#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <aes.h>
#include <vdi.h>
#include <tos.h>
#include <ext.h>

#define min(a, b)             ((a) < (b) ? (a) : (b))
#define max(a, b)             ((a) > (b) ? (a) : (b))
#define TRUE 1
#define FALSE 0

typedef struct tagBITMAPFILEHEADER
{
        unsigned int  bfType;                   /* "BM" or 0x4D42 */
        unsigned long bfSize;                   /* Size of file in bytes */
        unsigned int  bfReserved1;              /* Set to 0 */
        unsigned int  bfReserved2;              /* Set to 0 */
        unsigned long bfOffBits;                /* Offset in file where */
                                                /* the bits begin */
} BITMAPFILEHEADER;

typedef struct tagBITMAPINFOHEADER
{
        unsigned long biSize;                   /* Size of the structure */
        unsigned long biWidth;                  /* Width in pixels */
        unsigned long biHeight;                 /* Height in pixels  */
        unsigned int  biPlanes;                 /* # of color Planes: Set to 1 */
        unsigned int  biBitCount;               /* Color bits per pixel */
        unsigned long biCompression;            /* Compression Scheme */
        unsigned long biSizeImage;              /* Number of bitmap bytes */
        unsigned long biXPelsPerMeter;          /* Horizontal Resolution */
        unsigned long biYPelsPerMeter;          /* Vertical Resolution */
        unsigned long biClrUsed;                /* Number of colors used */
        unsigned long biClrImportant;           /* Important colors */

} BITMAPINFOHEADER;

BITMAPFILEHEADER BMPHeader;
BITMAPINFOHEADER BMPInfo;

FILE *fn;
int     Msgbuff[8];                 
int     W_handle, Wx, Wy, Ww, Wh;             
int     W_fulled;                                            
int     pxarray[128];               
int     Done = FALSE;              
int     work_in[12];
int     work_out[57];
int     extend_out[57];
int     handle, phys_handle;
int     gl_hchar,gl_wchar,gl_hbox,gl_wbox;
int     gl_apid;
int     xdesk, ydesk, wdesk, hdesk;
int     hidden;
int     xyarray[256];
unsigned int  color_correction[1024];
unsigned char colortable[1024][4];
unsigned char color[2048];
int     pallatte[1024];
int     rgbcolors[1024][3];
int     hw_index;
int     vdi_index;
int i;
int xy[4];
char path[128];
char fname[16];
char pathfname[144];
char c_temp[1024];
long file_length;

void close_vwork( void );
int open_vwork( void );
int fixint(int data);
long fixlong(long data);
int setcolors(FILE *fn);
void put8bits(void);
void put4bits(void);
void put2bits(void);
void put1bits(void);
void fake_calc(void);
void show_mouse(void);
void hide_mouse(void);
extern int (*byte2raw)(char *col, char *screen);
extern int (*p_pixel)(int x, int y, int color);
extern int pinit(int max_x, int max_y, void *video_buffer, int planes);
extern void pexit(void);
extern set16_pixel8(int x, int y, char *color);

main(int argc, char *argv[])
{
   struct ffblk fblock;
   char *cptr;
   int flag = 0;
   
   FILE *Fn;
   while(Bconstat(2)) Bconin(2);
   
   if(argc < 2) 
   {
      puts("No filename given");
      Bconin(2);
      return;
   }

   if ( open_vwork( ) == TRUE )
   {
      pinit(work_out[0]+1, work_out[1]+1, (void *)Logbase(), extend_out[4]);
      for(i = 0; i < work_out[13]; i++) {
         vq_color(handle, i, 1, (int *)&rgbcolors[i]);
         xy[0] = 0;
         xy[1] = 0;
         vsm_color(handle, i); 
         v_pmarker(handle, 1, xy);
         v_get_pixel(handle, 0, 0, &hw_index, &vdi_index);
         color_correction[hw_index] = vdi_index;
      }
      show_mouse();
   }
   else
   {
      fprintf(stderr, "Unable to start Program!" );
      exit ( -1 );
   }
   
   sprintf(c_temp, "%s", argv[1]); /* copy the commandline string. */

   /* Now strip the path from the string. */
   i = strlen(c_temp);
   cptr = c_temp + i;
   
   while(i > 0) {
      if(*cptr == ':') {
         sprintf(fname, "%s", cptr+1);
         *(cptr+1) = 0;
         sprintf(path, "%s\\", c_temp);
         break;
      }
      if(*cptr == '\\') {
         sprintf(fname, "%s", cptr+1);
         *(cptr+1) = 0;
         sprintf(path, "%s", c_temp);         
         break;
      }
      
      i--;
      cptr--;
   }      
   
   if(i <= 0) {
      path[0] = 0;
      sprintf(fname, "%s", c_temp);
   }
   
   if(strlen(fname) <= 0) {
      sprintf(fname,"*.BMP");
   }
   
   sprintf(pathfname, "%s%s", path, fname);
   
   flag = findfirst(pathfname, &fblock, 0);
   
   while(flag == 0) {
   
      sprintf(pathfname, "%s%s", path, fblock.ff_name);
      sprintf(fname,"%s",fblock.ff_name);
      file_length = fblock.ff_fsize;
      
      Bconout(2, 27);
      Bconout(2, 'E');
      puts(fname);
      
      Fn = fopen(pathfname,"rb");               /* Open up BMP image file  */   
        
      if(Fn == (FILE *)0) {
         printf("File %s not found\n", argv[1]);
         Bconin(2);
         close_vwork( );
         exit(0);
      }                                                   
                                                /* Read in BMP header */
      fread(&BMPHeader, sizeof(BMPHeader), 1, Fn);
      fread(&BMPInfo, sizeof(BMPInfo), 1, Fn);
      fclose(Fn);
      
      if(BMPHeader.bfType != 0x424d) {
         printf("File %s Not a Windows .BMP file\n", argv[1]);
         Bconin(2);
         close_vwork( );
         exit(0);
      }
   
      /* Convert INTEL to MOTOROLA format. */

      BMPHeader.bfSize        = fixlong(BMPHeader.bfSize);        /* Size of file in bytes */
      BMPHeader.bfOffBits     = fixlong(BMPHeader.bfOffBits);     /* Offset in file where */
      BMPInfo.biSize          = fixlong(BMPInfo.biSize);          /* Size of the structure */
      BMPInfo.biWidth         = fixlong(BMPInfo.biWidth);         /* Width in pixels */
      BMPInfo.biHeight        = fixlong(BMPInfo.biHeight);        /* Height in pixels  */
      BMPInfo.biPlanes        = fixint(BMPInfo.biPlanes);         /* # of color Planes: Set to 1 */
      BMPInfo.biBitCount      = fixint(BMPInfo.biBitCount);       /* Color bits per pixel */
      BMPInfo.biCompression   = fixlong(BMPInfo.biCompression);   /* Compression Scheme */
      BMPInfo.biSizeImage     = fixlong(BMPInfo.biSizeImage);     /* Number of bitmap bytes */
      BMPInfo.biXPelsPerMeter = fixlong(BMPInfo.biXPelsPerMeter); /* Horizontal Resolution */
      BMPInfo.biYPelsPerMeter = fixlong(BMPInfo.biYPelsPerMeter); /* Vertical Resolution */
      BMPInfo.biClrUsed       = fixlong(BMPInfo.biClrUsed);       /* Number of colors used */
      BMPInfo.biClrImportant  = fixlong(BMPInfo.biClrImportant);  /* Important colors */

      switch(BMPInfo.biBitCount) {
         case 1: put1bits(); break;
         case 2: put2bits(); break;
         case 4: put4bits(); break;
         case 8: put8bits(); break;                          
         default: printf("\rOnly 1/2/4 and 8 bit color currently supported\n");
       }
      flag = findnext(&fblock);
   }
   
   close_vwork( );
   exit ( 0 );
   return 0;
}

/***************************************************************/
/* */
/***************************************************************/
void put8bits(void) 
{
   FILE *Fn;
   register int x, maxx, y, pmaxx;
   int i;
   register char *screen;
   register char *Color;
   int kpress;
   extern long *_ytable;
   
   while(Bconstat(2)) Bconin(2);

   y = BMPInfo.biHeight;
   
   if(BMPInfo.biSizeImage == 0L)
      maxx = (int) ((unsigned long) (file_length - BMPHeader.bfOffBits) / (unsigned long)y);
   else
      maxx = (int) ((unsigned long) BMPInfo.biSizeImage / (unsigned long)y);

   for(i = 0; i < 2048; color[i++] = 0);
   
   Fn = fopen(pathfname, "rb");                  /* Open BMP file */
   setvbuf(Fn, (char *)0, _IOFBF, (size_t) file_length);
   
   if(extend_out[4] > 1)
      setcolors(Fn);

   fseek(Fn,BMPHeader.bfOffBits,SEEK_SET); /* BMP file */

   pmaxx = maxx;
   if(y > work_out[1] - 1) y = work_out[1] - 1;
   if(maxx > work_out[0]) pmaxx = work_out[0];

   Color = color;
   
   do {
      fread(&color, maxx, 1, Fn);
      screen = (char *) *(_ytable + y + 1);   
      for (x = 0; x < pmaxx;) {
         screen += (long)(*byte2raw)(Color+x, screen); x += 16;
         screen += (long)(*byte2raw)(Color+x, screen); x += 16;
         screen += (long)(*byte2raw)(Color+x, screen); x += 16;
         screen += (long)(*byte2raw)(Color+x, screen); x += 16;
         screen += (long)(*byte2raw)(Color+x, screen); x += 16;
         screen += (long)(*byte2raw)(Color+x, screen); x += 16;
         screen += (long)(*byte2raw)(Color+x, screen); x += 16;
         screen += (long)(*byte2raw)(Color+x, screen); x += 16;
      }
      if(Bconstat(2)) break;
   } while (y-- > 0);
   
   fclose(Fn);
   
   kpress = (int)Bconin(2) & 0xff;
   Bconout(2, 27);
   Bconout(2, 'E');
   
   if(kpress == 27) {
      fake_calc();
   }else
      return;
}

/***************************************************************/
/* */
/***************************************************************/
void put4bits(void) 
{
   FILE *Fn;
   register int x, maxx, y, pmaxx;
   register char *screen;
   register char *Color;
   int kpress;
   int i, j;
   extern long *_ytable;
   
   while(Bconstat(2)) Bconin(2);

   y = BMPInfo.biHeight;
   
   if(BMPInfo.biSizeImage == 0L)
      maxx = (int) ((unsigned long) (file_length - BMPHeader.bfOffBits) / (unsigned long)y);
   else
      maxx = (int) ((unsigned long) BMPInfo.biSizeImage / (unsigned long)y);

   maxx <<= 1; /* adjust for true width. */
   
   for(i = 0; i < 2048; color[i++] = 0);

   Fn = fopen(pathfname, "rb");                  /* Open BMP file */
   setvbuf(Fn, (char *)0, _IOFBF, (size_t) file_length);
   
   if(extend_out[4] > 1)
      setcolors(Fn);

   fseek(Fn,BMPHeader.bfOffBits,SEEK_SET); /* BMP file */

   pmaxx = maxx;
   if(y > work_out[1] - 1) y = work_out[1] - 1;
   if(maxx > work_out[0]) pmaxx = work_out[0];

   Color = c_temp;
   
   do {
      fread(&color, maxx >> 1, 1, Fn);
      
      j = 0;
      for(i = 0; i < (maxx >> 1); i++) {
         c_temp[j++] = (color[i] >> 4) & 0xf;
         c_temp[j++] =  color[i] & 0xf;
      }
      
      screen = (char *) *(_ytable + y + 1);   
      for (x = 0; x < pmaxx;) {
         screen += (long)(*byte2raw)(Color+x, screen); x += 16;
         screen += (long)(*byte2raw)(Color+x, screen); x += 16;
         screen += (long)(*byte2raw)(Color+x, screen); x += 16;
         screen += (long)(*byte2raw)(Color+x, screen); x += 16;
         screen += (long)(*byte2raw)(Color+x, screen); x += 16;
         screen += (long)(*byte2raw)(Color+x, screen); x += 16;
         screen += (long)(*byte2raw)(Color+x, screen); x += 16;
         screen += (long)(*byte2raw)(Color+x, screen); x += 16;
      }
      if(Bconstat(2)) break;
   } while (y-- > 0);
   
   fclose(Fn);
   
   kpress = (int)Bconin(2) & 0xff;
   Bconout(2, 27);
   Bconout(2, 'E');
   
   if(kpress == 27) {
      fake_calc();
   }else
      return;
}
/***************************************************************/
/* */
/***************************************************************/
void put2bits(void) 
{
   FILE *Fn;
   register int x, maxx, y, pmaxx;
   register char *screen;
   register char *Color;
   int kpress;
   int i, j;
   extern long *_ytable;
   
   while(Bconstat(2)) Bconin(2);

   y = BMPInfo.biHeight;
   
   if(BMPInfo.biSizeImage == 0L)
      maxx = (int) ((unsigned long) (file_length - BMPHeader.bfOffBits) / (unsigned long)y);
   else
      maxx = (int) ((unsigned long) BMPInfo.biSizeImage / (unsigned long)y);

   maxx <<= 2; /* adjust for true width. */

   for(i = 0; i < 2048; color[i++] = 0);

   Fn = fopen(pathfname, "rb");                  /* Open BMP file */
   setvbuf(Fn, (char *)0, _IOFBF, (size_t) file_length);
   
   if(extend_out[4] > 1)
      setcolors(Fn);

   fseek(Fn,BMPHeader.bfOffBits,SEEK_SET); /* BMP file */

   pmaxx = maxx;
   if(y > work_out[1] - 1) y = work_out[1] - 1;
   if(maxx > work_out[0]) pmaxx = work_out[0];

   Color = c_temp;
   do {
      fread(&color, maxx >> 2, 1, Fn);
      
      j = 0;
      for(i = 0; i < (maxx >> 2); i++) {
         c_temp[j++] = (color[i] >> 6) & 0x3;
         c_temp[j++] = (color[i] >> 4) & 0x3;
         c_temp[j++] = (color[i] >> 2) & 0x3;
         c_temp[j++] =  color[i] & 0x3;
      }
      
      screen = (char *) *(_ytable + y + 1);   
      for (x = 0; x < pmaxx;) {
         screen += (long)(*byte2raw)(Color+x, screen); x += 16;
         screen += (long)(*byte2raw)(Color+x, screen); x += 16;
         screen += (long)(*byte2raw)(Color+x, screen); x += 16;
         screen += (long)(*byte2raw)(Color+x, screen); x += 16;
         screen += (long)(*byte2raw)(Color+x, screen); x += 16;
         screen += (long)(*byte2raw)(Color+x, screen); x += 16;
         screen += (long)(*byte2raw)(Color+x, screen); x += 16;
         screen += (long)(*byte2raw)(Color+x, screen); x += 16;
      }
      if(Bconstat(2)) break;
   } while (y-- > 0);
   
   fclose(Fn);
   
   kpress = (int)Bconin(2) & 0xff;
   Bconout(2, 27);
   Bconout(2, 'E');
   
   if(kpress == 27) {
      fake_calc();
   }else
      return;
}

/***************************************************************/
/* */
/***************************************************************/
void put1bits(void) 
{
   FILE *Fn;
   register int x, maxx, y, pmaxx;
   register char *screen;
   register char *Color;
   int kpress;
   int i, j;
   extern long *_ytable;
   
   while(Bconstat(2)) Bconin(2);

   y = BMPInfo.biHeight;
   
   if(BMPInfo.biSizeImage == 0L)
      maxx = (int) ((unsigned long) (file_length - BMPHeader.bfOffBits) / (unsigned long)y);
   else
      maxx = (int) ((unsigned long) BMPInfo.biSizeImage / (unsigned long)y);

   maxx <<= 3; /* adjust for true width. */

   for(i = 0; i < 2048; color[i++] = 0);

   Fn = fopen(pathfname, "rb");                  /* Open BMP file */
   setvbuf(Fn, (char *)0, _IOFBF, (size_t) file_length);
      
   if(extend_out[4] > 1)
      setcolors(Fn);

   fseek(Fn,BMPHeader.bfOffBits,SEEK_SET); /* BMP file */
   pmaxx = maxx;
   if(y > work_out[1] - 1) y = work_out[1] - 1;
   if(maxx > work_out[0]) pmaxx = work_out[0];

   Color = c_temp;
   
   do {
      fread(&color, maxx >> 3, 1, Fn);
      
      j = 0;
      for(i = 0; i < (maxx >> 3); i++) {
         c_temp[j++] = (color[i] >> 7) & 0x1;
         c_temp[j++] = (color[i] >> 6) & 0x1;
         c_temp[j++] = (color[i] >> 5) & 0x1;
         c_temp[j++] = (color[i] >> 4) & 0x1;
         c_temp[j++] = (color[i] >> 3) & 0x1;
         c_temp[j++] = (color[i] >> 2) & 0x1;
         c_temp[j++] = (color[i] >> 1) & 0x1;
         c_temp[j++] =  color[i] & 0x1;
      }
      
      screen = (char *) *(_ytable + y + 1);   
      for (x = 0; x < pmaxx;) {
         screen += (long)(*byte2raw)(Color+x, screen); x += 16;
         screen += (long)(*byte2raw)(Color+x, screen); x += 16;
         screen += (long)(*byte2raw)(Color+x, screen); x += 16;
         screen += (long)(*byte2raw)(Color+x, screen); x += 16;
         screen += (long)(*byte2raw)(Color+x, screen); x += 16;
         screen += (long)(*byte2raw)(Color+x, screen); x += 16;
         screen += (long)(*byte2raw)(Color+x, screen); x += 16;
         screen += (long)(*byte2raw)(Color+x, screen); x += 16;
      }
      if(Bconstat(2)) break;
   } while (y-- > 0);
   
   fclose(Fn);
   
   kpress = (int)Bconin(2) & 0xff;
   Bconout(2, 27);
   Bconout(2, 'E');
   
   if(kpress == 27) {
      fake_calc();
   }else
      return;
}

/***************************************************************/
/* */
/***************************************************************/
int setcolors(FILE *fn)
{
   int offset;
   int count;
   int rgb[3];

   offset = sizeof(BMPInfo) + sizeof(BMPHeader);
   count = BMPHeader.bfOffBits - offset;
   fseek(fn,offset,SEEK_SET); /* BMP file */
   fread(colortable,count,1,fn);
   
   /* Convert to VDI levels. 1000/255 = 3.921568627 */
   for(count = 0; count < work_out[13]; count++) {
      rgb[2] = (int)((float)(colortable[count][0])) * 3.921568627;
      rgb[1] = (int)((float)(colortable[count][1])) * 3.921568627;
      rgb[0] = (int)((float)(colortable[count][2])) * 3.921568627;

      /* When setting the palette our putpixel routine is based */
      /* on the hardware color not VDI which is not always to   */
      /* same. So make the correction here.                     */
      vs_color(handle, color_correction[count], rgb);
   }
}

/***************************************************************/
/* */
/***************************************************************/

int open_vwork( void )
{
   register int i;

   if (( gl_apid = appl_init() ) != -1 )
   {
      for ( i = 1; i < 10; work_in[i++] = 1 );
      work_in[10] = 2;
      phys_handle = graf_handle( &gl_wchar, &gl_hchar, &gl_wbox, &gl_hbox );
      work_in[0]  = handle = phys_handle;

      v_opnvwk( work_in, &handle, work_out );
      vq_extnd(handle, 1, extend_out);
      
      return ( TRUE );
   }
   else
      return ( FALSE );
}
/***************************************************************/
/* */
/***************************************************************/
void hide_mouse(void)
{
   if(! hidden)
   {
      graf_mouse(M_OFF,0x0L);
      hidden=TRUE;
   }
}
/***************************************************************/
/* */
/***************************************************************/

void show_mouse(void)
{
   if(hidden)
   {
      graf_mouse(M_ON,0x0L);
      hidden=FALSE;
   }
}

/*************************************************************************/
/* Close Work Station.                                                   */
/*************************************************************************/

void close_vwork( void )
{
   int i;
   
   for(i = 0; i < work_out[13]; i++)
      vs_color(handle, i, (int *)&rgbcolors[i]);

   v_clsvwk( handle );
   pexit();
   appl_exit( );
}
/***************************************************************/
/* convert intel to motorola format                            */
/***************************************************************/
long fixlong(long data)
{
   char byte[4];
   char *bptr = (char *) &data;

   byte[0] = *(bptr+3);
   byte[1] = *(bptr+2);
   byte[2] = *(bptr+1);
   byte[3] = *(bptr);

   data = *((long *)byte);
   return(data);
}
/***************************************************************/
/* convert intel to motorola format                            */
/***************************************************************/
int fixint(int data)
{
   char byte[2];
   char *bptr = (char *)&data;

   byte[0] = *(bptr+1);
   byte[1] = *(bptr);

   data = *((int *)byte);
   return(data);
}

/****************************************************************/
/* Calc long axis of visual counter part.                       */
/****************************************************************/
void fake_calc(void) 
{
#ifdef DONT_WANT_WIFE_TO_SEE
   int i;
   int j;
   int number_of_loops;
   int spit_number;
   
   Bconout(2, 27);
   Bconout(2, 'E');
      
   for(i = 0; i < work_out[13]; i++)
      vs_color(handle, i, (int *)&rgbcolors[i]);
      
   while(Bconstat(2)) Bconin(2);
   
   j = 0;
   i = 0;
   spit_number = (int) (Random() & 0x3f) + 1;
   while(1) {
      if((i++ % spit_number) == 0) {
         printf("\r Return Value = %ld ", Random());
         j = 0;
         spit_number = (int) (Random() & 0x3f) + 1;
      }
         
      if((j++ % 78) == 0) 
         printf("\n");
      else
         printf("*");
         
      delay((int)(Random() & 0x1ff));
      
      if(Bconstat(2)) {
         number_of_loops = (int) Bconin(2) & 0xff;
         switch(number_of_loops) {
            case 'Q':
            case 'q': close_vwork();
                      exit(0);
            case 'R':
            case 'r':
                      return;
         }             
      }
   }
#else
   close_vwork();
   exit(0);
#endif
}   