#define INTUI_V36_NAMES_ONLY

#include <stdio.h>
#include <string.h>
#include <exec/types.h>
#include <exec/tasks.h>
#include <intuition/intuition.h>
#include <intuition/screens.h>
#include <graphics/displayinfo.h>
#include <graphics/text.h>
#include <dos/dos.h>

#include <clib/exec_protos.h>
#include <clib/alib_protos.h>
#include <clib/dos_protos.h>
#include <clib/asl_protos.h>
#include <clib/intuition_protos.h>


int CXBRK(void)    { return(0); }  /* Disable CTRL/C handling */
int chkabort(void) { return(0); }  /* really */

#include "screenchar.h"	/* trs80 font definition*/
#include "gadgets.h"	/* gadget definitions	*/
#include "keyboard.h"	/* trs80 keyboard map	*/


extern UBYTE far rom;	/* trs80 rom file	*/
extern far UBYTE *JUMPTBL; /* trs80 jumptbl ptr */
struct Task *trstask=NULL;
char *trstaskname = "Trashtask";


struct Library *IntuitionBase;
struct Library *AslBase;

UBYTE *scrn[1024];	/* array of ptrs to actual scrn locs */
ULONG SIGMASK=0;
UWORD PROGCOUNT=0;
UWORD CASSPTR=65535;
UWORD CHL;
UWORD CBC;
UWORD CDE;
UWORD TRACE=0;	/*0=NO TRACING 1=SINGLESTEP*/

VOID initscrnarray(struct Screen *scree); /* initialize the screen ptr array*/
void START00(void);
void RESET00(void);
void PAUSE00(void);
int loadcmd(void);
int savecass(void);
int loadcass(void);
int skip(BPTR filep, int n);
int getlowhi(BPTR filep, int *val);
int gethilow(BPTR filep, int *val);
BPTR fp;
char fname[256];
struct FileRequester *fr;
struct Window *win;


VOID main()
{

UWORD pens[] = { ~0 };
struct ColorSpec cols[]={0,0,0,0,	/* colour 0*/
			 1,0,205,0,	/* colour 1*/
			 -1,0,0,0};	/* end of array */


struct TextAttr myta = {"topaz.font",8,NULL,NULL,};

UBYTE *romptr;
UBYTE done=FALSE;

struct Screen *my_screen;
struct Gadget *lesgad;
ULONG class;
UWORD code;
struct IntuiMessage *message;
BOOL shiftkey = FALSE;
UBYTE *shiftloc;
UBYTE *keyloc;
UBYTE *keydown;
int c;



IntuitionBase = OpenLibrary("intuition.library",0);
if (NULL != IntuitionBase)
    {
    if (IntuitionBase->lib_Version >= 37)
        {
         if (NULL != (my_screen = OpenScreenTags(NULL,
				     SA_DisplayID, HIRES_KEY,
				     SA_Width, 512,
				     SA_Height, 171,
				     SA_Left, 32,
				     SA_Pens, (ULONG)pens,
				     SA_Colors, cols,
				     SA_Title,"AmiTRS-80 Model 1 Emulator V0.9f 1999 RedSkull^DC",
                                     SA_Depth, 1,
				     SA_Font, &myta,
				     TAG_DONE)))
            {
            /* screen successfully opened */

	     if (NULL != (win = OpenWindowTags(NULL,
					WA_CustomScreen, my_screen,
					WA_Width, 512,
					WA_Height, 171,
					WA_Gadgets,&buttonGad,
					WA_Backdrop, TRUE,
					WA_IDCMP, IDCMP_GADGETUP | IDCMP_RAWKEY,
					WA_Borderless, TRUE,
					WA_Activate, TRUE,
					TAG_DONE)))
		{
		/* Window now opened */

		romptr=&rom; /* start of trs80 mem map */
		initscrnarray(my_screen);
	
		    if(JUMPTBL= AllocMem(262144,0))
		    {
		     shiftloc=&rom+0x3880;
		     keyloc=&rom+0x3800;
		     keydown=&rom+0x387f;	/* any key down location */

		     trstask=CreateTask(trstaskname,0,START00,1000L);
		     if(!trstask) printf("Couldn't create the TRSTask");
		     while (!done)
			 {
			Wait(1L<<win->UserPort->mp_SigBit);
			while(message = (struct IntuiMessage *)GetMsg(win->UserPort))
			  {
			    class= message->Class;
			    code = message->Code;
			if (class == IDCMP_GADGETUP)
				lesgad=(struct Gadget *)message->IAddress;
			ReplyMsg((struct Message *)message);
				if (class==IDCMP_GADGETUP)
				{
				switch (lesgad->GadgetID)

					{
					case 1:
						Forbid();
						if(FindTask(trstaskname)) RemTask(trstask);
						Permit();
						done=TRUE;
						break;
					case 2:
						if(lesgad->Flags&GFLG_SELECTED)
						PAUSE00();
						else
						Signal(trstask,SIGMASK);
						break;
					case 3:
						RESET00();
						break;
					case 4:
						PAUSE00();
						loadcmd();
						Signal(trstask,SIGMASK);
						break;

						/*SinglStep
						printf("PC=%04x AF=%04x BC=%04x DE=%04x HL=%04x IX=%04x IY=%04x\n",PROGCOUNT,CASSPTR,CBC,CDE,CHL,CASSPTR,CASSPTR);
						Signal(trstask,SIGMASK);
						break;*/
					case 5:
						loadcass();
						break;
					case 6:
						savecass();
						break;
					}
				}
			if (class == IDCMP_RAWKEY)
			 {
			  if (code > 0x7f)
			   { 
			    switch(code)
			     {
			      case 0xE0:
			      case 0xE1:
					shiftkey=FALSE;
					break;
			      default:
					c= (int) (0x7f & code);
					if (shiftkey)
					 {
					 *shiftloc&=~kbdarr[c].shf2;
					 *(keyloc+kbdarr[c].col2)&=~kbdarr[c].bit2;
					 }
					else
					 {
					 *shiftloc&=~kbdarr[c].shf1;
					 *(keyloc+kbdarr[c].col1)&=~kbdarr[c].bit1;
					 }

			     }
			    *keydown=0;	/* no key is now pressed */
			   }
			  else
			   { 
			    switch(code)
			     {
			      case 0x60:
			      case 0x61:
					shiftkey=TRUE;
					break;
			      default:
					c= (int) (0x7f & code);
					if (shiftkey)
					 {
					 *shiftloc|=kbdarr[c].shf2;
					 *(keyloc+kbdarr[c].col2)|=kbdarr[c].bit2;
					 Delay(1L);
					 }
					else
					 {
					 *shiftloc|=kbdarr[c].shf1;
					 *(keyloc+kbdarr[c].col1)|=kbdarr[c].bit1;
					 Delay(1L);
					 }
			     }
			    *keydown=255;	/* set "any key down" */
			   }
			   }

			   }
			 }
		     Delay(50L);
		     FreeMem(JUMPTBL,262144);
		    }

		

		CloseWindow(win);
		}
            CloseScreen(my_screen);
            }
        }
    CloseLibrary(IntuitionBase);
    }
}

VOID initscrnarray(struct Screen *scree)
{
UBYTE *testloc;
USHORT cnt;

		testloc=scree->BitMap.Planes[0];
		testloc+=1728; /* start at line 4 */
		
		for (cnt=0;cnt<1024;cnt+=1)
		{

		if(cnt==64)testloc+=512;
		if(cnt==128)testloc+=512;
		if(cnt==192)testloc+=512;
		if(cnt==256)testloc+=512;
		if(cnt==320)testloc+=512;
		if(cnt==384)testloc+=512;
		if(cnt==448)testloc+=512;
		if(cnt==512)testloc+=512;
		if(cnt==576)testloc+=512;
		if(cnt==640)testloc+=512;
		if(cnt==704)testloc+=512;
		if(cnt==768)testloc+=512;
		if(cnt==832)testloc+=512;
		if(cnt==896)testloc+=512;
		if(cnt==960)testloc+=512;

		scrn[cnt]=testloc;
		testloc+=1;
		}
}




int loadcmd(void)
{
	int	n;
	int i;
	unsigned int addr;
	UBYTE *dum;
	int ch;

 if (AslBase = OpenLibrary("asl.library", 37L))
   {
    if (fr = (struct FileRequester *)
	   AllocAslRequestTags(ASL_FileRequest,
		ASL_Hail,       (ULONG)"Disk Image file requester",
		ASL_Height,     150,
		ASL_Width,      220,
		ASL_LeftEdge,   20,
		ASL_TopEdge,    20,
		ASL_OKText,     (ULONG)"OKAY",
		ASL_CancelText, (ULONG)"not OK",
		ASL_File,       (ULONG)"newdos80",
		ASL_Window,     win,
		TAG_DONE))
      {
       if (AslRequest(fr, NULL))
         {
          strcpy(fname,fr->rf_Dir);
          AddPart(fname,fr->rf_File,255);
         }
       FreeAslRequest(fr);
      }
    else printf("User Cancelled\n");
    if(AslBase)CloseLibrary(AslBase);
   }
	if (!(fp = Open(fname,MODE_OLDFILE)))
		return 0;

	ch = FGetC(fp);

	if (ch == 1)
		UnGetC(fp,ch);
	else if (ch != 5) {
		Close(fp);
		printf("No magic byte of 5, not a .cmd file.");
		return 0;
	}
	else if (!skip(fp, FGetC(fp))) {
		Close(fp);
		return 0;
	}

	for (;;) {
		if (!gethilow(fp, &n)) { Close(fp); return 0; }
		if (n == 514) break;

		if (n > 256)n -= 256;

		n -= 2;

		if (n == 0) n = 256;
		else if (n < 0)n += 256;

		if (!getlowhi(fp, &addr)) { Close(fp); return 0; }
		dum=&rom+addr;
		for (i = 0; i < n; i++)
			{
			*dum++=FGetC(fp);
			}
	}

	if (!getlowhi(fp, &addr)) { Close(fp); return 0; }
	Close(fp);
	PROGCOUNT=(UWORD)addr;
	return 1;
}

int skip(BPTR filep, int n)
{
	while (n-- > 0)
		if (FGetC(filep) == EOF) {
			return 0;
		}

	return 1;
}

int gethilow(BPTR filep, int *val)
{
	int hi;
	int low;

	hi = FGetC(filep);
	low = FGetC(filep);

	if (hi == EOF || low == EOF) {
		return 0;
	}

	*val =  hi * 256 + low;

	return 1;
}

int getlowhi(BPTR filep, int *val)
{
	int hi;
	int low;

	low = FGetC(filep);
	hi = FGetC(filep);

	if (low == EOF || hi == EOF) {
		return 0;
	}

	*val = hi * 256 + low;

	return 1;
}
	
int savecass(void)
{
 if (AslBase = OpenLibrary("asl.library", 37L))
   {
    if (fr = (struct FileRequester *)
	   AllocAslRequestTags(ASL_FileRequest,
		ASL_Hail,       (ULONG)"Cassfile requester",
		ASL_Height,     150,
		ASL_Width,      220,
		ASL_LeftEdge,   20,
		ASL_TopEdge,    20,
		ASL_OKText,     (ULONG)"OKAY",
		ASL_CancelText, (ULONG)"not OK",
		ASL_File,       (ULONG)"Cassfile",
		ASL_Window,     win,
		TAG_DONE))
      {
       if (AslRequest(fr, NULL))
         {
          strcpy(fname,fr->rf_Dir);
          AddPart(fname,fr->rf_File,255);
         }
       FreeAslRequest(fr);
      }
    if(AslBase)CloseLibrary(AslBase);
   }
	if (!(fp = Open(fname,MODE_NEWFILE)))
		return 0;

	Write(fp,&rom+0x10000,(LONG)CASSPTR+1);
	Close(fp);
	return 1;

}
int loadcass(void)
{
 if (AslBase = OpenLibrary("asl.library", 37L))
   {
    if (fr = (struct FileRequester *)
	   AllocAslRequestTags(ASL_FileRequest,
		ASL_Hail,       (ULONG)"Cassfile requester",
		ASL_Height,     150,
		ASL_Width,      220,
		ASL_LeftEdge,   20,
		ASL_TopEdge,    20,
		ASL_OKText,     (ULONG)"OKAY",
		ASL_CancelText, (ULONG)"not OK",
		ASL_File,       (ULONG)"Cassfile",
		ASL_Window,     win,
		TAG_DONE))
      {
       if (AslRequest(fr, NULL))
         {
          strcpy(fname,fr->rf_Dir);
          AddPart(fname,fr->rf_File,255);
         }
       FreeAslRequest(fr);
      }
    if(AslBase)CloseLibrary(AslBase);
   }
	if (!(fp = Open(fname,MODE_OLDFILE)))
		return 0;

	CASSPTR=(UWORD)Read(fp,&rom+0x10000,65536L)-1;
	Close(fp);
	return 1;

}
