/*--- mrr1term.c ----------------------------------------------------- */
/*  This file contains the window procedure for the terminal window
 *  for MRR1 (WINC).  The terminal emulator is very stupid--so far,
 *  I haven't been too motivated to add a lot of code to interpret
 *  the 7171 VT100 escape sequences.  (Having written a VT220 emulator
 *  a few years ago, I regard this as kind of reinventing the wheel,
 *  but I may get around to it.)
 *
 *  There's no way to get an interrupt each time a character arrives
 *  (as far as I know), so I just set a timer that wakes me up
 *  every once in a while (rather short intervals).  At each
 *  interval, I read all the characters that have been received
 *  since the previous timer interrupt.
 */
#include "windows.h"
#include "ctype.h"
#include "mrr1.h"
#include "newmemos.h"
#include "winundoc.h"
#include "mrr1glob.h"
#include "mrr1stat.h"

#define TIMECOUNT  100
#define BREAKTIME  200

void MoveCaret();
void MoveCursor();
void SetReverseVideo();
void SetNormalVideo();

HDC hDCTerm;                                /* handle to display context */
TypeState *state;
int j;
char *msg;
HBITMAP hCursorMap;
int BreakCount = 0;


/****************************************************************************

    FUNCTION: Mrr1TermWndProc(HWND, unsigned, WORD, LONG)

    PURPOSE:  Processes messages

    MESSAGES:

        WM_SYSCOMMAND - system menu (About dialog box)
        WM_CREATE     - create window
        WM_DESTROY    - destroy window
        WM_CHAR       - ASCII key value received
        WM_LBUTTONDOWN - left mouse button
        WM_MOUSEMOVE   - mouse movement
        WM_LBUTTONUP   - left button released
        WM_KEYDOWN     - key pressed
        WM_KEYUPS      - key released

    COMMENTS:


****************************************************************************/

long FAR PASCAL Mrr1TermWndProc(hWnd, message, wParam, lParam)
HWND hWnd;
unsigned message;
WORD wParam;
LONG lParam;
{
    FARPROC lpProcAbout;
    HMENU hMenu;

    PAINTSTRUCT ps;                              /* paint structure          */
    HDC hDC;                                /* handle to display context */

    char ch, kch;
    int ChCount;
    char mesbuf[60];
    int HiddenCaret = 0;


    switch (message) {
        case WM_SYSCOMMAND:
            return (DefWindowProc(hWnd, message, wParam, lParam));
            break;

        case WM_CREATE:

            /* Set the timer for brief intervals */

            idTimer =  SetTimer(hWnd, NULL, TIMECOUNT, (FARPROC) NULL);
            state = TermSt_Begin;
            xPos = SideSpace;
            yPos = TopSpace;
            MoveCursor();
            /* Create monochrome bitmap of all 1's */
            hCursorMap = CreateBitmap(CharWidth,3,1,1,(LPSTR) "\xff\xff\xff\xff\xff\xff");
            break;

        case WM_SETFOCUS:
            CreateCaret(hWnd,hCursorMap,0,0);
            ShowCaret(hWnd);
            break;

        case WM_KILLFOCUS:
            DestroyCaret();
            break;

        case WM_CHAR:
            /*  A keyboard character has been pressed; simply send
             *  it out the Comm port.
             */
            kch = wParam & 0x7f;
            if(kch != '\010') {
              WriteComm(CommDevice,(LPSTR) &kch, 1);
            }
            break;

        case WM_KEYDOWN:
            /* Control-Page Up means send a Break */
            if(wParam == VK_PRIOR) {
              if(GetKeyState(VK_CONTROL) < 0) {
                SetCommBreak(CommDevice);
                BreakCount = BREAKTIME / TIMECOUNT;
              } else {
                /* Unshifted PgUp means send control-V (Redisplay) */
                WriteComm(CommDevice,(LPSTR)"\x16",1);
              }
            } else {
              for(kch=0; KeySeqs[kch].keycode; kch++) {
                if(KeySeqs[kch].keycode == wParam) {
                  WriteComm(CommDevice, (LPSTR) KeySeqs[kch].outseq,
                    strlen(KeySeqs[kch].outseq));
                  break;
                }
              }
            }
            break;

        case WM_TIMER:
            if(BreakCount) {
              if(! (--BreakCount)) {
                ClearCommBreak(CommDevice);
              }
            }
            hDCTerm = GetDC(hWnd);
            while(ChCount = ReadComm(CommDevice,(LPSTR) &ch,1)) {
                if(!HiddenCaret) {
                  HideCaret(hWnd);
                  HiddenCaret = TRUE;

                  OldTextColor = GetTextColor(hDCTerm);
                  OldBkColor   = GetBkColor(hDCTerm);
                  if(ReverseVideo) {
                    SetReverseVideo();
                  }
                }
                ch &= 0x7f;
                InterpHostChar(ch);
            }
            if(HiddenCaret) {
              if(ReverseVideo) {
                SetNormalVideo();
              }

              MoveCaret();
              ShowCaret(hWnd);
              HiddenCaret = FALSE;
            }

            ReleaseDC(hWnd,hDCTerm);
            break;


        case WM_COMMAND:
            switch(wParam) {

              case IDM_EXIT:
                DestroyWindow(hWnd);
                break;

            }
            break;

        case WM_PAINT:
          /*  Redisplay the window from the array Lines.
           */
            hDC = BeginPaint (hWnd, &ps);

            OldTextColor = GetTextColor(hDC);
            OldBkColor   = GetBkColor(hDC);
            X = SideSpace;
            Y = TopSpace;

            for(il=0; il<MAXLINES; il++) {
              TextOut(hDC,X,Y,&(Lines[il][0]),strlen(&(Lines[il][0])));
              Y += LineHeight;
            }
            PaintCount++;
         /* sprintf(MrrText,"%d Paints",PaintCount);
            TextOut(hDC,100,20,MrrText,strlen(MrrText)); */
            MoveCursor();

            EndPaint(hWnd, &ps);
            break;


        case WM_DESTROY:
            DeleteObject(hCursorMap);
            KillTimer(hWnd, idTimer);                     /* Stops the timer */
            NTerminals--;
            break;

        default:
            return (DefWindowProc(hWnd, message, wParam, lParam));
    }
    return (NULL);
}

/*---  Function InterpHostChar ---------------------------------------
 *
 *   Handle an incoming character from the Comm port.
 */

InterpHostChar(ch)
char ch;
{
  static char prevchar;

  for(j=0; state[j].inchar && state[j].inchar!=CharClass(ch); j++) ;

    switch(state[j].action) {

    case ACT_INIT_ESC:
      EscNum[0] = -1;
      EscNumIndex = 0;
      break;

    case ACT_CR:
      xPos = SideSpace;
      TermCol = 0;
      MoveCursor();
      break;

    case ACT_LF:
    case ACT_DOWN:
      yPos += LineHeight;
      if(++TermRow >= MAXLINES-1) {
          TermRow = 0;
          yPos = TopSpace;
      }
      MoveCursor();
      if(state[j].action == ACT_DOWN) break;

      if(prevchar == '\r') {
        for(ic=TermCol; ic<MAXCHARS; ic++) Lines[TermRow][ic] = ' ';
        TextOut(hDCTerm,xPos,yPos,&(Lines[TermRow][TermCol]),MAXCHARS-TermCol);
      }
      break;

    case ACT_UP:
      yPos -= LineHeight;
      if(--TermRow < 0) {
          TermRow = MAXLINES-1;
          yPos = TopSpace + LineHeight*(MAXLINES-1);
      }
      MoveCursor();
      break;

    case ACT_PRINT:
      /*  Store printing characters in the array Lines (as well as
       *  displaying them), because the receipt of a WM_PAINT message
       *  will require this information to repaint the window.
       */
      if(ch != '\0' && ch != '\x7f') {
        Lines[TermRow][TermCol] = ch;
        Rend[TermRow][TermCol] = ReverseVideo;
        TextOut(hDCTerm,xPos,yPos,&ch,1);

        xPos += CharWidth;
        TermCol++;
        MoveCursor();
      }
      break;

    case ACT_DO_NOTHING:
      msg = "DO_NOTHING";
      break;

    case ACT_START_NUM:
      msg = "ACT_START_NUM";
      EscNum[EscNumIndex] = ch - '0';
      break;

    case ACT_ADD_UP:
      msg = "ACT_ADD_UP";
      EscNum[EscNumIndex] = 10*EscNum[EscNumIndex] + (ch-'0');
      break;

    case ACT_END_NUM:
      EscNum[++EscNumIndex] = -1;
      break;

    case ACT_GO_TO:
      msg = "ACT_GO_TO";
      TermRow = EscNum[0]<=0 ? 0 : EscNum[0]-1;
      TermCol = EscNum[1]<=0 ? 0 : EscNum[1]-1;
      xPos = SideSpace + TermCol*CharWidth;
      yPos = TermRow*LineHeight + TopSpace;
      MoveCursor();
      break;

    case ACT_CLEAR:
      {
        int irow,icol;
        int x=SideSpace;
        int y = 0;

        ReverseVideo = FALSE;
        SetNormalVideo();

        for(irow=0; irow<MAXLINES; irow++) {
          for(icol=0; icol<MAXCHARS; icol++) {
            Lines[irow][icol] = ' ';
            Rend [irow][icol] = FALSE;
          }
          TextOut(hDCTerm,x,y,Lines[irow],MAXCHARS);
          y += LineHeight;
        }
        xPos = SideSpace;
        yPos = TopSpace;
        TermCol = 0;
        TermRow = 0;
        MoveCursor();
        break;
      }

    case ACT_GRAPHIC_REND:
      if(EscNum[0] > 0) {
        ReverseVideo = TRUE;
        SetReverseVideo();
      } else {
        ReverseVideo = FALSE;
        SetNormalVideo();
      }
      break;

    case ACT_EREOL:
      {
        int icol=TermCol;

        for(;icol<MAXCHARS;icol++) Lines[TermRow][icol] = ' ';
        TextOut(hDCTerm,xPos,yPos,&(Lines[TermRow][TermCol]),MAXCHARS-TermCol);
      }
      break;

    case ACT_RIGHT:
      if(TermCol < MAXCHARS-1) {
        TermCol++;
        xPos += CharWidth;
        MoveCursor();
      }
      break;

    case ACT_LEFT:
      if(TermCol>0) {
        TermCol--;
        xPos -= CharWidth;
        MoveCursor();
      }
      break;

    default:
      msg = "default";
      break;
    }
  state = state[j].nextstate;
  prevchar = ch;
#ifdef UNDEF
    if(ch == '\r') {
        xPos = SideSpace;
        TermCol = 0;
    } else if(ch == '\n') {
        yPos += LineHeight;
        if(++TermRow >= MAXLINES) {
            TermRow = 0;
            yPos = 0;
        }
    } else if(ch == '\0') {
        /* do nothing */
    } else {
        /*  Store printing characters in the array Lines (as well as
         *  displaying them), because the receipt of a WM_PAINT message
         *  will require this information to repaint the window.
         */
        Lines[TermRow][TermCol] = ch;
        TextOut(hDCTerm,xPos,yPos,&ch,1);

        xPos += CharWidth;
        TermCol++;

    }
#endif
}

int
CharClass(ch)
unsigned char ch;
{

int class = ch;

  if(isdigit(ch)) {
    class = CL_DIGIT;
#if 0
  } else if(isupper(ch) || islower(ch) ) {
    class = CL_PRINT;
#endif
  }
  return(class);
}

void
MoveCaret()
{
  SetCaretPos(SideSpace+CharWidth*TermCol,TopSpace+LineHeight*TermRow+LineHeight-3);
}

void
MoveCursor()
{
}

void
SetReverseVideo()
{
  SetTextColor(hDCTerm,OldBkColor);
  SetBkColor(hDCTerm,OldTextColor);
}

void
SetNormalVideo()
{
  SetTextColor(hDCTerm,OldTextColor);
  SetBkColor(hDCTerm,OldBkColor);
}
