#include <stdio.h>
#include <exec/types.h>
#include <intuition/intuition.h>
#include <graphics/display.h>
#include <iff/iff.h>
#include <libraries/dos.h>

#define INT_REV 29L
#define GR_REV 29L

struct IntuitionBase *IntuitionBase, *OpenLibrary();
struct GfxBase *GfxBase;
struct Screen *s, *OpenScreen();
struct IntuiMessage *GetMsg();

#define SCREEN_WIDTH 320L
#define SCREEN_HEIGHT 400L
#define BUFFER_SIZE 8096

struct NewScreen MyScreen =
  {
  0, 0,
  SCREEN_WIDTH, SCREEN_HEIGHT,
  6,
  0, 1,
  INTERLACE | HAM,
  0,
  NULL,
  (UBYTE *) "Show screen",
  NULL,
  NULL
  };

UWORD ColourTbl[16] = { 0x000, 0x111, 0x222, 0x333, 0x444, 0x555, 0x666,
                       0x777, 0x888, 0x999, 0xaaa, 0xbbb, 0xccc, 0xddd,
                       0xeee, 0xfff };

LONG last_y = -1;

extern int Close_Threshold;

FILE *fp, *palette_file;

main (argc, argv) 
 int argc;
 char **argv;
 {
 unsigned int red, green, blue, i;
 struct IntuiMessage *message;
 unsigned int width, height, x, y, line_number;
 unsigned char red_buffer[SCREEN_WIDTH], green_buffer[SCREEN_WIDTH],
      blue_buffer[SCREEN_WIDTH];

 if ((argc < 2) || (argc > 4))
   {
   printf ("\nUsage:  DumpToIFF <dump_filename> <iff_file_name> [<palette_filename>]\n");
   exit(0);
   }

 Close_Threshold = 5;

 fp = NULL;

 IntuitionBase = (struct IntuitionBase *)
                  OpenLibrary ("intuition.library",INT_REV);
 if (IntuitionBase == NULL)
   exit(FALSE);

 GfxBase = (struct GfxBase *)
                      OpenLibrary ("graphics.library", GR_REV);
 if (GfxBase == NULL)
   exit(FALSE);

 if ((s = (struct Screen *) OpenScreen (&MyScreen))
          == NULL)
  exit (FALSE);

 ShowTitle (s, FALSE);


 LoadRGB4 (&(s->ViewPort), ColourTbl, 16L);
 SetAPen (&(s->RastPort), 7L);
 RectFill (&(s -> RastPort), 0L, 0L, SCREEN_WIDTH-1, SCREEN_HEIGHT-1);

 if ((fp = fopen (argv[1], "r")) == NULL)
   {
   display_close();
   exit(FALSE);
   }

 width = (unsigned int) (getc(fp) & 0xFF);
 width += ((unsigned int) (getc(fp) & 0xFF) * 256);
 height = (unsigned int) (getc(fp) & 0xFF);
 height += ((unsigned int) (getc(fp) & 0xFF) * 256);

 if ((width > 320) || (height > 400)) {
    display_close();
    printf ("\nError - picture too large\n");
    exit (0);
    }

 printf ("Processing...\n");

 if (argc == 4) {
    if ((palette_file = fopen (argv[3], "r")) == NULL) {
      display_close();
      exit(FALSE);
      }

   for (i = 0 ; i < 16 ; i++) {
     if (fscanf (palette_file, "%d %d %d", &red, &green, &blue) != 3) {
        printf ("Error reading palette file\n");
        exit (1);
        }
     ColourTbl[i] = ((red & 0x0f) << 4) |
                    ((green & 0x0f) << 4) | (blue & 0x0f);
     }
   }    
 else {
    start_recording_colours();

    for (y = 0 ; y < height ; y++) {
      /* Skip over the line number.  It's not important at this point */
      getc(fp);
      getc(fp);

      for (x = 0 ; x < width ; x++)
        red_buffer[x] = getc(fp);

      for (x = 0 ; x < width ; x++)
        green_buffer[x] = getc(fp);

      for (x = 0 ; x < width ; x++)
        blue_buffer[x] = getc(fp);

      for (x = 0 ; x < width ; x++)
        {
        red = red_buffer[x];
        green = green_buffer[x];
        blue = blue_buffer[x];
        process (x, height - y, red, green, blue);
        }
      }
    choose_palette();
    }

 printf ("Displaying...\n");

 LoadRGB4 (&(s->ViewPort), ColourTbl, 16L);
 fclose (fp);

 if ((fp = fopen (argv[1], "r")) == NULL)
   {
   display_close();
   exit(FALSE);
   }

 getc (fp);
 getc (fp);
 getc (fp);
 getc (fp);

 for (y = 0 ; y < height ; y++) {
   line_number = (unsigned int) (getc(fp) & 0xFF);
   line_number += ((unsigned int) (getc(fp) & 0xFF) * 256);
   for (x = 0 ; x < width ; x++)
     red_buffer[x] = getc(fp);

   for (x = 0 ; x < width ; x++)
     green_buffer[x] = getc(fp);

   for (x = 0 ; x < width ; x++)
     blue_buffer[x] = getc(fp);

   for (x = 0 ; x < width ; x++)
     {
     red = red_buffer[x];
     green = green_buffer[x];
     blue = blue_buffer[x];
     display_plot (x, line_number, red, green, blue);
     }
   }

 if (argc >= 3)
   ConvertToIFF(argv[2]);

 printf ("Finished\n");
 display_close();
 }

display_close ()
 {
 if (fp != NULL)
   fclose (fp);
 CloseScreen (s);
 CloseLibrary (GfxBase) ;
 CloseLibrary (IntuitionBase) ;
}

display_plot (x, y, new_red, new_green, new_blue)
  LONG x, y, new_red, new_green, new_blue;
  {
  LONG colour, newline;

  new_red &= 0xFF;
  new_green &= 0xFF;
  new_blue &= 0xFF;

  new_red /= 16;
  new_green /= 16;
  new_blue /= 16;

  newline = 0;
  if (last_y != y) {
    newline = 1;
    last_y = y;
    reset_colours();
    SetAPen (&(s -> RastPort), 0);
    WritePixel (&(s -> RastPort), 0, y);
    }

  colour = best_colour (new_red, new_blue, new_green);
  SetAPen (&(s -> RastPort), colour);
  WritePixel (&(s -> RastPort), x+1, y);
  }


process (x, y, new_red, new_green, new_blue)
  LONG x, y, new_red, new_green, new_blue;
  {
  LONG newline;

  new_red &= 0xFF;
  new_green &= 0xFF;
  new_blue &= 0xFF;

  new_red /= 16;
  new_green /= 16;
  new_blue /= 16;

  newline = 0;
  if (last_y != y) {
    newline = 1;
    last_y = y;
    reset_colours();
    }

  record_colours (new_red, new_green, new_blue);
  }


ConvertToIFF(file_name)
   char *file_name;
   {
   char *buffer, *malloc();
   BPTR file, Open();
   BOOL PutPict();

   if ((file = Open (file_name, MODE_NEWFILE)) == 0) {
      printf ("\nCannot open IFF file\n");
      exit (0);
      }

   buffer = malloc(BUFFER_SIZE);
   if (PutPict (file, &(s->ViewPort), buffer, BUFFER_SIZE))
      printf ("\nIFF write error\n");
   Close (file);
   }
