/**********************************************************************/
/*                    PSX main loop, entrance, etc                    */
/**********************************************************************/

#include "psx.h"
#include <libraries/gadtools.h>
#include <Exec/memory.h>

static struct Remember *ScreenListRemember;
static char OnPubScreenName[MAXPUBSCREENNAME];

struct PubNode
	{
	struct Node Node;
	char Data[1];
	};

char *ScreenNamePointers[255];
ULONG GlobalModes;

void MemCleanup(void) {}

/**********************************************************************/
/*              Build the list of public screens in RAM               */
/**********************************************************************/
void
BuildScreenList(void)
{
struct List *PubList;
struct Node *PubNode;
struct PubNode *Node;
int Num=0;

PubList=LockPubScreenList();

NewList(&ScreenList);
if (ScreenListRemember)
	{
	FreeRemember(&ScreenListRemember, TRUE);
	ScreenListRemember=0;
	}

for (PubNode=PubList->lh_Head; PubNode->ln_Succ; PubNode=PubNode->ln_Succ)
	{
	Node = (struct PubNode *)AllocRemember(&ScreenListRemember, sizeof(struct Node)+strlen(PubNode->ln_Name)+2, MEMF_CLEAR);
	if (Node==0) 
		{
		UnlockPubScreenList();
		exit(160);
		};

	Node->Node.ln_Name = &Node->Data[0];
	ScreenNamePointers[Num++]=&Node->Data[0];
	strcpy(&Node->Data[0], PubNode->ln_Name);

	if (strcmp(ScreenNamePointers[Num-1], CurPubScreenName)==0)
		ListViewTags[9]=Num-1;

	AddTail(&ScreenList, Node);
	}

UnlockPubScreenList();
}


/**********************************************************************/
/* Release any public screen that we've locked to put the window on.  */
/**********************************************************************/
void
ReleasePublicScreen(void)
{
if (Screen)
	{
	UnlockPubScreen(OnPubScreenName, Screen);
	};
}

/**********************************************************************/
/*              Find a public screen for PSX to open on.              */
/**********************************************************************/
void
FindPublicScreen(void)
{
strcpy(OnPubScreenName, CurPubScreenName);
Screen=LockPubScreen(CurPubScreenName);
if (Screen==NULL)
	{
	GetDefaultPubScreen(OnPubScreenName);
	strcpy(CurPubScreenName, OnPubScreenName);
	Screen=LockPubScreen(OnPubScreenName);
	};
}

/**********************************************************************/
/*        Init the PSX Window on the currently selected screen        */
/**********************************************************************/
struct Window *
OpenPSXWindow(void)
{
/** If the CurPubScreenName is Null then open on Workbench **/
ULONG TopBorder;
int WinHeight;

TAttr=Screen->Font;
FontY=TAttr->ta_YSize;
TopBorder=Screen->WBorTop;
VI=(APTR)GetVisualInfoA((struct Screen *)Screen, TAG_DONE);

BuildScreenList();

GadList=NULL;
WinHeight=CreatePSXGadgets(&GadList, VI, TopBorder, TAttr);
if (WinHeight==0)
	exit(150);

Window = OpenWindowTags( NULL,
		WA_Left,	WIN_LEFT,
		WA_Top,		WIN_TOP,
		WA_Width,	WIN_WIDTH,
		WA_Height,	WinHeight,
		WA_IDCMP,  	GADGETUP|CLOSEWINDOW|BUTTONIDCMP|LISTVIEWIDCMP|REFRESHWINDOW,
		WA_Activate,	TRUE,
		WA_CloseGadget,	TRUE,
		WA_DepthGadget,	TRUE,
		WA_DragBar,	TRUE,
		WA_RMBTrap,	TRUE,
		WA_Title,	"PSX Public Screen Tool",
		WA_SimpleRefresh, TRUE,
		WA_PubScreenName, CurPubScreenName,
		TAG_END
		);

if (!Window) return(FALSE);

/** Set screen font **/

TAttr=Screen->Font;
ScreenFont=(struct TextFont *)OpenFont(TAttr);
SetFont(Window->RPort, ScreenFont);

/** Internal size variables **/

ILeft=Window->BorderLeft;
ITop=Window->BorderTop;
IRight=(Window->Width-ILeft)-(Window->BorderRight+1);
IBottom=(Window->Height-ITop)-(Window->BorderBottom+1);
IWidth=IRight-ILeft;
IHeight=ITop-IBottom;

/** GadTools Init **/

AddGList(Window, GadList, -1, -1, NULL);
RefreshGList(GadList, Window, NULL, -1);
GT_RefreshWindow(Window, NULL);

GlobalModes=SetPubScreenModes(0);
SetPubScreenModes(GlobalModes);

GT_SetGadgetAttrs(ShanghaiGad, Window, 0, GTCY_Active, GlobalModes&SHANGHAI?0:1, TAG_DONE);
GT_SetGadgetAttrs(PopGad, Window, 0, GTCY_Active, GlobalModes&POPPUBSCREEN?0:1, TAG_DONE);

return(Window);
}




/**********************************************************************/
/*          Shut down the PSX Window, free anything involved          */
/**********************************************************************/
void
ClosePSXWindow(void)
{
if (Window)
	CloseWindow(Window);
if (VI)
	FreeVisualInfo(VI);
if (GadList)
	FreeGadgets(GadList);

VI=0;
Window=0;
GadList=0;
}




/**********************************************************************/
/*          Cleanup-style exit routine, closes windows, etc           */
/**********************************************************************/
void
ExitRoutine(void)
{
ClosePSXWindow();
ReleasePublicScreen();
if (ScreenListRemember)
	FreeRemember(&ScreenListRemember, TRUE);
ScreenListRemember=0;
CloseLibraries();
}



/**********************************************************************/
/*                         The main PSX Loop                          */
/**********************************************************************/
void
MainLoop(void)
{
int Keepgoing=TRUE;
struct IntuiMessage *Message;
ULONG Class, Code;
struct Screen *ToClose;
int Result;

GetDefaultPubScreen(CurPubScreenName);
FindPublicScreen();

if (OpenPSXWindow()==FALSE)
	exit(101);

SetMessage("PSX V1.0, by Steve Tibbett");

ScreenToFront(Screen);

while (Keepgoing)
	{
	struct Gadget *Gad;
	ULONG GadID;

	Message=(struct IntuiMessage *)GT_GetIMsg(Window->UserPort);
	if (Message==FALSE)
		{
		WaitPort(Window->UserPort);
		continue;
		};

	Class=Message->Class;
	Code=Message->Code;
	Gad=Message->IAddress;
	GadID=Gad->GadgetID;

	GT_ReplyIMsg((struct IntuiMessage *)Message);

	switch (Class)
		{
		case GADGETUP:
			switch (GadID)
				{
				case GADID_OPENSCREEN:
					SetMessage("");
					OpenNewPublicScreen();
					break;

				case GADID_CLOSESCREEN:
					ToClose=LockPubScreen(CurPubScreenName);
					
					if (ToClose==0) 
						{
						SetMessage("Unable to lock screen.");
						break;
						};
					
					if ((ToClose->Flags&SCREENTYPE)==WBENCHSCREEN)
						{
						SetMessage("Cannot close the workbench screen!");
						UnlockPubScreen(CurPubScreenName, ToClose);
						break;
						};

					UnlockPubScreen(CurPubScreenName, ToClose);

					ClosePSXWindow();
					ReleasePublicScreen();

					if (ToClose)
						Result=CloseScreen(ToClose);
						else Result=FALSE;

					FindPublicScreen();
					OpenPSXWindow();
					ScreenToFront(Screen);

					if (Result==FALSE)
						SetMessage("Unable to close screen.");
						else SetMessage("Screen closed.");
					break;	
						
				case GADID_SCREENLIST:
					strcpy(CurPubScreenName, ScreenNamePointers[Code]);
					SetMessage("");
					break;

				case GADID_MOVEPSX:
					ClosePSXWindow();
					ReleasePublicScreen();
					FindPublicScreen();
					OpenPSXWindow();
					ScreenToFront(Screen);
					SetMessage("PSX relocated.");
					break;

				case GADID_QUIT:
					exit(0);
	
				case GADID_MAKEDEFAULT:
					strcpy(MessageText, "'");
					strcat(MessageText, CurPubScreenName);
					strcat(MessageText, "' now the Default Public Screen");
					SetDefaultPubScreen(CurPubScreenName);
					SetMessage(NULL);
					break;
			
				case GADID_REFRESH:
					ListViewTags[1]=-1;
					GT_SetGadgetAttrsA(LVGad, Window, 0, (struct TagItem *)ListViewTags);
					ListViewTags[1]=(ULONG)&ScreenList;
					BuildScreenList();
					GT_SetGadgetAttrsA(LVGad, Window, 0, (struct TagItem *)ListViewTags);
					SetMessage("Screen list refreshed.");
					break;

				case GADID_SHANGHAI:
					if (Code)
						GlobalModes&=~SHANGHAI;
						else GlobalModes|=SHANGHAI;
					SetPubScreenModes(GlobalModes);
					break;

				case GADID_POP:
					if (Code)
						GlobalModes&=~POPPUBSCREEN;
						else GlobalModes|=POPPUBSCREEN;
					SetPubScreenModes(GlobalModes);
					break;
				};
			break;

		case CLOSEWINDOW:
			exit(0);

		case REFRESHWINDOW:
			GT_BeginRefresh(Window);
			GT_EndRefresh(Window, TRUE);
			break;
		default:	
			break;
		};	
	};
}



/**********************************************************************/
/*                 PSX enters and exits through here                  */
/**********************************************************************/
int
main(int argc, char **argv)
{
struct RDArgs *RA;
ULONG Args[12];

if (OpenLibraries(36)==FALSE)
	{
	PutStr("Unable to open 2.0+ libraries.\n");
	CloseLibraries();
	exit(20);
	};

onexit(ExitRoutine);

GlobalModes=SetPubScreenModes(0);
SetPubScreenModes(GlobalModes);
setmem(Args, 10*sizeof(ULONG), 0);

if (argc<2)
	MainLoop();
	else
	{
	RA=ReadArgs("OPEN/K,CLOSE/K,HIRES/S,LACE/S,DEPTH/N,MAKEDEFAULT/S,SHANGHAI/S,NOSHANGHAI/S,POP/S,NOPOP/S,TOFRONT/K,TOBACK/K", &Args[0], NULL);

	if (RA)
		{
		if (Args[0])		// Open
			{
			CLIOpenNewPublicScreen(Args[0], Args[2], Args[3], Args[4], Args[5]);
			};

		if (Args[1])		// Close
			{
			CLIClosePublicScreen(Args[1]);
			};

		if (Args[6])
			GlobalModes|=SHANGHAI;
		if (Args[7])
			GlobalModes&=~SHANGHAI;
		if (Args[8])
			GlobalModes|=POPPUBSCREEN;
		if (Args[9])
			GlobalModes&=~POPPUBSCREEN;		

		if (Args[10])
			{
			struct Screen *Screen=LockPubScreen((char *)Args[10]);
			if (Screen) ScreenToFront(Screen);
			UnlockPubScreen((UBYTE *)Args[10], Screen);
			};

		if (Args[11])
			{
			struct Screen *Screen=LockPubScreen((char *)Args[11]);
			if (Screen) ScreenToBack(Screen);
			UnlockPubScreen((UBYTE *)Args[1], Screen);
			};
		
		SetPubScreenModes(GlobalModes);

		FreeArgs(RA);
		} else PutStr("Bad args.\n");
	};

exit(0);
}
