#include <stdio.h>
#include <stdlib.h>
#include <vga.h>
#include <ncurses.h>
#include <sys/stat.h>
#include <linux/fcntl.h>

#include "standard.h"
#include "gbm.h"
#include "gbmerr.h"

#include "vga.h"

#define SUBPROG
#include "grav.h"

int ProcessFile(int Index)
{

  if ( gbm_guess_filetype(GRAVDIR[Index].DirEintrag, &GBM_Typ) != GBM_ERR_OK )
  {
      return(ERROR_TYP);
  }                                                                                                                                                                                                                                                                                                             

  if ( (GBM_File = open(GRAVDIR[Index].DirEintrag, O_RDONLY)) == -1 )
  {
      return(ERROR_OPEN);
   }

   gbm_query_filetype(GBM_Typ, &gbmft); 

   if ( (GBM_RC = gbm_read_header(GRAVDIR[Index].DirEintrag, GBM_File, GBM_Typ, &gbm, "\0")) != GBM_ERR_OK )
   {
      close(GBM_File);
      return(ERROR_HEADER);
   }         

   return(NO_ERROR);
}

int ViewFile(Index)
{   
   int PixelX, PixelY;
   int Pixel;
   int local;
   int RETURN;
   int KeyPressed;
   int BitmapWidth;
   int ScreenWidth;
   int SkippedLines;
  
   long Offset;
   long MaxOffset;
   long ImageSize;
   long ModeSize;
   long cRGB;

   char *SavedPointer;
   
   if ( (GBM_RC = gbm_read_palette(GBM_File, GBM_Typ, &gbm, gbmrgb)) != GBM_ERR_OK )
   {
       close(GBM_File);
       return(ERROR_PALETTE);
   }       

   if ( (ScreenLine = malloc((int) gbm.w)) == NULL)
   {
      close (GBM_File);
      return(ERROR_ALLOC);
   }
   
   BitmapSize = gbm.h * (((gbm.w * gbm.bpp + 31) / 32) * 4);

   if ( (Bitmap = malloc((int) BitmapSize)) == NULL )
   {
      close(GBM_File);
      free(ScreenLine);
      return(ERROR_ALLOC);
   }   

   attron(A_BOLD);
   attron(COLOR_PAIR(3));
   DrawBox(5,24,18,54,3);
   attron(A_BOLD);
   attron(COLOR_PAIR(3));
   mvaddstr(19,57,"Reading Data...");
   attroff(A_BOLD);
   attroff(COLOR_PAIR(3));
   refresh();

   if ( (GBM_RC = gbm_read_data(GBM_File, GBM_Typ, &gbm, Bitmap)) != GBM_ERR_OK )
   {
      free(Bitmap);
      free(ScreenLine);
      close(GBM_File);
      return(ERROR_READ);
   }   

   close(GBM_File);

   ExitNCurses();                                   /* NCurses ausschalten */

   vga_setmode(GMODE[ModeRC].ModeIndex);               /* Videomode setzen */
   vga_setdisplaystart(0);             /* Start = erstes Byte im Video RAM */
   vga_setmodeX();                     /* X-Mode (wirkt nur bei 256 Farben */
   vga_clear();                                     /* Bildschirm loeschen */
   vga_screenoff();                              /* Bildschirm ausschalten */

   cRGB = ( (1 << gbm.bpp) & 0x1ff );                 /* Anzahl der Farben */
   
   switch (gbm.bpp)               /* Breite des Bitmaps in Bytes berechnen */
   {                              /* Muss jeweils durch 4 teilbar sein! */
      case 8: BitmapWidth=((gbm.w+3)/4)*4;      
              break;

      case 4: BitmapWidth=(((gbm.w/2)+3)/4)*4;      
              break;

      case 1: BitmapWidth=(((gbm.w/8)+3)/4)*4;      
              break;              
   }

   if (GMODE[ModeRC].Width < gbm.w)    /* Setzen Laenge je Bildschirmzeile */
      ScreenWidth=GMODE[ModeRC].Width;
    else
      ScreenWidth=gbm.w;

   SavedPointer=ScreenLine;                              /* Pointer merken */
   Bitmap=Bitmap-BitmapWidth;      /* Vor der Schleife eine Zeile abziehen */

   for(local=gbm.h;local>0;local--)
   {  
      Bitmap=Bitmap+BitmapWidth;        /* Ich liebe Pointerarithmetik ;-) */   

      if (local<=GMODE[ModeRC].Heigh)
      {
         MakeLine();                                 /* Aufbauen der Linie */
         vga_drawscansegment(ScreenLine,0,local,ScreenWidth);/* Jede Linie */
      }
   }

   for ( local=0;local<cRGB;local++ )           /* 256-Farb Palette setzen */
   {
      gbmrgb[local].r=gbmrgb[local].r/4; 
      gbmrgb[local].g=gbmrgb[local].g/4;
      gbmrgb[local].b=gbmrgb[local].b/4;
      
      vga_setpalette(local,gbmrgb [local].r,gbmrgb [local].g,gbmrgb [local].b);
   }   
       
   vga_screenon();                                /* Bildschirm einschalten */

   RETURN=FALSE;
   
   ModeSize  = GMODE[Index].Width * GMODE[Index].Heigh;
   ImageSize = gbm.w * gbm.h;
   
   if(ImageSize>ModeSize)
      MaxOffset=ImageSize-ModeSize;
   else
      MaxOffset=0;   
   
   do
   {
      KeyPressed=getch();                                   /* Taste lesen */
   
      switch (KeyPressed)
      {
         case KEY_ENTER:  RETURN=TRUE;      
                          break;
      }
   }
   while(RETURN==FALSE);

   ScreenLine=SavedPointer;
   vga_setmode(TEXT);                                /* Textmode aktivieren */
   free (Bitmap);                                     /* Speicher freigeben */
   free (ScreenLine);
   VT100_CLS();                                 /* VT100-Screencodes senden */
   return(NO_ERROR);                                  /* Und wieder zurueck */
}

int CheckMode(void)
{
   vga_setchipset(CardRC);                           /* Grafikkarte setzen */

   if (!vga_hasmode(GMODE[ModeRC].ModeIndex))              /* kein Support */
      return (ERROR_SUPPORT);
   else
      return (NO_ERROR);
}

void MakeLine(void)
{
   int local;
   int IND;
   
   unsigned char Pixel;
   unsigned char Pixel1;
   unsigned char Pixel2;
   unsigned char Pixel3;
   unsigned char Pixel4;
   unsigned char Pixel5;
   unsigned char Pixel6;
   unsigned char Pixel7;
   unsigned char Pixel8;
   
   IND=0;

   switch (gbm.bpp)
   {
      case 8:   ScreenLine=Bitmap;                           /* 256 Farben */
                break;
      
      case 4:   for (local=0;local<gbm.w/2;local++)           /* 16 Farben */
                {  
                   Pixel=Bitmap[local];
                   
                   Pixel1=Pixel<<4;
                   Pixel1=Pixel1>>4;
                   
                   Pixel2=Pixel>>4;
                   
                   ScreenLine[IND]=Pixel2; IND++;
                   ScreenLine[IND]=Pixel1; IND++;
                }
                break;
      
      case 1:   for(local=0;local<(gbm.w+7)/8;local++)         /* 2 Farben */
                {
                   Pixel=Bitmap[local];
                   
                   Pixel1=Pixel&128;   Pixel2=Pixel&64;
                   Pixel3=Pixel&32;    Pixel4=Pixel&16;
                   Pixel5=Pixel&8;     Pixel6=Pixel&4;
                   Pixel7=Pixel&2;     Pixel8=Pixel&1;
                   
                   if (Pixel1!=0)
                      ScreenLine[IND]=0x01;
                   else
                      ScreenLine[IND]=0x00;
                   
                   IND++;
                   
                   if (Pixel2!=0)
                      ScreenLine[IND]=0x01;
                   else
                      ScreenLine[IND]=0x00;
                   
                   IND++;
                
                   if (Pixel3!=0)
                      ScreenLine[IND]=0x01;
                   else
                      ScreenLine[IND]=0x00;
                   
                   IND++;
                   
                   if (Pixel4!=0)
                      ScreenLine[IND]=0x01;
                   else
                      ScreenLine[IND]=0x00;
                   
                   IND++;
                   
                   if (Pixel5!=0)
                      ScreenLine[IND]=0x01;
                   else
                      ScreenLine[IND]=0x00;
                   
                   IND++;
                   
                   if (Pixel6!=0)
                      ScreenLine[IND]=0x01;
                   else
                      ScreenLine[IND]=0x00;
                   
                   IND++;
                
                   if (Pixel7!=0)
                      ScreenLine[IND]=0x01;
                   else
                      ScreenLine[IND]=0x00;
                   
                   IND++;
                   
                   if (Pixel8!=0)
                      ScreenLine[IND]=0x01;
                   else
                      ScreenLine[IND]=0x00;
                }
                break;
   }   
}                  