/***********************************************************************
*
* console.c - IBM 7090 emulator console routines.
*
* Changes:
*   ??/??/??   PRP   Original.
*   01/20/05   DGP   Changes for correct channel operation.
*   01/28/05   DGP   Revamped channel and tape controls.
*   02/07/05   DGP   Added command file.
*   
***********************************************************************/

#define EXTERN extern

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <signal.h>

#include "sysdef.h"
#include "regs.h"
#include "trace.h"
#include "lights.h"
#include "io.h"
#include "chan.h"
#include "console.h"
#include "screen.h"
#include "binloader.h"

extern char prtview[100][82];
extern int prtviewlen;
extern int panelmode;
char errview[5][81];
long total_cycles = 0;

static char iline[256];
static char *ibp = 0;
static char *lastcmd = 0;

#define VIEW_CLEAR   -1
#define VIEW_NONE   0
#define VIEW_HELP   1
#define VIEW_MOUNT   2
#define VIEW_PRINT   3
#define VIEW_TRACE   4
#define VIEW_ERROR   5

int view = VIEW_CLEAR;
int newview = VIEW_HELP;

/*
 * IBM 709x console
 */

void
errorview()
{
   int32 i;

   if (panelmode)
   {
      screenposition (17,1);
      clearline();
   }
   printf("\n");
   for (i = 0; i < 5; i++)
   {
      if (panelmode)
	 clearline();
      printf("%s\n", errview[i]);
      errview[i][0] = '\0';
   }
   if (panelmode)
   {
      printf ("press enter to continue:");
      fgetc (stdin);
   }
}

#if defined(UNIX)
void
sigintr (int sig)
{
   automatic = 0;
   signal (SIGINT, sigintr);
}
#endif

void
check_intr()
{
#if defined(WIN32)
   if (kbhit())
   {
      automatic = 0;
   }
#endif
}


static int
docommand (void)
{
   int32 kp;
   uint16 c;
   int loadaddr;

   c = *ibp++;
   switch (c)
   {

   case 'h':
      newview = VIEW_HELP;
      return (1);

   case 'r':
      reset();
      return (1);

   case 'c':
      if (strncmp(ibp, "lear", 4) == 0)
      {
         ibp += 4;
         clear();
         return (1);
      }
      if (strncmp(ibp, "lose", 4) == 0)
      {
         ibp += 4;
         while (*ibp == ' ') ibp++;
         if (dismount(ibp) < 0)
	 {
            newview = VIEW_ERROR;
            ibp = 0;
            return (1);
         }
         newview = VIEW_MOUNT;
         ibp = 0;
         return (1);
      }
      return(-1);

   case 'e':
      c = *ibp++;
      switch (c)
      {

      case 'm':
         mqh = kyh;
         mql = kyl;
         return (1);

      case 'i':
         run = 2;
         srh = kyh;
         srl = kyl;
         lastcmd = "ei";
         break;

      default:
         return(-1);
      }
      break;

   case 'a':
      automatic = 1;
      return (1);

   case 'm':
      automatic = 0;
      return (1);

   case 's':
      c = *ibp++;
      switch (c)
      {

      case 't':
         run = 1;
         lastcmd = "st";
         break;

      case 's':
         run = 3;
         lastcmd = "ss";
         break;

      case 'w':
         c = *ibp++;
         if (c >= '1' && c <= '6')
	 {
            setssw(c - '0');
            return (1);
         }
	 else
	 {
            return(-1);
         }

      case 'a':
         c = *ibp;
         if (c >= '0' && c <= '7')
	 {
            int i;

            addrstop = 1;
            stopic = 0;
            while (c >= '0' && c <= '7')
	    {
               stopic = (stopic << 3) + (c - '0');
               c = *++ibp;
            }
            itrc_idx = 0;
            for (i = 0; i < 32; i++)
               itrc_buf[i] = 0;
            newview = VIEW_TRACE;
         }
	 else if (c == 'l')
	 {
            char s[100];

            ibp++;
            long_trace();
	    screenposition(windowlen-2,1);
	    clearline();
	    printf ("press enter to continue:");
            fgets(s, sizeof(s), stdin);
            *(strchr(s,'\n')) = '\0';
         }
	 else
	 {
            addrstop = 0;
            newview = VIEW_NONE;
         }
         return (1);

      case 'c':
         single_cycle = 1 - single_cycle;
         lastcmd = "sc";
         return (1);

      default:
         return(-1);
      }
      break;

   case 'd':
      c = *ibp++;
      switch (c)
      {

      case 'n':
         kyl = (kyl &   037777700000) |
               (kyl+1 & 000000077777);
         srh = memh[kyl & (MEMLIMIT)];
         srl = getmeml(kyl & (MEMLIMIT));
         lastcmd = "dn";
         return (1);

      case 's':
         srh = memh[kyl & (MEMLIMIT)];
         srl = getmeml(kyl & (MEMLIMIT));
         lastcmd = "ds";
         return (1);

      default:
         return(-1);
      }
      break;

   case 'l':
      c = *ibp++;
      switch (c)
      {

      case 'c':
         if (automatic == 0)
            break;
         reset();
         channel[0].cunit = 0321;
         goto load_key;

      case 'f':
         while (*ibp == ' ') ibp++;
         reset();
         loadaddr = 0;
         while (isdigit(*ibp)) 
         {
            loadaddr = (loadaddr << 3) | (*ibp++ - '0');
         }
         if (loadaddr == 0) loadaddr = -1;
         while (*ibp == ' ') ibp++;
         if (binloader(ibp, loadaddr) < 0)
         {
            newview = VIEW_ERROR;
            ibp = 0;
            return (1);
         }
         if (automatic == 0)
            break;
         run = 3;
         goto loaded;

      case 't':
      case '\0':
         if (automatic == 0)
            break;
         reset();
         channel[0].cunit = 0221;
load_key:
         if (unitcheck(0, 1) != -1)
	 {
            channel[0].csel = READ_SEL;
            load_chan(0, 1);
            ic = 1;
            srh = 001;   /* LCHA 0 */
            srl = 014400000000;
            run = 3;
         }
loaded:
         lastcmd = "st";
         break;

      default:
         return(-1);
      }
      break;


   case 'o':
      while (*ibp == ' ') ibp++;
      if (mount(ibp) < 0)
      {
         newview = VIEW_ERROR;
         ibp = 0;
         return (1);
      }
      newview = VIEW_MOUNT;
      ibp = 0;
      return (1);

   case 'q':
      iofin();
      printf("\n");
      if (panelmode)
         screenposition (windowlen, 1);
      exit(0);

   case '-':
      kyh |= SIGN;
      c = *ibp++;
      goto setkey;

   case '+':
      c = *ibp++;
   case '0':
   case '1':
   case '2':
   case '3':
   case '4':
   case '5':
   case '6':
   case '7':
   case '.':
      kyh &= ~SIGN;
setkey:
      kp = 11;
      for (;;)
      {
         if (c >= '0' && c <= '7')
	 {
            uint32 v;

            v = c - '0';
            if (kp < 0)
	    {
               kyl =  (kyl & 037777700000) |
                     ((kyl & 000000007777) << 3) | v;
            }
	    else if (kp == 11)
	    {
               kyh = (kyh & (SIGN | 001)) | (v << 1);
            }
	    else if (kp == 10)
	    {
               kyh = (kyh & (SIGN | 006)) | (v >> 2);
               kyl = (kyl & 007777777777) | (v << 30);
            }
	    else
	    {
               kyl = (kyl & ~(07L << (3*kp))) |
                     (v << (3*kp));
            }
         }
	 else if (c == '.')
	 {
            if (kp == 11)
	    {
               kyh = (kyh & SIGN);
               kyl = 0;
            }
	    else if (kp == 10)
	    {
               kyh = (kyh & (SIGN | 006));
               kyl = 0;
            }
	    else
	    {
               kyl = (kyl &
                      (037777777777 << (3*(kp+1))));
            }
            kp = -1;
         }
	 else
	 {
            ibp--;
            return (1);
         }
         if (kp == 0)
            return (1);
         kp--;
         c = *ibp++;
      }

   case 0:
      return (1);

   default:
      return (-1);

   }
   return (0);

}


int 
commands(FILE *cmdfd)
{

   while (ibp = fgets (iline, sizeof(iline), cmdfd))
   {
      if (iline[0] == '#') continue;
      if (docommand () < 0)
      {
         fprintf (stderr, "Syntax error in command file: %s\n", iline);
	 return (-1);
      }
      return (0);
   }
   return (-1);
}

void
console()
{
   int i;

#if defined(UNIX)
        signal (SIGINT, sigintr);
#endif

redraw:
   if (newview == VIEW_NONE)
   {
      if (addrstop)
      {
         newview = VIEW_TRACE;
      }
      else if (errview[0][0])
      {
         newview = VIEW_ERROR;
      }
      else if (prtview[prtviewlen][0])
      {
         newview = VIEW_PRINT;
      }
      else
      {
         newview = VIEW_NONE;
      }
   }

   if (view != newview)
   {
      clear_screen();
      view = newview;
   }

   lights();

   switch (view)
   {

   case VIEW_HELP:
      help();
      newview = VIEW_NONE;
      break;

   case VIEW_MOUNT:
      listmount();
      newview = VIEW_NONE;
      break;

   case VIEW_TRACE:
      trace();
      break;

   case VIEW_ERROR:
      errorview();
      newview = VIEW_NONE;
      break;

   case VIEW_PRINT:
      pview();

   default: ;
   }

   keys();

   total_cycles += cycle_count;
   cycle_count = 0;
   next_lights = NEXTLIGHTS;

   if (ibp == 0 || *ibp == 0)
   {
      if (lastcmd != 0)
      {
	 printf(
	       " %s                                                      \r.",
	       lastcmd);
      }
      else
      {
	 printf(
	       "                                                         \r.");
      }
      ibp = (char *)fgets(iline, sizeof(iline), stdin);
      *(strchr(iline,'\n')) = '\0';
      if (ibp == 0)
      {
         iofin();
         exit(0);
      }
      if (*ibp == 0)
      {
         ibp = lastcmd;
         if (ibp == 0)
            goto redraw;
      }
      else
      {
         lastcmd = 0;
      }
   }

   if ((i = docommand ()) < 0) goto syntax;
   if (i == 1) goto redraw;

   lights();
   if (single_cycle)
   {
      next_steal = 0;
   }
   else
   {
      if (next_steal > NEXTLIGHTS)
         next_steal = NEXTLIGHTS;
   }
   return;

syntax:
   printf("%c", 7);
   ibp = 0;
   goto redraw;
}

void
setssw(int c)
{

   switch(c)
   {

   case 1:
      ssw ^= 040;
      break;

   case 2:
      ssw ^= 020;
      break;

   case 3:
      ssw ^= 010;
      break;

   case 4:
      ssw ^= 004;
      break;

   case 5:
      ssw ^= 002;
      break;

   case 6:
      ssw ^= 001;
      break;
   }
}

void
clear()
{
   uint32 i;

   for (i = 0; i <= MEMLIMIT; i++)
   {
      memh[i] = 0;
      setmeml(i, 0L);
   }
   sih = 0;
   sil = 0;
   reset();
   memset (prtview, '\0', sizeof(prtview));
   memset (errview, '\0', sizeof(errview));
}

void
reset()
{
   int32 i;

   srh = 0;
   srl = 0;
   ach = 0;
   acl = 0;
   mqh = 0;
   mql = 0;
   ic = 0;
   for (i = 0; i < 8; i++)
   {
      xr[i] = 0;
   }
   run = 0;
   sl = 0;
   op = 0;
   stop = 0;
   trap = 0;
   simulate = 0;
   multtag = 1;
   acoflo = 0;
   mqoflo = 0;
   rwsel = 0;
   divchk = 0;
   machchk = 0;
   iochk = 0;
   spill = 0;
   cycle_count = 0;
   single_cycle = 0;
   for (i = 0; i < MAXCHAN; i++)
   {
      memset (&channel[i], '\0', sizeof (Channel_t));
   }
   ctrap_enb = 0;
   ctrap_ind = 0;
   chan_in_op = 0;
   view = VIEW_CLEAR;
}

void
clear_screen()
{
   if (panelmode)
   {
      clearscreen();
      screenposition (1,1);
   }
}

void
keys()
{
   if (panelmode)
   {
      screenposition(windowlen-2,1);
      clearline();
   }
   else
      printf("\n");
}
