#include <OSIncludes.h>

#pragma header

#include <stdio.h>
#include <string.h>

#include "misc.h"

/***************************************************/

static char *VERSTRING = "$VER: MCPPReload 0.5 (" __DATE2__ ")";
static char *AUTHSTRING = "$AUTH: Georg Steger";

#define COMPILERFILE "bin/mcpp4"
#define ARG_TEMPLATE "STACK/N/K,MUSTEXIST/S,QUIET/S"

enum {ARG_STACK,ARG_MUSTEXIST,ARG_QUIET,NUM_ARGS};

struct Library *RexxSysBase;
struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;

static struct RDArgs *MyArgs;
static struct MsgPort *replyport;
static struct RexxMsg *rexxmsg;

static LONG Args[NUM_ARGS];
static BPTR lock,olddir,seglist;
static BOOL resetcurrentdir;

static LONG stack = 10000;

static char *rexxcommand = "quit";
static char *compilername = "MaxonCompiler";
static char s[256];


/***************************************************/

static void Cleanup(char *msg)
{
	WORD rc;

	if (msg)
	{
		printf("MCPPReload: %s\n",msg);
		rc = RETURN_WARN;
	} else {
		rc = RETURN_OK;
	}

	if (rexxmsg)
	{
		ClearRexxMsg(rexxmsg,1);
		DeleteRexxMsg(rexxmsg);
	}

	if (resetcurrentdir) CurrentDir(olddir);
	if (lock) UnLock(lock);

	if (MyArgs) FreeArgs(MyArgs);

	if (replyport) DeleteMsgPort(replyport);
	if (RexxSysBase) CloseLibrary(RexxSysBase);	

	exit(rc)
}

static void OpenLibs(void)
{
	if (!(RexxSysBase = OpenLibrary("rexxsyslib.library",0)))
	{
		Cleanup("Can't open rexxsyslib.library!");
	}
}

static void GetArguments(void)
{
	if (!(MyArgs = ReadArgs(ARG_TEMPLATE,Args,0)))
	{
		Fault(IoErr(),0,s,255);
		Cleanup(s);
	}
	
	if (Args[ARG_STACK]) stack = *(LONG *)Args[ARG_STACK];
}

static void Prepare(void)
{
	if (!(lock = Lock("MDEV:",ACCESS_READ)))
	{
		Cleanup("Can't lock \"MDEV:\"!");
	}
	
	olddir = CurrentDir(lock);
	resetcurrentdir = TRUE;

	if (!(replyport = CreateMsgPort()))
	{
		Cleanup("Can't create MsgPort!");
	}

	if (!(rexxmsg = CreateRexxMsg(replyport,0,0)))
	{
		Cleanup("Can't create RexxMsg!");
	}
	
	if (!(rexxmsg->rm_Args[0] = CreateArgstring(rexxcommand,strlen(rexxcommand))))
	{
		Cleanup("Out of memory!");
	}
	
	rexxmsg->rm_Action = RXCOMM | RXFF_NOIO;
}

static void KillCompiler(void)
{
	struct MsgPort *port;

	Forbid();
	if ((port = FindPort("MAXONCPP")))
	{
		PutMsg(port,(struct Message *)rexxmsg);
	}
	Permit();
	
	if (port)
	{
		WaitPort(replyport);
		GetMsg(replyport);
	} else if (Args[ARG_MUSTEXIST]) {
		Cleanup("ARexx port \"MAXONCPP\" not found. Compiler is not running!");
	}
}

static void RestartCompiler(void)
{
	BPTR homelock;

	Delay(50);

	if (!(seglist = NewLoadSeg(COMPILERFILE,0)))
	{
		Cleanup("Can't load compiler!");
	}
	
	if (!(CreateNewProcTags(NP_Seglist,seglist,
									NP_StackSize,stack,
									NP_Arguments,"MAXONDEV.1",
									NP_Cli,TRUE,
									NP_CloseInput,TRUE,
									NP_CloseOutput,TRUE,
									NP_FreeSeglist,TRUE,
									NP_CommandName,compilername,
									NP_Name,compilername,
									NP_HomeDir,homelock = DupLock(lock),
									TAG_DONE)))
	{
		if (homelock) UnLock(homelock);
		UnLoadSeg(seglist);
		
 		Cleanup("Can't restart compiler!");
	}
}

static void ShowSuccess(void)
{
	static char *MESSAGE = "Compiler reloaded!";
	static UWORD pattern[] = {0x5555,0xAAAA};
	
	struct Window *win;
	struct Screen *scr;
	struct DrawInfo *dri;
	struct RastPort *rp,temprp;
	WORD x,y,w,h,a,b;

	if (Args[ARG_QUIET]) return;

	if ((IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",36)))
	{
		if ((GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",36)))
		{
			scr = LockPubScreen("MaxonDevelop.1");
			if (!scr) scr = LockPubScreen(0);
			
			if (scr)
			{
				if ((dri = GetScreenDrawInfo(scr)))
				{
					InitRastPort(&temprp);
					SetFont(&temprp,dri->dri_Font);

					x = TextLength(&temprp,MESSAGE,strlen(MESSAGE));
					y = dri->dri_Font->tf_YSize;
					
					w = x + 16 + 10;
					h = y + 8 + 10;
					
					CalcCenteredWin(scr,w,h,&a,&b);
					
					if ((win = OpenWindowTags(0,WA_PubScreen,scr,
														 WA_Left,a,
														 WA_Top,b,
														 WA_Width,w+5,
														 WA_Height,h+5,
														 WA_Flags,WFLG_BORDERLESS|WFLG_SIMPLE_REFRESH,
														 WA_BackFill,LAYERS_NOBACKFILL,
														 TAG_DONE)))
					{
						rp = win->RPort;
						
						SetFont(rp,dri->dri_Font);
						SetDrMd(rp,JAM1);

						SetAPen(rp,0);
						RectFill(rp,0,0,w-1,h-1);

						SetAPen(rp,dri->dri_Pens[SHADOWPEN]);
						RectFill(rp,w-1,1,w-1,h-1);
						RectFill(rp,1,h-1,w-2,h-1);

						RectFill(rp,5,5,w-6,h-6);

						SetAfPt(rp,pattern,1);
						RectFill(rp,w,4,w+4,h-1);
						RectFill(rp,4,h,w+4,h+4);
						SetAfPt(rp,0,0);
						
						SetAPen(rp,dri->dri_Pens[SHINEPEN]);
						RectFill(rp,0,0,0,h-1);
						RectFill(rp,1,0,w-1,0);
						RectFill(rp,6,h-6,w-6,h-6);
						RectFill(rp,w-6,6,w-6,h-7);
						
						
						SetAPen(rp,dri->dri_Pens[SHINEPEN]);

						Move(rp,(w - x) / 2,(h - y) / 2 + dri->dri_Font->tf_Baseline);
						Text(rp,MESSAGE,strlen(MESSAGE));

						Delay(50*2);
						
						CloseWindow(win);
					} /* if ((win = ... */
					
					FreeScreenDrawInfo(scr,dri);
				} /* if ((dri = GetScreenDrawInfo(scr))) */
				
				UnlockPubScreen(0,scr);
			} /* if (scr) */

			CloseLibrary((struct Library *)GfxBase);
		} /* if ((GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",36))) */

		CloseLibrary((struct Library *)IntuitionBase);
	} /* if ((IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",36))) */
}

void main(void)
{
	OpenLibs();
	GetArguments();
	Prepare();
	KillCompiler();
	RestartCompiler();
	ShowSuccess();
	Cleanup(0);
}	
