#include <stdint.h>
#include <stdio.h>
#include <curses.h>
#include "cpu.h"

#define WCOLS 80
#define WLINES 25

#ifndef FBIN_PATH
#error FBIN_PATH needed
#endif
#ifndef BLKFS_PATH
#error BLKFS_PATH needed
#endif

extern uint8_t byteregtable[8];
extern union _bytewordregs_ regs;
extern INTHOOK INTHOOKS[0x100];

static FILE *fp;
static FILE *blkfp;
static int retcode = 0;
WINDOW *bw, *dw, *w;

/* we have a fake INT API:
INT 1: EMIT. AL = char to spit
INT 2: KEY. AL = char read
INT 3: AT-XY. AL = x, BL = y
INT 4: BLKREAD. AX = blkid, BX = dest addr
INT 5: BLKWRITE. AX = blkid, BX = src addr
INT 6: RETCODE. AX = retcode.
*/

void int1() {
   uint8_t val = regs.byteregs[regal];
   if (fp != NULL) {
       putchar(val);
   } else {
       if (val >= 0x20 || val == '\n') {
           wechochar(w, val);
       } else if (val == 0x08) {
           int y, x; getyx(w, y, x);
           wmove(w, y, x-1);
       }
   }
}

void int2() {
   int c;
   if (fp != NULL) {
       c = getc(fp);
   } else {
       // debug_panel();
       c = wgetch(w);
   }
   if (c == EOF) {
       c = 4; // ASCII EOT
   }
   regs.byteregs[regal] = c;
}

void int3() {
   wmove(w, regs.byteregs[regbl], regs.byteregs[regal]);
}

void int4() {
   uint16_t blkid = getreg16(regax);
   uint16_t dest = getreg16(regbx);
   fseek(blkfp, blkid*1024, SEEK_SET);
   for (int i=0; i<1024; i++) {
       write86(dest+i, getc(blkfp));
   }
}

void int5() {
   uint16_t blkid = getreg16(regax);
   uint16_t dest = getreg16(regbx);
   fseek(blkfp, blkid*1024, SEEK_SET);
   for (int i=0; i<1024; i++) {
       putc(read86(dest+i), blkfp);
   }
}

void int6() {
   retcode = getreg16(regax);
}

int main(int argc, char *argv[])
{
   INTHOOKS[1] = int1;
   INTHOOKS[2] = int2;
   INTHOOKS[3] = int3;
   INTHOOKS[4] = int4;
   INTHOOKS[5] = int5;
   INTHOOKS[6] = int6;
   reset86(0);
   fprintf(stderr, "Using blkfs %s\n", BLKFS_PATH);
   blkfp = fopen(BLKFS_PATH, "r+");
   if (!blkfp) {
       fprintf(stderr, "Can't open\n");
       return 1;
   }
   fseek(blkfp, 0, SEEK_END);
   if (ftell(blkfp) < 100 * 1024) {
       fclose(blkfp);
       fprintf(stderr, "emul/blkfs too small, something's wrong, aborting.\n");
       return 1;
   }
   fseek(blkfp, 0, SEEK_SET);
   // initialize memory
   FILE *bfp = fopen(FBIN_PATH, "r");
   if (!bfp) {
       fprintf(stderr, "Can't open forth.bin\n");
       return 1;
   }
   int i = 0;
   int c = getc(bfp);
   while (c != EOF) {
       write86(i++, c);
       c = getc(bfp);
   }
   fclose(bfp);
   w = NULL;
   if (argc == 2) {
       fp = fopen(argv[1], "r");
       if (fp == NULL) {
           fprintf(stderr, "Can't open %s\n", argv[1]);
           return 1;
       }
       while (exec86(100));
       fclose(fp);
   } else if (argc == 1) {
       initscr(); cbreak(); noecho(); nl(); clear();
       // border window
       bw = newwin(WLINES+2, WCOLS+2, 0, 0);
       wborder(bw, 0, 0, 0, 0, 0, 0, 0, 0);
       wrefresh(bw);
       // debug panel
       dw = newwin(1, 30, LINES-1, COLS-30);
       w = newwin(WLINES, WCOLS, 1, 1);
       scrollok(w, 1);
       while (exec86(100)) {
           //debug_panel();
       }
       nocbreak(); echo(); delwin(w); delwin(bw); delwin(dw); endwin();
       printf("\nDone!\n");
       //emul_printdebug();
   }

   return retcode;
}