/****************************************\
* This file controls the display (dpy.c) *
\****************************************/

#include <exec/types.h>
#include <graphics/gfxbase.h>
#include <graphics/gfx.h>
#include <graphics/text.h>
#include <stdio.h>
#include <intuition/intuitionbase.h>
#include <intuition/intuition.h>

extern struct IntuitionBase *IntuitionBase;
extern struct GfxBase       *GfxBase;

extern Beep();

static short x, y, mode, parse, saved_arg, dpytype, autocr;

static struct RastPort *rp;
static struct Window *w;

#define ctrl  0x1F  /* turns letter into ctrl char */
#define INVIS 0x80 /* returned by Emit for non-printed chars */

/* Screen dimensions */

#define LEFT    0
#define RIGHT   LEFT+8*80-1
#define TOP     4 /* overlapped by menu stripe, but so what */
#define BOTTOM  TOP+8*24-1

/* Mode bits */

#define EMPH    (1<<0)  /* emphasis (implemented as alternate background) */
#define BLINK   (1<<1)  /* blinking (implemented as colored text) */
#define INSDEL  (1<<2)  /* insert/delete mode */
#define ROLL    (1<<3)  /* what to do when cursor moves down from last line */

/* Parse-state bits */

#define NORMAL   0
#define QUOTING  1  /* next char is displayed even if special */
#define CURSOR   2  /* next 2 chars specify new cursor loc */
#define CURSOR2  3  /* first cursor-loc char is in saved_arg */

/* Display types */

#define GLASS  0  /* vanilla, handles BS, FF, and BEL specially */
#define SAIL   1  /* DM with blink/bold swapped & 128 possible chars */
#define MAX_TYPE  1

/*
 * Initialisation
 */

SetUpDisplay(window, type) struct Window *window; int type; {
   if (type >= 0 && type <= MAX_TYPE) dpytype = type;
   if (window) {
      Move(rp=((w=window)->RPort), x=LEFT, (y=TOP)+6);
      ClearScreen(rp);
      Cursor();
      }
   parse = NORMAL;
   mode = ROLL;
   autocr = FALSE;
   }

/*
 * Querying re special SAIL chars
 *
 * Certain control chars have special effects when sent to the Stanford host.
 * Since these special effects are being provided by certain function keys,
 * the control chars themselves can be interpreted as ordinary type-in.  To
 * do this, you have to ship Stanford a special prefix char.  This function
 * lets the main loop test whether such a prefix is needed.
 */

NeedQuote(c) char c; {
   if (dpytype == SAIL) switch (c) {
      case ctrl&'C':
      case ctrl&'^':
      case ctrl&'_':
         return(TRUE);
      }
   return(FALSE);
   }

/*
 * The Guts
 *
 * Process one output char; returns char to go into log file (INVIS if none)
 */

static char RealEmit(c) char c; {
   if (autocr) switch (c) { /* suppress explicit CR/LF after wrapping around */
      case ctrl&'M': return(INVIS);
      case ctrl&'J': {autocr = FALSE; return(c);};
      default: autocr = FALSE;
      }
   if (parse == CURSOR || parse == CURSOR2) {
      switch (c) {
         case ctrl&'B':
         case ctrl&'L':
         case ctrl&'Q':
         case ctrl&'R':
         case ctrl&'X':
         case ctrl&'^':
         case ctrl&'_':
            parse = NORMAL; /* new control char overrides cursor command */
            break;
         default:
            if (parse == CURSOR) {
               saved_arg = c^0x60;
               parse = CURSOR2;
               return(INVIS);
               }
            x = min(79, saved_arg&0xFF) * 8 + LEFT;
            y = min(23, (c^0x60)&0xFF) * 8 + TOP;
            parse = NORMAL;
            return(INVIS);
         }
      }
   if ((c >= ' ' && c <= '~') || parse == QUOTING) { /* display this char */
      if (mode & INSDEL && x < RIGHT-8)
         ScrollRaster(rp, -8, 0, x, y, RIGHT, y+7);
      Show(c);
      parse = NORMAL;
      return(c);
      }
   switch (c) {
      case ctrl&'B': /* home cursor */
         if (dpytype == SAIL) {x = LEFT; y = TOP;}
         break;
      case ctrl&'G': /* beep */
         if (Beep()) DisplayBeep(w->WScreen);
         break;
      case ctrl&'H': /* backspace */
         if (! (mode & INSDEL)) x = max(x-8, LEFT);
         else if (x < RIGHT-8) ScrollRaster(rp, 8, 0, x, y, RIGHT, y+7);
         else {Move(rp, x, y+6); ClearEOL(rp);}
         break;
      case ctrl&'I': /* tab */
         x = ((x-LEFT) / 64 + 1) * 64 + LEFT;
         if (x <= RIGHT) return(c);
         x = LEFT;
      case ctrl&'J': /* line feed (or tab overflow) */
         if (! (mode & INSDEL)) {DownLine(); return(c);}
         if (y < BOTTOM-8) ScrollRaster(rp, 0, -8, LEFT, y, RIGHT, BOTTOM);
         else {Move(rp, LEFT, y+6); ClearEOL(rp);}
         break;
      case ctrl&'L': /* clear screen or set cursor */
         if (dpytype == SAIL) parse = CURSOR;
         else {
            Move(rp, x=LEFT, (y=TOP)+6);
            ClearScreen(rp);
            }
         break;
      case ctrl&'M': /* carriage return (or excess tab) */
         x = LEFT;
         break;
      case ctrl&'N': /* turn on bold */
         if (dpytype == SAIL) mode |= EMPH;
         break;
      case ctrl&'O': /* turn on blinking */
         if (dpytype == SAIL) mode |= BLINK;
         break;
      case ctrl&'P': /* turn on insert/delete mode */
         if (dpytype == SAIL) mode |= INSDEL;
         break;
      case ctrl&'W': /* erase to EOL */
         if (dpytype == SAIL) {
            Move(rp, x, y+6);
            ClearEOL(rp);
            }
         break;
      case ctrl&'X': /* cancel modes */
         if (dpytype == SAIL) mode = 0;
         break;
      case ctrl&'Z': /* cursor up */
         if (dpytype != SAIL) break;
         if (! (mode & INSDEL)) y = max(TOP, y-8);
         else if (y < BOTTOM-8) ScrollRaster(rp, 0, 8, LEFT, y, RIGHT, BOTTOM);
         else {Move(rp, LEFT, y+6); ClearEOL(rp);}
         break;
      case ctrl&'[': /* quote next character */
         if (dpytype == SAIL) parse = QUOTING;
         break;
      case ctrl&'\\': /* cursor right */
         if (dpytype != SAIL) break;
         if (mode & INSDEL) {
            if (x < RIGHT-8) ScrollRaster(rp, -8, 0, x, y, RIGHT, y+7);
            else {Move(rp, x, y+6); ClearEOL(rp);}
            }
         else if ((x += 8) > RIGHT) {
            x = LEFT;
            if ((y += 8) > BOTTOM) y = TOP;
            }
         break;
      case ctrl&']': /* turn on roll mode */
         if (dpytype == SAIL) mode |= ROLL;
         break;
      case ctrl&'^': /* master clear */
      case ctrl&'_': /* clear unprotected text */
         if (dpytype != SAIL) break;
         mode &= ~(BLINK | EMPH | INSDEL);
         Move(rp, x=LEFT, (y=TOP)+6);
         ClearScreen(rp);
         break;
      } /* end of switch (c) for control chars */
   return(INVIS);
   } /* end of RealEmit */

/*
 * Various screen-action functions
 */

static Show(c) char c; {
   Move(rp, x, y+6);
   if (c < ' ') c += 0x80; /* chars 00-1F are hidden in 80-9F in the font */
   if (mode & EMPH) SetBPen(rp, 2); /* emphasis by changing background */
   if (mode & BLINK) SetAPen(rp, 3); /* "blink" by changing foreground */
   Text(rp, &c, 1);
   if (mode & EMPH) SetBPen(rp, 0);
   if (mode & BLINK) SetAPen(rp, 1);
   if ((x += 8) > RIGHT) {
      x = LEFT;
      DownLine();
      autocr = TRUE;
      }
   }

static DownLine() {
   if ((y += 8) > BOTTOM) {
      y -= 8;
      if (mode & ROLL) ScrollRaster(rp, 0, 8, LEFT, TOP, RIGHT, BOTTOM);
      else y = TOP;
      }
   }

static Cursor() {
   SetAPen(rp, 3);
   SetDrMd(rp, COMPLEMENT);
   RectFill(rp, x, y, x+7, y+7);
   SetDrMd(rp, JAM2);
   SetAPen(rp, 1);
   }

/*
 * Public function to process one char
 */

char Emit(c) char c; {
   Cursor();
   c = RealEmit(c & 0x7F);
   Cursor();
   return(c);
   }

/*
 * Public function to process a string of chars (not currently used)
 */

Emits(string) char *string; {
   Cursor();
   while (*string) RealEmit(*string++ & 0x7F);
   Cursor();
   }
