/** SCI input/output **/

#ifdef USE_SERIAL_IO

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sim.h"
#include "options.h"
#include "serial_io.h"
#include "sim_irq.h"

extern m6811	state;
extern byte *	memory;
extern short * breaks;


enum { 	/* item numeration of serial dialog (do not modify!) */
			iTextIn = 1, iTextOut, iFromFile, iToFile,
			iDeferred = 9, iSendNow, iTextLast= 11 };

Handle	gInText, gLastText;
Boolean	gSendOnCR, gWaiting;

DialogPtr serialDlg = nil;
Str255	buf_fromSCI = "\p",
		buf_queuedToSCI = "\p",
		buf_toSCI = "\p";

short iType;
Handle iHandle;
Rect iRect;
FILE	* fileFrom = NULL,
		* fileTo = NULL;


void init_serial_io()

	serialDlg = GetNewDialog(208,NULL,(WindowPtr)-1L);
	GetDialogItem(serialDlg,iTextIn,&iType,&gInText,&iRect);
        /* HLock(gInText); */

	GetDialogItem(serialDlg,iTextLast,&iType,&gLastText,&iRect);
        /* HLock(gLastText); */

	gSendOnCR = false; /* default: immediate send */
	gWaiting = gSendOnCR;
	GetDialogItem( serialDlg, iDeferred, &iType, &iHandle, &iRect);
	SetControlValue ((ControlHandle)iHandle, gSendOnCR);

	SetDialogDefaultItem(serialDlg, iSendNow);
	if (gSendOnCR)
		ShowDialogItem(serialDlg, iSendNow);
	else
		HideDialogItem(serialDlg, iSendNow);
}	


Boolean handleSerial(EventRecord event,short hit)
{
Boolean handled = false;
/*
static SFTypeList myTypes = { 'TEXT' };
static SFReply rep;
Point SFGwhere = { 90, 82 };
Point SFPwhere = { 106, 104 };
short tmp;
*/
	switch(hit)
	{
		case 5: /* clear */
			GetDialogItem(serialDlg,iTextOut,&iType,&iHandle,&iRect);
			SetDialogItemText(iHandle,"\p");
			GetDialogItem(serialDlg,iTextLast,&iType,&iHandle,&iRect);
			SetDialogItemText(iHandle,"\p");
			break;
		case iDeferred: /* send on CR */
			GetDialogItem( serialDlg, iDeferred, &iType, &iHandle, &iRect);
			gSendOnCR = !GetControlValue ((ControlHandle)iHandle);
			SetControlValue ((ControlHandle)iHandle, gSendOnCR);
	
			gWaiting = gSendOnCR;
	
			if (gSendOnCR)
			{
				ShowDialogItem(serialDlg, iSendNow);
				GetDialogItem(serialDlg, iSendNow, &iType, &iHandle, &iRect);
				HiliteControl((ControlHandle)iHandle, 0);
			}
			else
				HideDialogItem(serialDlg, iSendNow);
			break;
		case iSendNow:	/* send now */
			gWaiting = false;
			break;
	/*	case iFromFile:  
			if (fileFrom!=NULL) fclose(fileFrom);
			SFGetFile(SFGwhere, "\p", 0L, 1, myTypes, 0L, &rep );
			if (rep.good && GetVol( 0, &tmp)==noErr && SetVol( 0, rep.vRefNum)==noErr)
			{
				PtoCstr(rep.fName); 
				if ((fileFrom = fopen((char *)rep.fName,"r")) == NULL)
					Error("error opening input file");
				SetVol( 0, tmp);
			} else fileFrom = NULL;
			break;
		case iToFile: /* to file.. */
			if (fileTo!=NULL) fclose(fileTo);
			SFPutFile(SFPwhere, "\p", "\p", 0L,  &rep);
			if (rep.good && GetVol( 0, &tmp)==noErr && SetVol( 0, rep.vRefNum)==noErr)
			{
				PtoCstr(rep.fName);
				if ((fileTo = fopen((char *)rep.fName,"w")) == NULL)
					Error("error opening output file");
				SetVol( 0, tmp);
			} else fileTo = NULL;
			break;
	*/
	};
	return handled;
}

/** head-pop & tail-push **/

PRIVATE
char popC(Str255 buf)
{	register short i,len = buf[0];
	char c;
	if (len>0) { /* simple pop */
		buf[0]--; 
		c = buf[1];
		for(i=1;i<len;i++) buf[i]=buf[i+1];
	} else c = '\0'; /* EOF character - the right one ? */
	return c;
}

PRIVATE
void pushC(Str255 buf,char c) 
{	register short i,len = buf[0];
	
	if (len<255) { /* simple push */
		len = ++buf[0];
	} 
	else
	{	/* shift */
		for(i=1;i<255;i++) buf[i]=buf[i+1];
	}
	buf[len]=c;
}	

short serial_output(byte * /*memory*/,m6811 * /*state*/, byte c)
{
CAVEAT("could be optimized");

	if (! c) return 0;

	GetDialogItem(serialDlg,iTextOut,&iType,&iHandle,&iRect);
	GetDialogItemText(iHandle,buf_fromSCI);
	
	if (fileTo)
		putc(c,fileTo); 
	else
		pushC(buf_fromSCI,c);
	
	SetDialogItemText(iHandle,buf_fromSCI);
	
	return 1;
}

short serial_input(byte * /*memory*/,m6811 * /*state*/, byte *c)
{	
	GetDialogItemText(gInText,buf_queuedToSCI);
	GetDialogItemText(gLastText, buf_toSCI);

	if (fileFrom)
		*c = getc(fileFrom);
	else
	{
		if (gWaiting) return 0;

		if (*buf_queuedToSCI == 0)
		{
			/* empty buffer, ready to wait if necessary */
			gWaiting = gSendOnCR;	
			return 0; /* no characters read */
		}
		*c = popC(buf_queuedToSCI);
		pushC(buf_toSCI, *c);
	}

	SetDialogItemText(gInText,buf_queuedToSCI);
	SetDialogItemText(gLastText,buf_toSCI);
	return 1;		
}


/*-----------------------------------------------------*/
#ifdef NEVER
#pragma mark -
#pragma mark ее OBSOLETE TRAP STUFF ее

#define NMAX_TRAPS 64

typedef short (*t_handler)(byte *m,m6811 *s);

typedef struct {
	t_handler hdlr;
	char *name;
} trapRec;

/* local functions */
short ser_tx(byte *mem,m6811 *s);
short ser_rx(byte *mem,m6811 *s);
void init_traps();
void handle_s wi();
short ins_trap(byte code,char *trapName,t_handler handler);

/* globals */
trapRec t_table[NMAX_TRAPS];


void init_traps()
{	short i;

	for(i=0;i<NMAX_TRAPS;i++)
	{	t_table[i].name = NULL;
		t_table[i].hdlr = NULL;
	}
	
	ins_trap(1,NULL,ser_rx);
	ins_trap(2,NULL,ser_tx);
}


short ins_trap(byte code,char *trapName,t_handler handler)
{
	if (t_table[code].name==NULL && t_table[code].hdlr==NULL)
	{
		t_table[code].hdlr = handler;
		/***
		if (trapName)
			strcpy(t_table[code].name = (char *)malloc(strlen(trapName)),trapName);
		*******/
	} else Error("Tried to install a duplicate trap handler (%d)",code);
	return 0;
}

void handle_swi()
{
t_handler xec;
byte code;
	cycle(&state, 14);
	if (Options.SWItraps)
	{
		code = fetch8(memory,&state);
		if (xec = t_table[code].hdlr) xec(memory,&state);
		else Error("Uninitialized trap (%d) at %lx",code,get_pc(&state));
	}
	else not_done(state, memory);
}

#endif  /* NEVER */

#endif /* USE_SERIAL_IO */
