/* BnuView v1.0
 * Written by Prez@lfx.org
 * 
 * Amiga Port and modifications by drHirudo@Amigascne.org
 * 
 * For more information, see README
 *
 */

#include <intuition/intuition.h>
#include <fcntl.h>
#include <sys/types.h>
#include <stdio.h>
#include <libraries/dos.h>
#include "font_amiga.h"

#define w 16
#define h 16

#define BPP1    1
#define GB      2
#define NES     3

struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;

struct Screen *my_screen;
 
struct TextAttr my_font=
{
  "topaz.font",                 /* Topaz font. */
  8,                            /*                 */
    0,
 FPF_ROMFONT                   /* Exist in ROM. */
};

struct NewScreen my_new_screen=
{
  0,            /* LeftEdge  Should always be 0. */
  0,            /* TopEdge   Top of the display.*/
  320,          /* Width     We are using a low-resolution screen. */
  256,          /* Height    Non-Interlaced PAL (European) display. */
  3,            /* Depth     8 colours. */
  0,            /* DetailPen Text should be drawn with colour reg. 0 */
  1,            /* BlockPen  Blocks should be drawn with colour reg. 1 */
  0,         /* ViewModes No special modes. (Low-res, Non-Interlaced) */
  CUSTOMSCREEN, /* Type      Your own customized screen. */
  0,         /* Font      Default font. */
  "BnuView v1.0",/* Title The screen' title. */
  0,         /* Gadget    Must for the moment be NULL. */
  0          /* BitMap    No special CustomBitMap. */
};

struct NewWindow my_new_window=
{
  0,            /* LeftEdge    x position of the window. */
  12,            /* TopEdge    y position of the window. */
  320,           /* Width      320 pixels wide. */
  244,           /* Height     244 lines high. */
  0,             /* DetailPen  Text should be drawn with colour reg. 0 */
  1,             /* BlockPen   Blocks should be drawn with colour reg. 1 */
  MENUPICK|RAWKEY, /* IDCMPFlags. */
  SMART_REFRESH|BACKDROP|BORDERLESS|ACTIVATE, /* Flags       Intuition should refresh the window. */ 
  0,          /* FirstGadget No Custom Gadgets. */
  0,          /* CheckMark   Use Intuition's default CheckMark (v). */
  0,          /* Title       Title of the window. */
  0,          /* Screen      Connected to the Workbench Screen. */
  0,          /* BitMap      No Custom BitMap. */
  0,0,0,0,
  CUSTOMSCREEN   /* Type        Connected to custom Screen. */
};
 
struct IntuiText my_first_text=
{
  2,          /* FrontPen, black. */
  0,          /* BackPen, not used since JAM1. */
  JAM1,       /* DrawMode, do not change the background. */
  0,          /* LeftEdge, CHECKWIDTH amount of pixels out. */
              /* This will leave enough space for the check mark. */
  1,          /* TopEdge, 1 line down. */
  NULL,       /* TextAttr, default font. */
  "Quit",     /* IText, the string. */
  NULL        /* NextItem, no link to other IntuiText structures. */
};

struct MenuItem my_first_item=
{
  NULL,            /* NextItem. */
  0,               /* LeftEdge, 0 pixels out. */
  20,              /* TopEdge, 10 lines down. */
  150,             /* Width, 150 pixels wide. */
  10,              /* Height, 10 lines high. */
  ITEMTEXT|        /* Flags, render this item with text. */
  ITEMENABLED|     /*        this item will be enabled. */
  COMMSEQ|         /*        accessible from the keyboard. */
  HIGHCOMP,        /*        complement the colours when highlihted. */
  0x00000000,      /* MutualExclude, mutualexclude the first item only. */
  (APTR) &my_first_text, /* ItemFill, pointer to the text. */
  NULL,            /* SelectFill, nothing since we complement the col. */
  'Q',               /* Command, no command-key sequence. */
  NULL,            /* SubItem, no subitem list. */
  MENUNULL,        /* NextSelect, no items selected. */
};


struct Menu my_menu=
{
  NULL,          /* NextMenu, no more menu structures. */
  0,             /* LeftEdge, left corner. */
  0,             /* TopEdge, for the moment ignored by Intuition. */
  65,            /* Width, 50 pixels wide. */
  0,             /* Height, for the moment ignored by Intuition. */
  MENUENABLED,   /* Flags, this menu will be enabled. */
  "BnuView",     /* MenuName, the string. */
  &my_first_item /* FirstItem, pointer to the first item in the list. */
};

int fp;
int p1 = 0xF, p2 = 0xA, p3 = 0x5, p4 = 0x00;

int bpp1_tile(int loc, int x, int y) {
    int r,c;
    char data[8];

    if (!fp) return(-1);

    Seek(fp, loc, SEEK_SET);
    Read(fp, data, 8);


    for ( r = 0 ; r < 8 ; r++ ) {
        for ( c = 0 ; c < 8 ; c++ ) {
            if ( data[r] & 1<<c ) SetAPen(my_window->RPort,2);
            else SetAPen(my_window->RPort,5);
            WritePixel(my_window->RPort,x+(7-c),y+r);
        }
    }

    return(0);
}

int gb_tile(int loc, int x, int y) {
    int r,c;
    char data[16];

    if (!fp) return(-1);

    Seek(fp, loc, SEEK_SET);
    Read(fp, data, 16);

    for ( r = 0 ; r < 16 ; r+=2 ) {
        for ( c = 0 ; c < 8 ; c++ ) {
            if ( data[r] & 1<<c && data[r+1] & 1<<c ) SetAPen(my_window->RPort,2);
            else if ( data[r] & 1<<c && ! (data[r+1] & 1<<c) ) SetAPen(my_window->RPort,3);
            else if ( ! (data[r] & 1<<c) && data[r+1] & 1<<c ) SetAPen(my_window->RPort,4);
            else SetAPen(my_window->RPort,5);

            WritePixel(my_window->RPort,x+(7-c),y+(r/2));
        }
    }

    return(0);
}

int nes_tile(int loc, int x, int y) {
    int r,c;
    char data[16];

    if (!fp) return(-1);

    Seek(fp, loc, SEEK_SET);
    Read(fp, data, 16);

    for ( r = 0 ; r < 8 ; r++ ) {
        for ( c = 0 ; c < 8 ; c++ ) {
            if ( data[r] & 1<<c && data[r+8] & 1<<c ) SetAPen(my_window->RPort,2);
            else if ( data[r] & 1<<c && ! (data[r+8] & 1<<c) ) SetAPen(my_window->RPort,3);
            else if ( ! (data[r] & 1<<c) && data[r+8] & 1<<c ) SetAPen(my_window->RPort,4);
            else SetAPen(my_window->RPort,5);

            WritePixel(my_window->RPort,x+(7-c),y+r);
        }
    }

    return(0);
}

void draw_file(int loc, int mode, int bpp) {
    int r,c;

    for ( r = 0 ; r < h ; r++ ) {
        for ( c = 0 ; c < w ; c++ ) {
          if ( mode == BPP1 ) bpp1_tile(loc+((c+(r*w))*(8*bpp)), c*8, r*8);
          else if ( mode == GB ) gb_tile(loc+((c+(r*w))*(8*bpp)), c*8, r*8);
          else if ( mode == NES ) nes_tile(loc+((c+(r*w))*(8*bpp)), c*8, r*8);
        }
    }

}

int swap_pal() {
    int temp;

    temp = p1;
    p1 = p4;
    p4 = temp;

    temp = p2;
    p2 = p3;
    p3 = temp;

    SetRGB4( &my_screen->ViewPort,2,p1,p1,p1);
    SetRGB4( &my_screen->ViewPort,3,p2,p2,p2);
    SetRGB4( &my_screen->ViewPort,4,p3,p3,p3);
    SetRGB4( &my_screen->ViewPort,5,p4,p4,p4);

    return(0);
}

int draw_box(int x, int y, int W, int H) {
    int r,c;

    for ( r = 0 ; r < H ; r++ ) {
        for ( c = 0 ; c < W ; c++ ) {
            SetAPen(my_window->RPort,0);
            WritePixel(my_window->RPort,x+c,y+r);
        }
    }

    return(0);
}

int main(int argc, char ** argv) {


  ULONG class;      /* IDCMP flag. */

  /* Pointer to an IntuiMessage structure: */
  struct IntuiMessage *my_message;


    int loc = 0;
    int input=0,close=0;
    int mode = BPP1;
    int bpp = 1;
    int eof;
    char addr[20];
    char eofaddr[16];

    if ( argc < 2 ) exit(printf("Usage: %s <file>\n", argv[0]));

    fp = Open(argv[1], MODE_OLDFILE);
    if ( !fp ) exit(printf("Error loading file..\n"));
    eof = Seek(fp, 0, OFFSET_END);
    eof = Seek(fp, 0, OFFSET_END);

/* Open the Intuition library: */
  IntuitionBase = (struct IntuitionBase *)
    OpenLibrary( "intuition.library", 0 );
  if( !IntuitionBase )
    exit();
/* Open the Graphics library: */
  GfxBase = (struct GfxBase *)
    OpenLibrary( "graphics.library", 0 );
  if( !GfxBase )
  {
  CloseLibrary( IntuitionBase );
  exit();    
  }
/* We will now try to open the screen: */

 my_screen = (struct Screen *) OpenScreen( &my_new_screen );
  if( !my_screen )
  {
   CloseLibrary( GfxBase );
   CloseLibrary( IntuitionBase );
   exit();
   }

    SetRGB4( &my_screen->ViewPort,0,0,0,0);
    SetRGB4( &my_screen->ViewPort,1,0,15,8);
    SetRGB4( &my_screen->ViewPort,2,p1,p1,p1);
    SetRGB4( &my_screen->ViewPort,3,p2,p2,p2);
    SetRGB4( &my_screen->ViewPort,4,p3,p3,p3);
    SetRGB4( &my_screen->ViewPort,5,p4,p4,p4);

 my_new_window.Screen = my_screen;
 my_window = (struct Window *) OpenWindow( &my_new_window );

if ( !my_window )
  {
    /* Could NOT open the Window! */
    
    /* Close the Intuition Library since we have opened it: */
   CloseScreen( my_screen );
   CloseLibrary( GfxBase );   
   CloseLibrary( IntuitionBase );
   exit();  
  }

   SetMenuStrip( my_window, &my_menu );

    SetAPen(my_window->RPort,1);
    draw_string("BnuView v1.0 Written by Prez@lfx.org",0,240-36);
    draw_string("Amiga Port by drHirudo@Amigascne.org",0,240-16);

    SetAPen(my_window->RPort,1);

    draw_string("Controls:\nw  Line up\nz  Line down\ns  Byte up\na  Byte down\ne  Page up\nx  Page down", (8*17), 0);

    draw_string("1  BPP1\n2  Gameboy\n3  NES\n\nr  Swap palette\nq  Quit", (8*30), 16);

    sprintf(eofaddr,"End: 0x%08X", eof);
    draw_string(eofaddr,0,(8*16)+16);

    while (!close) {
        draw_file(loc, mode, bpp);
        sprintf(addr,"Offset: 0x%08X", loc);
        draw_box(0,(8*16),(5*18),16);
        SetAPen(my_window->RPort,1);
        draw_string(addr,0,(8*16));


    /* Wait until we have recieved a message: */
    Wait( 1 << my_window->UserPort->mp_SigBit );


    /* As long as we can collect messages successfully we stay in the */
    /* while-loop: */
    while(my_message = (struct IntuiMessage *) GetMsg(my_window->UserPort))
    {
      /* After we have successfully collected the message we can read */
      /* it, and save any important values which we maybe want to check */
      /* later: */
      class = my_message->Class;         /* IDCMP flag. */
      input = my_message->Code;           /* Code. */

      /* After we have read it we reply as fast as possible: */
      /* REMEMBER! Do never try to read a message after you have replied! */
      /* (Some other process has maybe changed it.) */
      ReplyMsg( my_message );


  if( class == MENUPICK && input == 63488)
       { close=TRUE; break;}
        if ( input == 17 ) loc-=((bpp*8)*w);
        else if ( input == 49 ) loc+=((bpp*8)*w);
        else if ( input == 32 ) loc--;
        else if ( input == 33 ) loc++;
        else if ( input == 18 ) loc-=((bpp*8)*w)*h;
        else if ( input == 50 ) loc+=((bpp*8)*w)*h;

        else if ( input == 1 ) mode = BPP1, bpp = 1;
        else if ( input == 2 ) mode = GB, bpp = 2;
        else if ( input == 3 ) mode = NES, bpp = 2;

        else if ( input == 19 ) swap_pal();
        else if ( input == 16 ) close=TRUE;} 
    if ( loc > eof - ((bpp*8)*16*16) ) loc = eof - ((bpp*8)*16*16);
    if ( loc < 0 ) loc = 0;
}

 Close(fp);
 
 ClearMenuStrip( my_window );

 CloseWindow ( my_window ); 

 CloseScreen( my_screen );
  
  /* Close the Graphics Library since we have opened it: */
  CloseLibrary( GfxBase );

  /* Close the Intuition Library since we have opened it: */
  CloseLibrary( IntuitionBase );

  /* THE END */
  exit();

    /*we should never get here.. but incase we do..*/
    return(0);
}        
