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

/********************************************************
 * Main GUI
 */

#define CDPanelObject   NewObject( CDPanelClass, NULL /* ) open parentheses annoy */

struct Gadget *GList[G_MAX+1];

struct Screen *Scr;
struct DrawInfo *Dri;
struct Window *Win;
Object *WinObj;
struct Gadget *MainLayout;
STRPTR Screen;

static UWORD chip forwardData[26] =
{
    /* Plane 0 */
    0x0000,0x0000,0x0000,0x0000,0x0410,0x0000,0x0618,0x0000,
    0x071C,0x0000,0x079E,0x0000,0x07DF,0x0000,0x079E,0x0000,
    0x071C,0x0000,0x0618,0x0000,0x0410,0x0000,0x0000,0x0000,
    0x0000,0x0000
};

static struct Image ForwardButton =
{
    0, 0,       /* LeftEdge, TopEdge */
    20, 13, 1,  /* Width, Height, Depth */
    forwardData,    /* ImageData */
    0x0001, 0x0000, /* PlanePick, PlaneOnOff */
    NULL        /* NextImage */
};

static UWORD chip playData[26] =
{
    /* Plane 0 */
    0x0000,0x0000,0x0000,0x0000,0x1003,0xDE00,0x1C03,0xDE00,
    0x1F03,0xDE00,0x1FC3,0xDE00,0x1FF3,0xDE00,0x1FC3,0xDE00,
    0x1F03,0xDE00,0x1C03,0xDE00,0x1003,0xDE00,0x0000,0x0000,
    0x0000,0x0000
};

static struct Image PlayButton =
{
    0, 0,       /* LeftEdge, TopEdge */
    26, 13, 1,  /* Width, Height, Depth */
    playData,   /* ImageData */
    0x0001, 0x0000, /* PlanePick, PlaneOnOff */
    NULL        /* NextImage */
};

static UWORD chip rewindData[26] =
{
    /* Plane 0 */
    0x0000,0x0000,0x0000,0x0000,0x0082,0x0000,0x0186,0x0000,
    0x038E,0x0000,0x079E,0x0000,0x0FBE,0x0000,0x079E,0x0000,
    0x038E,0x0000,0x0186,0x0000,0x0082,0x0000,0x0000,0x0000,
    0x0000,0x0000
};

static struct Image RewindButton =
{
    0, 0,       /* LeftEdge, TopEdge */
    20, 13, 1,  /* Width, Height, Depth */
    rewindData, /* ImageData */
    0x0001, 0x0000, /* PlanePick, PlaneOnOff */
    NULL        /* NextImage */
};

static UWORD chip stopData[26] =
{
    /* Plane 0 */
    0x0000,0x0000,0x0000,0x0000,0x1FF0,0x2000,0x1FF0,0x7000,
    0x1FF0,0xF800,0x1FF1,0xFC00,0x1FF3,0xFE00,0x1FF0,0x0000,
    0x1FF3,0xFE00,0x1FF3,0xFE00,0x1FF3,0xFE00,0x0000,0x0000,
    0x0000,0x0000
};

static struct Image StopButton =
{
    0, 0,       /* LeftEdge, TopEdge */
    26, 13, 1,  /* Width, Height, Depth */
    stopData,   /* ImageData */
    0x0001, 0x0000, /* PlanePick, PlaneOnOff */
    NULL        /* NextImage */
};

struct TextAttr CompactAttr = { NULL, 0, FS_NORMAL, FPF_PROPORTIONAL };
struct TextAttr PanelAttr = { NULL, 0, FS_NORMAL, 0L };
struct TextFont *CompactFont;
struct TextFont *PanelFont;
struct TextFont *ScreenFont;

struct List dummyList;

/* handler functions for the buttons, since I want to act on them from
 * rawkey messages too. Gadgets don't support rawkey command keys (as of yet
 * anyway) because it is generally a bad practise to bind a rawkey to a gadget. */
static void
SeekCD(ULONG id)
{
  /* notifications from the rewind/fast forward buttons */
	ULONG status;
	static struct timeval tv1, tv2, tv3;

	GetSysTime(&tv1);
	tv3 = tv1;
	SubTime(&tv3, &tv2);
	
	SafeGetAttr(CDPANEL_Status, GList[G_Panel], &status);

	if ((status == CDP_PLAYING || status == CDP_SEEKING)
		&& (tv3.tv_secs || tv3.tv_micro >= 190000))
	{
		tv2 = tv1;					   /* only seek four times per second */
		switch (id)
		 {
		 case G_Backward:
			 CD_Seek(-2);
			 break;

		 case G_Forward:
			 CD_Seek(2);
			 break;
		 }
		if (status == CDP_PLAYING)
			SafeSetGadgetAttrs(GList[G_Panel], Win, NULL, CDPANEL_Status, CDP_SEEKING, TAG_END);
	}
}

static void
PlayCD(void)
{
	ULONG status;

	SafeGetAttr(CDPANEL_Status, GList[G_Panel], &status);

	if (status == CDP_PLAYING || status == CDP_SEEKING)
	{
		SafeSetGadgetAttrs(GList[G_Panel], Win, NULL, CDPANEL_Status, CDP_PAUSED, TAG_END);
		CD_PauseResume(0x00);
	}
	else if (status == CDP_PAUSED)
	{
		SafeSetGadgetAttrs(GList[G_Panel], Win, NULL, CDPANEL_Status, CDP_PLAYING, TAG_END);
		CD_PauseResume(0x01);
	}
	else if (status == CDP_STOPPED)
	{
		ULONG track;

		SafeSetGadgetAttrs(GList[G_Panel], Win, NULL, CDPANEL_Status, CDP_PLAYING, TAG_END);
		SafeGetAttr(LISTBROWSER_Selected, GList[G_List], &track);
		if (track++ > 100)
			track = 1;
		CD_Play(track);
		AbortIO(TimerIO);
	}
	else if (status == CDP_EJECTED || status == CDP_EMPTY)
	{
		CD_Eject(0x00);
		Delay(20);					   /* give it a chance to settle. I really hate these kind of things */
		if (Tracks = CD_ReadTOC())
			CD_Play(1);
	}
}

static void
StopCD(void)
{
	ULONG status;

	SafeGetAttr(CDPANEL_Status, GList[G_Panel], &status);
	
	JustStarted = FALSE;

	if (status == CDP_STOPPED || status == CDP_EMPTY || status == CDP_EJECTED)
	{
		SafeSetGadgetAttrs(GList[G_Panel], Win, NULL, CDPANEL_Status, CDP_EJECTED, TAG_END);
		CD_Eject(0x01);
	}
	else
	{
		SafeSetGadgetAttrs(GList[G_List], Win, NULL, LISTBROWSER_Selected, ~0, TAG_END);
		SafeSetGadgetAttrs(GList[G_Panel], Win, NULL, CDPANEL_Status, CDP_STOPPED, TAG_END);
		CD_Stop();
		AbortIO(TimerIO);
	}
}

static void
SelectCD(LONG dir)
{
	LONG track;
	ULONG status;

	SafeGetAttr(LISTBROWSER_Selected, GList[G_List], (ULONG *) & track);
	if (dir > 0)
	{
		 if (track < 100)
		 {
			 track++;
			 if (track >= Tracks)
				 track = Tracks - 1;
		 }
		 else
			 track = 0;
	}
	else
	{
		if (track > 100)
			track = Tracks;
		track--;
		if (track < 0)
			track = 0;
	}
	SafeSetGadgetAttrs(GList[G_List], Win, NULL, LISTBROWSER_Selected, track, LISTBROWSER_MakeVisible, track, TAG_END);

	SafeGetAttr(CDPANEL_Status, GList[G_Panel], &status);
	
	if (status == CDP_PLAYING || status == CDP_SEEKING)
	{
		 CD_Play(track+1);
		 AbortIO(TimerIO);
	}
}

static struct Hook IDCMPHook;

static ULONG __asm __saveds
IDCMPHookFunc(register __a0 struct Hook * hook, register __a2 Object * WinObj, register __a1 struct IntuiMessage *msg)
{
	/* this function is hooked from windowclass to grab some IDCMP messages */

	switch (msg->Class)
	{
	case IDCMP_IDCMPUPDATE:
	{
		ULONG id = GetTagData(GA_ID, 0, msg->IAddress);
		
		if (FindTagItem(GA_Selected, msg->IAddress) && (id == G_Backward || id == G_Forward))
		{
			SeekCD(id);
		}
		break;
	}
	
	case IDCMP_RAWKEY:
		switch (msg->Code)
		{
		case 0x43:	/* enter */
		case 0x44:	/* return */
			if (!(msg->Qualifier & IEQUALIFIER_REPEAT))
				StopCD();
			break;
			
		case 0x40:	/* space */
			if (!(msg->Qualifier & IEQUALIFIER_REPEAT))
				PlayCD();
			break;
			
		case 0x4f:	/* cursor left */
			SeekCD(G_Backward);
			break;
			
		case 0xcf:	/* cursor left (keyup)*/
			SafeSetGadgetAttrs(GList[G_Panel], Win, NULL, CDPANEL_Status, CDP_PLAYING, TAG_END);
			break;
			
		case 0x4e:	/* cursor right */
			SeekCD(G_Forward);
			break;
			
		case 0xce:	/* cursor right (keyup) */
			SafeSetGadgetAttrs(GList[G_Panel], Win, NULL, CDPANEL_Status, CDP_PLAYING, TAG_END);
			break;
			
		case 0x4c:	/* cursor up */
			SelectCD(-1);
			break;
			
		case 0x4d:	/* cursor down */
			SelectCD(+1);
			break;
		}
		break;
	}
	return 0;
}

struct Window *
OpenMainWindow(ULONG X, ULONG Y)
{
    if (!ButtonBase) /* force it open */
        return NULL;

    if (Win)
        return Win;

    NewList( &dummyList );

    if (!(Scr = LockPubScreen(Screen)))
        Scr = LockPubScreen(NULL);

    if (Scr)
    {
        ScreenFont = OpenFont(Scr->Font);

        if (!CompactAttr.ta_Name)
        {
            CompactAttr = *Scr->Font;
        }
        if (!PanelAttr.ta_Name)
        {
            PanelAttr.ta_Name = GfxBase->DefaultFont->tf_Message.mn_Node.ln_Name;
            PanelAttr.ta_YSize = GfxBase->DefaultFont->tf_YSize;
        }

        if ((CompactFont = OpenDiskFont( &CompactAttr )) && (PanelFont = OpenDiskFont( &PanelAttr )))
        {
            if (Dri = GetScreenDrawInfo(Scr))
            {
            	struct Image *i;
            
                MainLayout = HGroupObject, Offset(1,1,1,1), Spacing(1),
                    GA_TextAttr, & CompactAttr,
                    GA_DrawInfo, Dri,
                    LAYOUT_AddChild, VGroupObject, Spacing(1),
                    
                    	/* Layout hierarchies are so hard to explain.. we have the
                    	 * window split to the status panel side and the listview side,
                    	 * with four buttons below the status panel. */

                        StartMember, GList[G_Panel] = CDPanelObject,
                            CDPANEL_Status, CDP_EMPTY,
                            GA_TextAttr, & PanelAttr,
                            End,

                        StartHGroup, 
                        	LAYOUT_SpaceInner, FALSE,

                            StartMember, GList[G_Backward] = ButtonObject,
                                GA_Image, i = & RewindButton,
                                GA_RelVerify, TRUE,
                                GA_ID, G_Backward,
                                ICA_TARGET, ICTARGET_IDCMP,
                                BUTTON_FillPen, Dri->dri_Pens[BACKGROUNDPEN],
                                End,
                                CHILD_MinWidth, i->Width,
	                        	CHILD_WeightMinimum, TRUE,

                            StartMember, GList[G_Play] = ButtonObject,
                                GA_Image, i = & PlayButton,
                                GA_RelVerify, TRUE,
                                GA_ID, G_Play,
                                BUTTON_FillPen, Dri->dri_Pens[BACKGROUNDPEN],
                                End,
                                CHILD_MinWidth, i->Width,
	                        	CHILD_WeightMinimum, TRUE,

                            StartMember, GList[G_Forward] = ButtonObject,
                                GA_Image, i = & ForwardButton,
                                GA_RelVerify, TRUE,
                                GA_ID, G_Forward,
                                ICA_TARGET, ICTARGET_IDCMP,
                                BUTTON_FillPen, Dri->dri_Pens[BACKGROUNDPEN],
                                End,
                                CHILD_MinWidth, i->Width,
	                        	CHILD_WeightMinimum, TRUE,

                            StartMember, GList[G_Stop] = ButtonObject,
                                GA_Image, i = & StopButton,
                                GA_RelVerify, TRUE,
                                GA_ID, G_Stop,
                                BUTTON_FillPen, Dri->dri_Pens[BACKGROUNDPEN],
                                End,
                                CHILD_MinWidth, i->Width,
	                        	CHILD_WeightMinimum, TRUE,
                            End,
                            CHILD_WeightedHeight, 0,
                        End,

                    StartVGroup, Spacing(1),
                    
                    	/* This is the listview group, with two buttons above it */
                    
                        StartHGroup, Spacing(1),
                            LAYOUT_EvenSize, TRUE,

                            StartMember, GList[G_Titles] = ButtonObject,
                                GA_Text, "_TITLES",
                                GA_TextAttr, & CompactAttr,
                                GA_RelVerify, TRUE,
                                GA_ID, G_Titles,
                                End,

                            StartMember, GList[G_Program] = ButtonObject,
                                GA_Text, "_PROGR",
                                GA_TextAttr, & CompactAttr,
                                GA_RelVerify, TRUE,
                                GA_ID, G_Program,
                                End,
                            End,
                            CHILD_WeightedHeight, 0,

                        StartMember, GList[G_List] = ListBrowserObject,
                            LISTBROWSER_Labels, &dummyList,
                            LISTBROWSER_VerticalProp, FALSE,
                            LISTBROWSER_ShowSelected, TRUE,
                            GA_ReadOnly, TRUE,
                            GA_TextAttr, & CompactAttr,
                            GA_RelVerify, TRUE,
                            GA_ID, G_List,
                            End,
                        End,
                    End;

                if (MainLayout)
                {
	            	IDCMPHook.h_Entry = (HOOKFUNC)IDCMPHookFunc;
    	        	IDCMPHook.h_SubEntry = NULL;
        	    	IDCMPHook.h_Data = NULL;
            
                    if (WinObj = WindowObject,
                            WA_DepthGadget,		TRUE,
                            WA_DragBar,			TRUE,
                            WA_CloseGadget,		TRUE,
                            WA_Activate,		TRUE,
                            WA_Top,             Y,
                            WA_Left,            X,
                            WA_PubScreen,       Scr,
                            WA_Title,           "CompactPlayer",
                            WA_ScreenTitle,     "CompactPlayer Copyright 1995 Osma Ahvenlampi",
                            WA_AutoAdjust,      TRUE,
                            WINDOW_Layout, 		MainLayout,
                            WINDOW_IDCMPHook,	&IDCMPHook,
                            WINDOW_IDCMPHookBits, IDCMP_IDCMPUPDATE | IDCMP_RAWKEY,
                    		WA_IDCMP,			IDCMP_IDCMPUPDATE | IDCMP_RAWKEY,
                            TAG_END))
                    {
						Win = CA_OpenWindow(WinObj);
						
                        return Win;
                    }
                    DisposeObject(MainLayout);
                    MainLayout = NULL;
                }
	            ErrorMsg("Failed to create GUI");
            }
        }
        else
            ErrorMsg("Failed to open fonts");
    }
    return NULL;
}

void
CloseMainWindow(void)
{
    if (TrackList)
    {
        SafeSetGadgetAttrs(GList[G_List], Win, NULL, LISTBROWSER_Labels, ~0, TAG_END);
        FreeBrowserNodes(TrackList);
        TrackList = NULL;
    }
    if (WinObj)
    {
        DisposeObject(WinObj);
        MainLayout = NULL;
        WinObj = NULL;
        Win = NULL;
        memset(&GList[G_Panel], 0, &GList[G_Artist]-&GList[G_Panel]);
    }
    if (Dri)
    {
        FreeScreenDrawInfo(Scr, Dri);
        Dri = NULL;
    }
    if (Scr)
    {
        UnlockPubScreen(0, Scr);
        Scr = NULL;
    }
    if (CompactFont)
    {
        CloseFont(CompactFont);
        CompactFont = NULL;
    }
    if (PanelFont)
    {
        CloseFont(PanelFont);
        PanelFont = NULL;
    }
    if (ScreenFont)
    {
        CloseFont(ScreenFont);
        ScreenFont = NULL;
    }
}

void
MainWindowIDCMP()
{
	ULONG code = 0, result;

	while ((result = CA_HandleInput(WinObj, &code)) != WMHI_LASTMSG)
	{
		/* Windowclass translates key events to GADGETUPs on its own */
	
		switch (result & WMHI_CLASSMASK)
		{
		 case WMHI_CLOSEWINDOW:
			 done = TRUE;
			 break;
			 
		 case WMHI_GADGETUP:
			switch (result & WMHI_GADGETMASK)
			 {
			 case G_Backward:
				 {
					 ULONG status;
					 
					 /* only do this if not playing. During playing do a continous
					  * seek by listening to the IDCMP messages */

					 SafeGetAttr(CDPANEL_Status, GList[G_Panel], &status);

					 if (status == CDP_STOPPED)
					 {
					 	SelectCD(-1);
					 }
					 else if (status == CDP_SEEKING)
						SafeSetGadgetAttrs(GList[G_Panel], Win, NULL, CDPANEL_Status, CDP_PLAYING, TAG_END);
				 }
				 break;

			 case G_Play:
			 	 PlayCD(); /* see earlier in this file */
				 break;

			 case G_Forward:
				 {
					 ULONG status;
					 
					 /* As with G_Backward */

					 SafeGetAttr(CDPANEL_Status, GList[G_Panel], &status);

					 if (status == CDP_STOPPED)
					 {
					 	SelectCD(+1);
					 }
					 else if (status == CDP_SEEKING)
						 SafeSetGadgetAttrs(GList[G_Panel], Win, NULL, CDPANEL_Status, CDP_PLAYING, TAG_END);
				 }
				 break;

			 case G_Stop:
			 	 StopCD(); /* see earlier */
				 break;

			 case G_Titles:
				 {
					 ULONG status;
					 
					 /* open up the list list editor */

					 OpenListWindow(Win->LeftEdge + Win->Width, Win->TopEdge);

					 SafeGetAttr(CDPANEL_Status, GList[G_Panel], &status);

					 if (status != CDP_EJECTED && status != CDP_EMPTY)
					 {
						 UpdateTitleEditor();
					 }
				 }
				 break;

			 case G_Program:
			 	/* program editor unimplemented */
				 break;

			 case G_List:
			 	/* user selected a track in the listview, jump to it and play */
				 CD_Play(code + 1);
				 AbortIO(TimerIO);
				 break;
			 }
		}
	}
}
