/* KeyReq by Georg Steger */

#include <OSIncludes.h>

#pragma header

#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#include "soundmessage.h"
#include "KeyReq.h"

#define NumPatches (sizeof(PatchTable)/sizeof(struct PatchEntry))

char *VerString="$VER: KeyReq 0.6 ("__DATE2__")";
char *AuthString="$AUTH: Georg Steger";

struct PatchEntry PatchTable[] =
{
/* 0 */	 {TRUE,LIB_INTUITION,LVO_EasyRequestArgs,New_EasyRequestArgs,Old_EasyRequestArgs},
/* 1 */	 {TRUE,LIB_INTUITION,LVO_AutoRequest,New_AutoRequest,Old_AutoRequest},
/* 2 */	 {TRUE,LIB_INTUITION,LVO_OpenWindowTagList,New_OpenWindowTagList,Old_OpenWindowTagList},
/* 3 */	 {TRUE,LIB_INTUITION,LVO_BuildEasyRequestArgs,New_BuildEasyRequestArgs,Old_BuildEasyRequestArgs},
/* 4 */	 {TRUE,LIB_INTUITION,LVO_SysReqHandler,New_SysReqHandler,Old_SysReqHandler},
/* 5 */	 {TRUE,LIB_INTUITION,LVO_FreeSysRequest,New_FreeSysRequest,Old_FreeSysRequest},
/* 6 */	 {TRUE,LIB_INTUITION,LVO_BuildSysRequest,New_BuildSysRequest,Old_BuildSysRequest}
};

static void Cleanup(WORD rc)
{
	if (ProgPort)
	{
		if (Flags&PFLG_PORTADDED) RemPort(ProgPort);
		DeleteMsgPort(ProgPort);
	}

	if (IntuitionBase) CloseLibrary((struct Library *)IntuitionBase);
	if (GfxBase) CloseLibrary((struct Library *)GfxBase);
	if (KeymapBase) CloseLibrary(KeymapBase);
	if (UtilityBase) CloseLibrary(UtilityBase);

	exit(rc);
}

static void Init(void)
{
	static char *PORTNAME="KeyReq Warp Core";
	struct MsgPort *p;
	WORD i;

	Forbid();
	if ((p=FindPort(PORTNAME)))
	{
		Signal(p->mp_SigTask,SIGBREAKF_CTRL_C);
		Permit();
		Cleanup(RETURN_WARN);
	} else {
		if (!(ProgPort=CreateMsgPort()))
		{
			Permit();
			Cleanup(RETURN_ERROR);
		}
		ProgPort->mp_Node.ln_Name=PORTNAME;
		ProgPort->mp_Node.ln_Pri=-128;
		AddPort(ProgPort);
		Flags|=PFLG_PORTADDED;
	}
	Permit();
	
	InitSemaphore(&ReqSem);
	NewList(&ReqList);

	OK_Key='V';
	CANCEL_Key='B';
	HCPen=SHADOWPEN;
	
	for (i=0;i<NUM_SOUNDMESSAGE;i++)
	{
		// if ln_Name is 1, the message is free to use, otherwise
		// it is actually used by another requester and not yet
		// replied by the sound daemon

		soundmsg[i].ExecMessage.mn_Node.ln_Name=(char *)1;
		soundmsg[i].ExecMessage.mn_Length=sizeof(struct SoundMessage);
	}
}

static void OpenLibs(void)
{
	if (
		 (!(IntuitionBase=(struct IntuitionBase *)OpenLibrary("intuition.library",36))) ||
		 (!(GfxBase=(struct GfxBase *)OpenLibrary("graphics.library",36))) ||
		 (!(KeymapBase=OpenLibrary("keymap.library",36))) ||
		 (!(UtilityBase=OpenLibrary("utility.library",36)))
		) Cleanup(RETURN_ERROR)
}

static void GetArguments(void)
{
	#define ARG_TEMPLATE "OK_KEY/K,CANCEL_KEY/K,HIGHLIGHTCOL/N/K,HIGHLIGHTRGB/K,CENTERREQ/S,MOUSEREQ/S,NOHIGHLIGHT/S,NOTAB/S,NOCOMMAND/S,NOKEYGADGET/S,NOBUILDREQ/S,SOUNDDAEMON/S"

	enum
	{
		ARG_OK_KEY,
		ARG_CANCEL_KEY,
		ARG_HIGHLIGHTCOL,
		ARG_HIGHLIGHTRGB,
		ARG_CENTERREQ,
		ARG_MOUSEREQ,
		ARG_NOHIGHLIGHT,
		ARG_NOTAB,
		ARG_NOCOMMAND,
		ARG_NOKEYGADGET,
		ARG_NOBUILDREQ,
		ARG_SOUNDDAEMON,
		NUM_ARGS,
	};
	
	struct RDArgs *MyArgs;
	LONG	 Args[NUM_ARGS]={0};

	if (!(MyArgs=ReadArgs(ARG_TEMPLATE,Args,0)))
	{
		PrintFault(IoErr(),"KeyReq");
		Cleanup(RETURN_ERROR);
	}
	
	if (Args[ARG_OK_KEY]) OK_Key=toupper(*(char *)Args[ARG_OK_KEY]);
	if (Args[ARG_CANCEL_KEY]) CANCEL_Key=toupper(*(char *)Args[ARG_CANCEL_KEY]);

	if (Args[ARG_HIGHLIGHTCOL]) HCPen=*(LONG *)Args[ARG_HIGHLIGHTCOL];
	if (Args[ARG_HIGHLIGHTRGB] && (((struct ExecBase *)SysBase)->LibNode.lib_Version>=39))
	{
		HCTyp=HCTYP_RGB;
		HCRGB=strtol((char *)Args[ARG_HIGHLIGHTRGB],0,0);
	}
	
	if (Args[ARG_CENTERREQ]) ReqPos=RPOS_CENTER;
	if (Args[ARG_MOUSEREQ]) ReqPos=RPOS_MOUSE;

	if (Args[ARG_NOHIGHLIGHT]) Flags|=PFLG_NOHIGHLIGHT;
	if (Args[ARG_NOTAB]) Flags|=PFLG_NOTAB;
	if (Args[ARG_NOCOMMAND]) Flags|=PFLG_NOCOMMAND;
	if (Args[ARG_NOKEYGADGET]) Flags|=PFLG_NOKEYGADGET;
	if (Args[ARG_NOBUILDREQ]) PatchTable[4].DoPatch=FALSE;
	
	if (Args[ARG_SOUNDDAEMON])
	{
		strncpy(SOUNDPORTNAME,"CoolSound",30);
		Flags |= PFLG_SOUNDDAEMON;
	}

	if (Flags&PFLG_NOHIGHLIGHT) Flags|=PFLG_NOTAB;

	FreeArgs(MyArgs);
}

static void DoPatches(void)
{
	WORD i;
	
	Disable();
	for (i=0;i<NumPatches;i++)
	{
		if (PatchTable[i].DoPatch)
		{
			PatchTable[i].OldFunction=SetFunction((struct Library *)IntuitionBase,PatchTable[i].LVO,PatchTable[i].NewFunction);
		}
	}
	Enable();
}

static BOOL RemovePatches(void)
{
	WORD i,i2;
	APTR oldfunc[NumPatches];
	BOOL rc=TRUE;

	Disable();
	for (i=0;i<NumPatches;i++)
	{
		if (PatchTable[i].DoPatch)
		{
			oldfunc[i]=SetFunction((struct Library *)IntuitionBase,PatchTable[i].LVO,PatchTable[i].OldFunction);

			if (oldfunc[i]!=PatchTable[i].NewFunction)
			{
				for (i2=0;i2<=i;i2++)
				{
					if (PatchTable[i2].DoPatch) SetFunction((struct Library *)IntuitionBase,PatchTable[i2].LVO,oldfunc[i2]);
				}
				rc=FALSE;
				break;
			}
		}
	}
	Enable();

	return rc;
}

static void HandleAll(void)
{
	for (;;)
	{
		Wait(SIGBREAKF_CTRL_C);
		if (OutOfAction() && RemovePatches())
		{
			break;
		} else {
			DisplayBeep(IntuitionBase->ActiveScreen);
		}
	}
}

void main(void)
{
	Init();
	OpenLibs();
	GetArguments();
	DoPatches();
	HandleAll();
	Cleanup(RETURN_OK);
}

