#include "sysheaders.h"
#include "cdpanel.h"
#include "CompactPlayer.h"

long __oslibversion = 37;
long __classactversion = 40;

UBYTE Version[] = "$VER: CompactPlayer 1.6 " __AMIGADATE__;

BOOL Dummy(void) { return FALSE; }

void (*CD_Eject)(UBYTE );
void (*CD_Stop)(void);
void (*CD_Play)(ULONG );
void (*CD_PauseResume)(UBYTE );
void (*CD_Seek)(LONG );
ULONG (*CD_Snoop)(ULONG * , ULONG * , ULONG * , ULONG );
ULONG (*CD_ReadTOC)(void);
BOOL (*CD_IsCD)(void);
void (*CD_Close)(void) = (void (*)(void))Dummy;

/*****************************************************************
 * Error message
 */

void 
ErrorMsg( const STRPTR error, ... )
{
	ULONG *args = ((ULONG *)&error) + 1;
	
	/* Display an error easyrequest */
	
	struct EasyStruct req =
	{
		sizeof(struct EasyStruct),
		0,
		NULL, NULL, NULL
	};
	
	req.es_Title = GS(ERROR_TITLE);
	req.es_TextFormat = error;
	req.es_GadgetFormat = GS(ERROR_BUTTON);
	
	EasyRequestArgs( NULL, &req, NULL, args );
}

void 
Sprintf(char *buffer, const char *ctl, ...)
{
	ULONG *args = (ULONG *)&ctl;
	
	/* Print a string */
	
	RawDoFmt((char *)ctl, ++args, (void (*))"\x16\xc0\x4e\x75", buffer);
}

int
Init_Device(void)
{
	CD_Close();
	if (!strcmp("cd.device", Device))
		return Open_CD();
	else
		return Open_SCSI();
}

/********************************************************
 * Index files
 */
 
ULONG TOCL[MAX_TOC];					/* track lenghts in blocks */
ULONG TOCT[MAX_TOC];					/* track lenghts in seconds */
UBYTE TOCF[MAX_TOC];					/* audio/data */
STRPTR TOCS[MAX_TOC];					/* titles */
ULONG TOCP[MAX_TOC];					/* program */
STRPTR TITLE[2];					 	/* artist/record */
UBYTE TitleBuffer[(MAX_TOC+2)*40];		/* title string buffer */
ULONG Tracks;
ULONG Track;
BOOL done;

/***********************************************************
 * Primary event handler
 */

extern struct List *BrowserNodesA( STRPTR * );
extern void FreeBrowserNodes( struct List * );

struct List *TrackList;
struct MsgPort *AppPort, *WinPort;

static void
MainLoop(void)
{
	ULONG sig,	wsig = 1L << WinPort->mp_SigBit, 
				asig = 1L << AppPort->mp_SigBit, 
				tsig = 1L << TimerPort->mp_SigBit,
				rsig;
				
	GetAttr( AREXX_SigMask, ARexxObj, &rsig );

	while (done == FALSE)
	{
		sig = Wait(wsig | asig | tsig | rsig | SIGBREAKF_CTRL_C);

		if (sig & (wsig | asig))
		{
			/* Messages waiting in the shared IDCMP or AppMessage port */
			MainWindowIDCMP();
			ListWindowIDCMP();
			ConfWindowIDCMP();
		} 

		if (sig & tsig)			/* timer triggered */
		{
			ULONG status, ostatus;
			ULONG track = 0;
			ULONG tracktime = 0;
			ULONG time = 0;

			WaitIO(TimerIO);

			TimerIO->tr_node.io_Command = TR_ADDREQUEST;
			TimerIO->tr_time.tv_secs = 1;
			TimerIO->tr_time.tv_micro = 0;
			SendIO((struct IORequest *) TimerIO);

			GetAttr(CDPANEL_Status, GList[G_Panel], &ostatus);
			status = CD_Snoop(&track, &tracktime, &time, ostatus);

			if ((ostatus == CDP_EMPTY || ostatus == CDP_EJECTED) && status != ostatus)
			{
				/* A CD was just inserted? */
			
				SetGadgetAttrs(GList[G_List], Win, NULL, LISTBROWSER_Labels, ~0, TAG_END);

				FreeBrowserNodes(TrackList);
				
				Tracks = CD_ReadTOC();
				TrackList = BrowserNodesA(TOCS);

				SetGadgetAttrs(GList[G_Panel], Win, NULL,
							   CDPANEL_Status, status,
							   CDPANEL_Artist, TITLE[0],
							   CDPANEL_Title, TITLE[1],
							   CDPANEL_Tracks, Tracks,
							   CDPANEL_TrackTitles, TOCS,
							   CDPANEL_TrackTimes, TOCT,
							   CDPANEL_TotalTime, TOCT[Tracks],
							   TAG_END);
							   
				if (SetGadgetAttrs(GList[G_List], Win, NULL, LISTBROWSER_Labels, TrackList, GA_ReadOnly, FALSE, TAG_END))
					RefreshGList(GList[G_List], Win, NULL, 1);

				UpdateTitleEditor();
			}

			if (track)
			{
				ULONG i;
				
				/* We're apparently playing */

				GetAttr(LISTBROWSER_Selected, GList[G_List], &i);
				if (track - 1 != i)
					SetGadgetAttrs(GList[G_List], Win, NULL, LISTBROWSER_Selected, track - 1, LISTBROWSER_MakeVisible, track - 1, TAG_END);
					
				if (ostatus == CDP_SEEKING)
					status = CDP_SEEKING;

				SetGadgetAttrs(GList[G_Panel], Win, NULL,
							   CDPANEL_Status, status,
							   CDPANEL_Time, time,
							   CDPANEL_Track, track,
							   CDPANEL_TrackTime, tracktime,
							   TAG_END);
							   
				if (!Track) Track = track;
			}

			if (status == CDP_EMPTY || status == CDP_EJECTED)
			{
				SetGadgetAttrs(GList[G_Panel], Win, NULL,
							   CDPANEL_Status, status,
							   TAG_END);
							   
				/* No CD. If it was just removed, expunge the names */

				if (TrackList)
				{
					if (SetGadgetAttrs(GList[G_List], Win, NULL, LISTBROWSER_Labels, &dummyList, GA_ReadOnly, TRUE, TAG_END))
						RefreshGList(GList[G_List], Win, NULL, 1);
					FreeBrowserNodes(TrackList);
					TrackList = NULL;
				}
			}

			if (status == CDP_STOPPED)
			{
				/* CD isn't playing */
			
				SetGadgetAttrs(GList[G_Panel], Win, NULL,
							   CDPANEL_Status, status,
							   TAG_END);
							   
				if (ostatus == CDP_PLAYING || ostatus == CDP_SEEKING)
				{
					if (SetGadgetAttrs(GList[G_List], Win, NULL, LISTBROWSER_Selected, ~0, TAG_END))
						RefreshGList(GList[G_List], Win, NULL, 1);
				}
			}
		}
		
		if (sig & rsig)
		{
			DoMethod( ARexxObj, AM_HANDLEEVENT );
		}
		
		if (sig & SIGBREAKF_CTRL_C)
		{
			done = TRUE;
		}
	}
}

/*************************************************************
 * Initialisation 
 */

#define TEMPLATE "DEVICE/K,UNIT/K/N,PUBSCREEN/K,INDEXPATH/K,XPOS/K/N,YPOS/K/N,TINYFONT/K,PANELFONT/K"
enum { ARG_Device, ARG_Unit, Arg_PubScreen, ARG_IndexPath, ARG_XPos, ARG_YPos, ARG_TinyFont, ARG_PanelFont, ARG_ThrowAway, ARG_MAX };
LONG ArgArray[ARG_MAX+1];

int
main(void)
{
	struct RDArgs *RDArgs;
	
	if (RDArgs = ReadToolArgs( TEMPLATE, ArgArray ))
	{
		Screen = (STRPTR)ArgArray[Arg_PubScreen];
		if (ArgArray[ARG_Device])
		{
			if (AvoidDevice((STRPTR)ArgArray[ARG_Device]))
			{
				ErrorMsg(GS(DEVICE_INCOMPATIBLE), ArgArray[ARG_Device]);
			}
			else
				Device = (STRPTR)ArgArray[ARG_Device];
		}
		if (ArgArray[ARG_Unit])
			Unit = *(ULONG *)ArgArray[ARG_Unit];
		if (ArgArray[ARG_IndexPath])
			IndexPath = (STRPTR)ArgArray[ARG_IndexPath];
		if (ArgArray[ARG_TinyFont])
		{
			/* Fill up the TextAttr for the main windows list/button font */
		
			STRPTR s = (STRPTR)ArgArray[ARG_TinyFont];
			CompactAttr.ta_Name = s;
			while (*s && *s != '/')
				s++;
			if (*s == '/')
			{
				*s++ = 0;
				CompactAttr.ta_YSize = atoi(s);
			}
		}
		if (ArgArray[ARG_PanelFont])
		{
			/* Fill up the TextAttr for the font used in the status panel */
			
			STRPTR s = (STRPTR)ArgArray[ARG_PanelFont];
			PanelAttr.ta_Name = s;
			while (*s && *s != '/')
				s++;
			if (*s == '/')
			{
				*s++ = 0;
				PanelAttr.ta_YSize = atoi(s);
			}
		}

		if (InitARexx() != (APTR)~0)	/* ~0 means already running */
		{
			if ((AppPort = CreateMsgPort()) && (WinPort = CreateMsgPort()))
			{
				if (OpenMainWindow(	ArgArray[ARG_XPos] ? *(ULONG *)ArgArray[ARG_XPos] : 0,
									ArgArray[ARG_YPos] ? *(ULONG *)ArgArray[ARG_YPos] : 4000))
				{
					Init_Device();
			
					MainLoop();
				}
				CloseListWindow();
				CloseConfWindow();
				CloseMainWindow();
			}
			if (AppPort)
				DeleteMsgPort(AppPort);
			if (WinPort)
				DeleteMsgPort(WinPort);
		}

		CloseARexx();

		CD_Close();
		FreeToolArgs(RDArgs);
	}
	return 0;
}
