/*
 * The functions in this file negotiate with the operating system for
 * characters, and write characters in a barely buffered fashion on the display.
 * All operating systems.
 */
#include <exec/types.h>
#include <exec/exec.h>
#include <intuition/intuition.h>
#include <devices/console.h>
#include <stdio.h>
#include "ed.h"
#include "keymap.h"

struct IntuitionBase *IntuitionBase;
#define INTUITION_REV 29

static struct NewWindow NewWindow = {
   0, 0,
   640, 200,
   -1, -1,
   0,
   SMART_REFRESH | ACTIVATE | WINDOWDRAG | WINDOWDEPTH | WINDOWSIZING,
   NULL,
   NULL,
   "MicroEMACS",
   NULL,
   NULL,
   100, 35,
   640, 200,
   WBENCHSCREEN
};

static struct Window *Window;
static struct IOStdReq consoleIO;
static struct MsgPort consoleMsgPort;

#define NOBUF 1024
static char obuf[NOBUF];
static int nobuf;

/*
 * This function is called once to set up the terminal device streams.
 * On VMS, it translates SYS$INPUT until it finds the terminal, then assigns
 * a channel to it and sets it raw. On CPM it is a no-op.
 */
ttopen()
{
   IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",
							INTUITION_REV);
   if (IntuitionBase == NULL)
   {  printf("can't open Intuition\n"); exit(1); }
   Window = (struct Window *)OpenWindow(&NewWindow);
   if (Window == NULL)
   {  printf("can't open window\n"); exit(1); }
   consoleIO.io_Data = (APTR) Window;
   consoleIO.io_Length = sizeof(*Window);
   if (OpenDevice("console.device", 0, &consoleIO, 0) != 0)
   {  printf("can't open console\n"); exit(1); }
   consoleMsgPort.mp_Node.ln_Type = NT_MSGPORT;
   consoleMsgPort.mp_Flags = 0;
   consoleMsgPort.mp_SigBit = AllocSignal(-1);
   consoleMsgPort.mp_SigTask = (struct Task *)FindTask(NULL);
   consoleIO.io_Message.mn_ReplyPort = &consoleMsgPort;

   consoleIO.io_Command = CD_SETKEYMAP;
   consoleIO.io_Data = (APTR) &KeyMap;
   consoleIO.io_Length = sizeof(KeyMap);
   DoIO(&consoleIO);

   nobuf = 0;
}

/*
 * This function gets called just before we go back home to the command
 * interpreter. On VMS it puts the terminal back in a reasonable state.
 * Another no-operation on CPM.
 */
ttclose()
{
   ttflush();
   CloseDevice(&consoleIO);
   CloseWindow(Window);
   CloseLibrary(IntuitionBase);
}

/*
 * Write a character to the display. On VMS, terminal output is buffered, and
 * we just put the characters in the big array, after checking for overflow.
 * On CPM terminal I/O unbuffered, so we just write the byte out. Ditto on
 * MS-DOS (use the very very raw console output routine).
 */
ttputc(c)
{
        if (nobuf >= NOBUF)
                ttflush();
        obuf[nobuf++] = c;
}

/*
 * Flush terminal buffer. Does real work where the terminal output is buffered
 * up. A no-operation on systems where byte at a time terminal I/O is done.
 */
ttflush()
{
   if (nobuf != 0)
   {
      long old[15], new[15];
      int i;
      
      consoleIO.io_Command = CMD_WRITE;
      consoleIO.io_Data = (APTR) obuf;
      consoleIO.io_Length = nobuf;
      setjmp(old);
      DoIO(&consoleIO);
      setjmp(new);
      for (i = 1; i < 15; ++i)
      {
         if (old[i] != new[i])
	    if (i < 8)
	       printf("ttflush: [D%d] 0x%08x->0x%08x\n", i, old[i], new[i]);
	    else
	       printf("ttflush: [A%d] 0x%08x->0x%08x\n", i - 7, old[i], new[i]);
      }
      nobuf = 0;
   }
}

/*
 * Read a character from the terminal, performing no editing and doing no echo
 * at all. More complex in VMS that almost anyplace else, which figures. Very
 * simple on CPM, because the system can do exactly what you want.
 */
ttgetc()
{
   char ch;
   long old[15], new[15];
   int i;

   consoleIO.io_Command = CMD_READ;
   consoleIO.io_Data = (APTR) &ch;
   consoleIO.io_Length = 1;
      setjmp(old);
   DoIO(&consoleIO);
      setjmp(new);
      for (i = 1; i < 15; ++i)
      {
         if (old[i] != new[i])
	    if (i < 8)
	       printf("ttgetc: [D%d] 0x%08x->0x%08x\n", i, old[i], new[i]);
	    else
	       printf("ttgetc: [A%d] 0x%08x->0x%08x\n", i - 7, old[i], new[i]);
      }
   return((int)ch);
}
