#include "exec/types.h"
#include "exec/ports.h"
#include "exec/devices.h"
#include "exec/io.h"
#include "exec/memory.h"
#include "devices/console.h"
#include "intuition/intuition.h"
struct MsgPort *CreatePort();
struct IOStdReq *CreateStdIO();
struct Window *OpenWindow();
void *GetMsg();

#define ESC 27


extern struct IOStdReq *ConWriteReq;
extern struct IOStdReq *ConReadReq;
extern struct Window *Win;
extern ULONG InSerSigMask;
extern int FullDuplex;
extern struct MsgPort  *InSerPort;
extern struct IOExtSer *InSer;
static int ConOpen;
extern struct MsgPort  *ConReadPort,*ConWritePort;

/*
 * mini-terminal function
 * exit when user hits close box
 *
 */
term()
{
    char ConChar,SerChar;
    ULONG ConInMask,mask,IntuiMask;
    struct IntuiMessage *message;

    ConInMask = 1 << (ConReadPort->mp_SigBit);
    IntuiMask = 1 << (Win->UserPort->mp_SigBit);
    QueueRead(ConReadReq,&ConChar);
    SendSer(1,&SerChar);
    while(1) {
	mask=Wait(ConInMask|InSerSigMask|IntuiMask);
	if(CheckQuit()) break;
	if( mask & ConInMask ) {
	    GetMsg(ConReadPort);
	    LWriteSer(&ConChar,1);
	    if(!FullDuplex) ConPutChar(ConWriteReq,ConChar);
	    QueueRead(ConReadReq,&ConChar);
	}
	if( mask & InSerSigMask ) {
	    GetMsg(InSerPort);
	    ConPutChar(ConWriteReq,SerChar&0x7F);
	    SendSer(1,&SerChar);
	}
    }
    /*if( (mask & InSerSigMask)==0) {
	AbortIO(InSer);
	Wait(InSerSigMask);
    }
    GetMsg(InSerPort);
    if( (mask & ConInMask)==0) {
	AbortIO(ConReadReq);
	Wait(ConInMask);
    }
    GetMsg(ConReadPort);*/
    KillIO( (struct IOStdReq *)InSer,mask);
    KillIO(ConReadReq,mask);
    return 0;
}


/*
 * Open a console device
 *
 */
      int
OpenConsole(WriteReq,ReadReq,Win)
    struct IOStdReq **WriteReq;
    struct IOStdReq **ReadReq;
    struct Window *Win;
{
    int error;

    ConWritePort = CreatePort(0L,0L);
    if ( ConWritePort == NULL ) {
	CloseConsole();
	return -1;
    }
    *WriteReq = CreateStdIO(ConWritePort);
    if( WriteReq == NULL ) {
	CloseConsole();
	return -1;
    }

    ConReadPort = CreatePort(0L,0L);
    if ( ConReadPort == NULL ) {
	CloseConsole();
	return -1;
    }

    *ReadReq = CreateStdIO(ConReadPort);
    if( ReadReq == NULL ) {
	CloseConsole();
	return -1;
    }

    (*WriteReq)->io_Data = (APTR) Win;
    (*WriteReq)->io_Length = sizeof(*Win);
    error = OpenDevice("console.device", 0, *WriteReq, 0);
    (*ReadReq)->io_Device = (*WriteReq)->io_Device;
    (*ReadReq)->io_Unit   = (*WriteReq)->io_Unit;
	  /* clone required parts of the request */
    if( !error ) ConOpen=TRUE;
    else CloseConsole();
    return error;
}

CloseConsole(ReadReq,WriteReq)
struct IOStdReq *WriteReq;
struct IOStdReq *ReadReq;
{
    if(ConOpen)       CloseDevice(ReadReq);
    if( ConReadPort)  DeletePort(ConReadPort);
    if( ReadReq)      DeleteStdIO(ReadReq);
    if( ConWritePort) DeletePort(ConWritePort);
    if( WriteReq)     DeleteStdIO(WriteReq);
}

/* Output a single character to a specified console */

      int
ConPutChar(request,character)
      struct IOStdReq *request;
      char character;
      {
	    request->io_Command = CMD_WRITE;
	    request->io_Data = (APTR)&character;
	    request->io_Length = 1;
	    request->io_Flags = IOF_QUICK;
	    DoIO(request);
	    return(0);
      }

/* Output a NULL-terminated string of characters to a console */

      int
ConPutStr(request,string)
      struct IOStdReq *request;
      char *string;
      {
	    request->io_Command = CMD_WRITE;
	    request->io_Data = (APTR)string;
	    request->io_Length = -1;
	    DoIO(request);
	    return(0);
      }

      /* queue up a read request to a console */

      int
QueueRead(request,whereto)
      struct IOStdReq *request;
      char *whereto;
      {
	    request->io_Command = CMD_READ;
	    request->io_Data = (APTR)whereto;
	    request->io_Length = 1;
	    SendIO(request);
	    return(0);
      }

 /*
  * Check if user has hit close box
  *
  */

int CheckQuit()
{
 int Quit;
 struct IntuiMessage *message;

    Quit=FALSE;
    while( ((message = (struct IntuiMessage *)
			GetMsg(Win->UserPort) ) != NULL)) {
	if(message->Class==CLOSEWINDOW) Quit=TRUE;
	ReplyMsg(message);
    }
    return Quit;
}

ConGetC(request)
struct IOStdReq *request;
{
  char c;

    request->io_Command = CMD_READ;
    request->io_Data = (APTR)&c;
    request->io_Length = 1;
    DoIO(request);
    return c;
}

