/* ------------------------------------------------------------------------- */
/*              I/O AND SCREEN MANAGEMENT OVERLAY                            */
/* ------------------------------------------------------------------------- */

#include "pcstdio.h"
#include "pcdefs.h"             /* header containing all #defines */
#include "pcglobal.h"           /* global variable declarations */

/*      Main function table is here.  If overlays are turned on,
        those functions which are in the other overlays are set to
        their overlay number in this table and their companion 
        tables are compiled.
*/

#ifndef OVLON                   /* in overlay PCREPLI.C */
extern  int KErase();
extern  int KRErase();
extern  int KPick();
extern  int KRPick();
extern  int KPut();
extern  int KRPut();
extern  int KInsLine();
extern  int KDelLine();
extern  int KInsColumn();
extern  int KDelColumn();
                                        /* in overlay PCWIN.C */
extern  int KLock();
extern  int KRLock();
extern  int KUnlock();
extern  int KRUnlock();
extern  int KEdit();
extern  int KWin2();
extern  int KWin1();
extern  int KWhere();
extern  int KUpdate();
extern  int KTitles();
extern  int KF1Hlp();				/* XXX */
extern  int KSF1Hlp();				/* XXX */
extern  int KAF1Hlp();				/* XXX */
extern  int KCF1Hlp();				/* XXX */
extern  int KHelp();
extern  int KMHelp();
extern  int KXHelp();
extern  int KExit();
                                        /* in overlay PCBUF.C */
extern  int BSwap();
extern  int BReDraw();
extern  int KFind();
extern  int KAssocBuf();
extern  int KSwitchBuf();
extern  int KWinOther();
extern  int KKillBuf();
extern  int KStatBuf();
extern  int KDnPage();
extern  int KRtPage();
extern  int KLtPage();
extern  int KUpPage();
extern  int KDnOPage();
extern  int KRtOPage();
extern  int KLtOPage();
extern  int KUpOPage();
#endif                                  /* in PCCOMD.C */
extern  int KLabel();
extern  int KFormula();
extern  int KNumber();
extern  int KBackSpace();
extern  int KNewline();
extern  int KBottom();
extern  int KFarRight();
extern  int KFarLeft();
extern  int KTop();
extern  int KDown();
extern  int KUp();
extern  int KRight();
extern  int KLeft();
extern  int KExchange();
extern  int KSetMark();
extern  int KUnivArg();
extern  int KAbort();
extern  int KReDraw();
extern  int KReCalc();
extern  int KOther();

int     KZap();                 /* these functions are in this overlay */
int     KPosition();
int     KNxtUnlkd();
int     KWidth();
int     KFormat();
int     KWrite();
int     KSave();
int     KPrint();
int     KRPrint();
int     KRead();
int     KJust();

int (*Functions[])() =   {
        &KBackSpace,
        &KNewline,
        &KDown,
        &KUp,
        &KRight,
        &KLeft,

        &KLabel,                /* mainly in PCCOMD.C           */
        &KFormula,
        &KNumber,
        &KBottom,
        &KFarRight,
        &KFarLeft,
        &KTop,
        &KExchange,
        &KSetMark,
        &KUnivArg,
        &KAbort,
        &KReDraw,
        &KReCalc,

#ifdef OVLON
        0,0,0,0,0,0,0,0,0,0,
#else                   /* these functions are in overlay PCREPLI.C */
        &KErase,
        &KRErase,
        &KPick,
        &KRPick,
        &KPut,
        &KRPut,
        &KInsLine,
        &KDelLine,
        &KInsColumn,
        &KDelColumn,
#endif                  /* these functions are in this overlay */
        &KPosition,
        &KNxtUnlkd,
        &KWidth,
        &KFormat,
        &KFormat,
        &KJust,
        &KPrint,
        &KRPrint,
        &KRead,
        &KWrite,
        &KSave,
        &KZap,
#ifdef OVLON            /* these functions are in PCWIN.C */
        2,2,2,2,2,2,2,2,2,2,2,2,2,2,
#else
        &KLock,
        &KRLock,
        &KUnlock,
        &KRUnlock,
        &KEdit,
        &KWin2,
        &KWin1,
        &KWhere,
        &KUpdate,
        &KTitles,
	   &KF1Hlp,				/* XXX */
	   &KSF1Hlp,				/* XXX */
	   &KAF1Hlp,				/* XXX */
	   &KCF1Hlp,				/* XXX */
        &KHelp,
        &KMHelp,
        &KXHelp,
        &KExit,
#endif
#ifdef OVLON            /* these functions are in overlay PCBUF.C */
        3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
#else
        &BSwap,
        &BReDraw,
        &KSwitchBuf,
        &KKillBuf,
        &KStatBuf,
        &KFind,
        &KAssocBuf,
        &KWinOther,
        &KDnPage,
        &KUpPage,
        &KRtPage,
        &KLtPage,
        &KDnOPage,
        &KUpOPage,
        &KRtOPage,
        &KLtOPage,
#endif
        &KOther    };

KPosition()     /* move cursor to a specific position */
{   int pos[2];
    CmdStart("GO TO: ");
    if (!getpos(pos)) {ZapCmdLine();  return;}
    if (finfp != NULL) {curx = pos[0]; cury = pos[1];  return;}
    position(pos[0], pos[1]);
}

KNxtUnlkd()     /* move directly to next unlocked formula */
{   int x, y;  char *GetElt();
    x = curx;  y = cury;
    while (1)
    {   if (++y > lasty)
        {   if (++x > lastx) {BEEP;  return;}
            y = w->miny;
        }
        if (IsNumElt(GetElt(x,y)) && !IsLocked(x,y)) {position(x,y);  return;}
    }
}

getpos(pos)     /* get a typed-in position into array 'pos' */
int pos[];      /* return length in characters typed */
{   int c;
 ne:chrcnt = 0;     /* reset character counter */
    if ((c=NextKey()) == DEL || abort) return(0);
    else if (isalpha(c))
    {   pos[1] = numcoord(c);
        if (pos[1] < w->miny) {BEEP;  goto ne;} else Tputch(c);
    } else {BEEP;  goto ne;}
    if ((pos[0]=getint(0)) < w->minx || pos[0] > MAXLINE)
    {   if (abort) return(0);
        if (keybuf != DEL) BEEP; else chrcnt += 2;
        backup(--chrcnt);  goto ne;
    }
    return(--chrcnt);
}

position(x,y)   /* go directly to <x,y>, redrawing if necessary */
int x,y;
{   int reset;
    reset = 0;
    /* check to see if within screen */
    if (x < w->homex) {w->homex = x;  reset++;} else
      if (x >= w->homex + w->lines) {w->homex = x - w->lines + 1;  reset++;}
    if (y < w->homey) {w->homey = y;  reset++;} else
      if (y >= w->homey+w->cols)
      {	w->homey = y - w->cols;  reset++;
	do {(w->homey)++;  w->cols = NumCols(w);} while (!OnScreen(w,x,y));
      }
    if (reset) {curx = x;  cury = y;  ReDraw(w);} else movecur(x,y);
    ZapCmdLine();
}

/* ----------------------------------------------------------------------- */
/*              Window Formatting                                          */
/* ----------------------------------------------------------------------- */

KWidth()        /* reset column widths */
{   int newwidth, type;

 qu:if ((type=GetGLC("Width:")) == -1) goto rt;
    while ((newwidth=getint(0)) < MINCOLW || newwidth > MAXCOLW)
        switch (keybuf)
        {   case BEL:   goto rt;
            case DEL:   goto qu;
            case '\r':  if (newwidth == -1)
                        {  newwidth = (type == 'g')? DFCOLW : -1;  goto sw; }
            default:    CmdStart("\007Enter width (0-%d): ");
			printf(Tcols-YAXWIDTH);
        }
 sw:switch(type)
    {   case 'g':   if (newwidth) w->colwidth = newwidth;  break;
        case 'c':   indcolw[cury] = newwidth;  
                    if (w2->active && w2->curbuf == w->curbuf) 
                        w2->fullscreen = FALSE;  break;
    }
    w->tdispy = (w->minx - 1)*colwth(w,1) + w->toffy + YAXWIDTH;
    if (w->homey+(newwidth=NumCols(w)) > MAXCOL) w->homey = MAXCOL-newwidth-1;
    w->cols = NumCols(w);  ReDraw(w);  gotkey = 1;
 rt:ZapCmdLine();
}

KFormat()       /* reset display format */
{   int newdecpl, type;  char *Mchg();
 qu:if ((type=GetGLC("Display:")) == -1)
         goto rt;
    while ((newdecpl=getint(0)) < 0)
        switch (keybuf=tolower(keybuf))
        {   case BEL:   goto rt;
            case DEL:   goto qu;
            case '\r':  newdecpl = (type == 'g')? DFDECPL : -1;  goto df;
            case '$':   newdecpl = confirm("Display cents? ")? '&' : '$';
                        goto df;
            case 's':   keybuf = 'e';
            case 'f':
            case '*':   newdecpl = keybuf;  goto df;
	    default:Cmdstart("\007\060 to 15, Sci, *, $, Formula, or <CR>: ");
        }
 df:switch (type)
    {   case 'g':   w->decpl = newdecpl;  break;
        case 'l':   if (curx <= lastx) *(Mchg(screen[curx])) = (char) newdecpl;
                    break;
        case 'c':   coldp[cury] = (char) newdecpl;  break;
    }
    ReDraw(w);
 rt:ZapCmdLine();
}

KJust()         /* change justification parameters */
{   int type, newjust;
 qu:if ((type=GetGLC("Justify:")) == -1) goto rt;
 sw:switch (keybuf=tolower(NextKey()))
    {   case BEL:       goto rt;
        case DEL:       goto qu;
        case '\r':      newjust = -1;  break;
        case 'c':
        case 'l':
        case 'r':       newjust = keybuf;  break;
        default:   Cmdstart("\007Left, Right, Center, or <CR>: ");  goto sw;
    }
    switch (type)
    {   case 'g':   w->just = newjust;  break;
        case 'l':   if (curx <= lastx) *(Mchg(screen[curx])+1) = (char)newjust;
                    break;
        case 'c':   coljust[cury] = (char) newjust;  break;
    }
    ReDraw(w);
 rt:ZapCmdLine();
}

GetGLC(cmd)     /* get Global, Line, or Column */
char *cmd;
{   int type;
    CmdStart(cmd);
    format((*cmd=='W')? " Global or Column? " : " Global, Line, or Column? ");
ga: switch (type=tolower(NextKey()))
    {   case BEL:
        case DEL:   return(-1);
        case 'g':   CmdStart("Global: ");  break;
        case 'l':   CmdStart("Line %d: ");  printf(curx);  break;
        case 'c':   CmdStart("Column %c: ");  printf(letcoord(cury));  break;
        default:    BEEP;  goto ga;
    }
    return(type);
}

KWrite()        /* write to an arbitrary filename */
{   CmdStart("Write to file <CR>: ");  WriteFile();   }

KSave()         /* save to current buffer's filename */
{   gotfile = 1;  WriteFile();   }

WriteFile()     /* output to a filename */
{   int x, y;  char *elt, *np, *ep, *zp;
    struct buffer *Madr();
    if (!getfile(file, "w")) return;
    if (w->colwidth != DFCOLW) {format("\\wg%d\n");  printf(w->colwidth);}
    if (w->decpl != DFDECPL)  {format("\\dg%d\n");  printf(w->decpl);}
    if (w->just != -1) {format("\\jg%c\n");  printf(w->just);}
    for (x=1; x<=lastx; x++)
    {   for (y=1; y<=lasty; y++)
        {   if (abort) {BadWrite();  return;}
            if (elt=GetElt(x,y))
            {   Tputch('>');  outloc(x,y);  Tputch(':');
                switch (*(elt+TYPE))
                {   case LABEL:     format("\"%s");
                                    printf(elt+VALUE);  break;
                    case FORMULA:   format("=%s");
                                    printf(DecForm(elt,EntBuf,0));  
				    Tputch(VALDELIM);	/*now value*/
                    case NUMBER:    ftoa(elt+VALUE, EntBuf, 'e', 20, 12);
                                    np = EntBuf;  while (*np == ' ') np++;
				    ep = np; while (*++ep != 'E');
				    zp = ep; while (*--zp == '0');
				    copystr(ep, ++zp);
                                    format(np);  break;
                }
                Tputch('\n');
            }
            if (x == 1)
            {   saveparam(coldp[y], x, y, ":\\dc%d\n");
                saveparam(indcolw[y], x, y, ":\\wc%d\n");
                saveparam(coljust[y], x, y, ":\\jc%c\n");
            }
        }
        saveparam((char) ((int)GetVElt(x,0)&0xFF), x, 1, ":\\dl%d\n");
        saveparam((char) ((int)GetVElt(x,0)>>8), x, 1, ":\\jl%c\n");
    }
    format(">a1\n");

    /* write out link as last operation for possible failure on input */
    if ((x=Madr(Buff[w->curbuf])->linked) != -1)
    {   format("\\a%s\n");  printf(Madr(Buff[x])->bfile);   }

    Tputch('\032');  foutfp = NULL;  modified = 0;
    if (ferror(chanfp)) {BadWrite();  return;}
    fclose(chanfp);  ZapCmdLine();
}

BadWrite()              /* bad write -- tell user and recover */
{   fclose(chanfp);  unlink(file);  foutfp = NULL;
    CmdStart("\007Disk error - probably full");  LvCmdLine();
    return;
}

saveparam(par, x, y, fmt)       /* save a parameter */
char par;  int x, y;  char *fmt;
{   if (par != 0xFF)
    {   Tputch('>');  outloc(x,y);  format(fmt);  printf(par);   }
}

KRPrint()       /* ranged print */
{   MakRegion();  KPrint();   }

KPrint()        /* print entire or ranged sheet to "prfile" */
{   int x, plasty, phomey, pcols, pminy;

    CmdStart("Print to file <CR>: ");  copystr(PRINTER, prfile);
    if (!getfile(prfile, "w")) return;
    plasty = lasty;  phomey = w->homey;  pcols = w->cols;  /* save globals */
    pminy = w->miny;  w->miny = 1;  format(Pinstr);  /* initialize printer */
    if (rangex[0])
    {   w->homey = rangey[0];  lasty = rangey[1];   }
    else
    {   rangex[0] = w->homey = 1;  rangex[1] = lastx;   }
    do                                  /* output page at a time */
    {   w->cols = PrtCols();            /* compute columns to print */
        for (x=rangex[0]; x<=rangex[1]; x++) {DrLine(w,x);  Tputch('\n');}
        w->homey += w->cols;
        if (w->homey <= lasty) Tputch(FORMFEED);  
	if (abort) {BadWrite();  goto rs;}
    } while (w->homey <= lasty);
    format(Pdeinstr);  
    Tputch('\032');
    foutfp = NULL;
    fclose(chanfp); /* back to terminal I/O */
 rs:lasty = plasty;  w->homey = phomey;  w->cols = pcols; /* restore */
    w->miny = pminy;
 rt:ZapCmdLine();
}

PrtCols()       /* compute number of columns on this printer page */
{   int ncol, ypos;
    for (ncol = ypos = 0; ypos <= prtwidth; ncol++)
        ypos += colwth(w, w->homey+ncol);
    return(--ncol);
}

KRead()
{   if (gotfile != 1) CmdStart("Read from file <CR>: ");
    if(getfile(file, "r")) {updform = 0;  InitWindow();}
}

KZap()  /* also a prefixed command to zap memory and start over */
{   int i;  char *fn, *bn;  struct buffer *b;
    if (initdone && !confirm("Kill ENTIRE Memory? ")) goto rt;
    Minit();
    gotkey = lastx = lasty = scrny = pickbuf = 0;
    for (i=0; i<=MAXLINE; i++)
    {   screen[i] = 0;
        if (i < MAXBUF) Buff[i] = 0;
        if (i <= MAXCOL) indcolw[i] = coldp[i] = coljust[i] = 0xFF;
    }
    updform = 1;

    /* initialize windows */
    w = &win[0];  w2 = &win[1];  w->active = TRUE;  w2->active = FALSE;
    w->curbuf = w->prevbuf = 0;
    w->tlines = Tlines - 1;  w->tcols = Tcols;
    w->toffx = w->toffy = 1;
    w->OK_EOL = w->OK_EOS = TRUE;
    w->colwidth = DFCOLW;  w->decpl = DFDECPL;  w->just = -1;
    InitWindow();  w->fullscreen = Axis(w);
    
    /* initialize first buffer */
    b = Madr(Buff[0] = (struct buffer *) AskMem(BUFDEFSIZE));
    if (initdone) copystr(DFFILE, file);
    copystr(file, b->bfile);  BDerivName(file, b->bname);
    b->blx = b->bscp = 0;  b->bmod = b->updx[0] = 0;
    b->linked = -1;
    /* rest gets filled in the first time we BSaveBuf() this buffer */

    if (!OpnSwpFile())
    {   CmdStart("\007Cannot open help file!");  LvCmdLine();  return;   }

 rt:ZapCmdLine();
}

/* ------------------------ Local Utilities ------------------------------- */

getfile(fname, use)    /* get a filename and record the fact in globals */
char *fname, *use;
{   int len, NonTerm();
    len = (!--gotfile)? 0 : FillBuf(0, NonTerm, EntBuf, 15);
    if (len < 0) {ZapCmdLine();  return(0);}
    if (len) {strupper(EntBuf);  copystr(EntBuf, fname);}
    if (fname == file)  /* update current buffer filename */
        copystr(fname, ((struct buffer *) Mchg(Buff[w->curbuf]))->bfile);
    if (!(chanfp=fopen(fname, use)))
    {   if (*use != 'w') CmdStart("New File");
          else {CmdStart("\007Cannot write %s");  printf(fname);}
        LvCmdLine();  return(0);
    }
    if (*use == 'r') 
    {   CmdStart("Reading %s...");  printf(fname);  finfp = chanfp;   }
    else
    {   CmdStart("Writing %s...");  printf(fname);  foutfp = chanfp;   }
    return(1);
}

InitWindow()    /* initialize window parameters */
{   curx = w->cx = w->cy = cury = w->homex = w->homey = 1;
    w->markx = w->marky = w->minx = w->miny = 1;  modified = 0;
    w->tdispx = w->toffx+1;  w->tdispy = w->toffy+YAXWIDTH;
    w->lines = w->tlines-1;  w->cols = NumCols(w);
}
