/* patch.c */

#include <OSIncludes.h>

#pragma header

#include <ctype.h>
#include "KeyReq.h"

static WORD AllocReqTitle(STRPTR titleset)
{
	WORD i,rc=-1;

	Forbid();
	for (i=0;i<NUM_REQTITLE;i++)
	{
		if (reqtitle[i] == 0)
		{
			reqtitle[i]=titleset;
			rc=i;
			break;
		}
	}
	Permit();
	
	return rc;
}

static LONG MySysReqHandler(struct Window *req,ULONG *idcmpflags,LONG wait)
{
	struct IntuiMessage *msg;
	struct Gadget *igad;
	struct DrawInfo *di;
	struct ReqEntry *re=0;
	ULONG iclass;
	LONG ret=0;
	LONG hcol=1;
	UWORD iquali;
	WORD icode;
	WORD activegad;

	di=GetScreenDrawInfo(req->WScreen);
	
	if (!(re=Find_Requester(req)))
	{
		// this is the first time that MySysReqHandler() has
		// been called for the requester <req>

		Forbid();
		req->Flags&=(~WFLG_NOCAREREFRESH);
		if (!(req->IDCMPFlags&IDCMP_REFRESHWINDOW)) ModifyIDCMP(req,req->IDCMPFlags|IDCMP_REFRESHWINDOW);
		Permit();

		if ((re=Add_Requester(req)))
		{
			if (HCTyp==HCTYP_PEN)
			{
				hcol=di ? di->dri_Pens[HCPen] : 1;
			} else {
				hcol=ObtainBestPen(req->WScreen->ViewPort.ColorMap,
					MakeRGB32(HCRGB>>16),
					MakeRGB32((HCRGB>>8)&0xFF),
					MakeRGB32(HCRGB&0xFF),
					OBP_Precision,PRECISION_EXACT,
					TAG_DONE);
			}
			re->highcol=hcol;
		}

		if (FindGadget(req,1)) activegad=1; else activegad=0;
		HighlightGadget(req,di,activegad,GRMOD_NORMAL,hcol);

	} else {
		// MySysReqHandler() was already called at least
		// once for the requester <req>

		activegad=re->activegad;
		hcol=re->highcol;
	}

	
	ret=-2;
	if (wait) WaitPort(req->UserPort);
	while ((msg=(struct IntuiMessage *)GetMsg(req->UserPort)))
	{
		iclass=msg->Class;
		icode=msg->Code;
		iquali=msg->Qualifier;
		igad=msg->IAddress;
		ReplyMsg((struct Message *)msg);

		switch(iclass)
		{
			case IDCMP_REFRESHWINDOW:
				BeginRefresh(req);
				HighlightGadget(req,di,activegad,GRMOD_NORMAL,hcol);
				EndRefresh(req,TRUE);
				break;

			case IDCMP_GADGETUP:
				ret=igad ? igad->GadgetID : 0;
				break;
			
			case IDCMP_VANILLAKEY:
				// RETURN or RCOMMAND <OK_Key>
				if ((icode==13) || ((toupper(icode)==OK_Key) && ((iquali&IEQUALIFIER_LCOMMAND) || (Flags&PFLG_NOCOMMAND))))
				{
					if (KeyGadget(req,FindGadget(req,activegad),icode))
					{
						ret=activegad;
					}
					
				// ESC or RCOMMAND <CANCEL_Key>
				} else if ((icode==27) || ((toupper(icode)==CANCEL_Key) && ((iquali&IEQUALIFIER_LCOMMAND) || (Flags&PFLG_NOCOMMAND))))
				{
					if (KeyGadget(req,FindGadget(req,0),icode))
					{
						ret=0;							
					}
				
				// TAB
				} else if (icode==9 && (!(Flags&PFLG_NOTAB)))
				{
					icode=activegad+1;
					if (!FindGadget(req,icode)) icode=0;

					if (icode!=activegad && FindGadget(req,icode))
					{
						HighlightGadget(req,di,activegad,GRMOD_BACKFILL,hcol);
						activegad=icode;
						HighlightGadget(req,di,activegad,GRMOD_NORMAL,hcol);
					}
				}
				break;
			
			default:
				// -1 (application supplied custom IDCMP arrived)
				// must not override an already replied requester

				if (ret == -2)
				{
					ret=-1;
					if (idcmpflags) *idcmpflags=iclass;
				}
				break;

		} // switch(iclass)

	} // while ((msg= ...

byebye:
	if (di) FreeScreenDrawInfo(req->WScreen,di);
	if (re) re->activegad=activegad;
	return ret;
}

LONG NEW_EasyRequestArgs(struct Window *window,struct EasyStruct *easystruct,ULONG *idcmpflags,APTR args)
{
	struct Window *req;
	LONG	ret;

	if (idcmpflags)
	if (*idcmpflags & IDCMP_VANILLAKEY)
	{
		ret=JumpOld_EasyRequestArgs(window,easystruct,idcmpflags,args);
		goto byebye;
	}

	req=BuildEasyRequestArgs(window,easystruct,idcmpflags ? *idcmpflags : 0,args);

	if (!req)
	{
		ret=0;
	} else if (req == (struct Window *)1) {
		ret=1;
	} else {
		while ((ret=MySysReqHandler(req,idcmpflags,TRUE)) == -2)
		{
		}
		FreeSysRequest(req);
	}

byebye:
	return ret;
}

LONG NEW_AutoRequest(struct Window *window,struct IntuiText *bodytext, struct IntuiText *positivetext, struct IntuiText *negativetext,ULONG positiveflags,ULONG negativeflags,ULONG width,ULONG height)
{
	struct Window *req;
	ULONG idcmp;
	LONG	ret;
	
	if ((positiveflags&IDCMP_VANILLAKEY) ||
		 (negativeflags&IDCMP_VANILLAKEY))
	{
		ret=JumpOld_AutoRequest(window,bodytext,positivetext,negativetext,positiveflags,negativeflags,width,height);
		goto byebye;
	}
		
	req=BuildSysRequest(window,bodytext,positivetext,negativetext,positiveflags|negativeflags,width,height);
	
	if (!req)
	{
		ret=0;
	} else if (req == (struct Window *)1) {
		ret=1;
	} else {
		while ((ret=MySysReqHandler(req,&idcmp,TRUE)) == -2)
		{
		}
	
		if (ret == -1)
		{
			ret=(idcmp&positiveflags) ? 1 : 0;
		}
		FreeSysRequest(req);
	}

byebye:	
	return ret;
}

struct Window *NEW_BuildEasyRequestArgs(struct Window *win,struct EasyStruct *es,ULONG idcmpflags,APTR args)
{
	struct Window *rc;
	WORD	usedreqtitle=-1;

	if (ReqPos != RPOS_DONTCHANGE)
	{	
		if ((usedreqtitle=AllocReqTitle(es->es_Title)) >= 0)
		{
			es->es_Title=(STRPTR) &(reqtitle[usedreqtitle]);
		}
	}

	rc=JumpOld_BuildEasyRequestArgs(win,es,idcmpflags,args);

	if (usedreqtitle >= 0)
	{
		es->es_Title=reqtitle[usedreqtitle];
		reqtitle[usedreqtitle]=0;
	}

	return rc;
}

LONG NEW_SysReqHandler(struct Window *win,ULONG *idcmpflags,LONG wait)
{
	return MySysReqHandler(win,idcmpflags,wait);
}

void NEW_FreeSysRequest(struct Window *win)
{
	Remove_Requester(Find_Requester(win));
}

struct Window *NEW_OpenWindowTagList(struct NewWindow *nw,struct TagItem *taglist)
{
	struct TagItem newtags[]={WA_AutoAdjust,TRUE,
									  TAG_MORE,(LONG)taglist};

	struct Window *rc;
	struct Screen *scr=0;
	struct TagItem *ti;
	struct Rectangle myrect;
	ULONG displayid;
	WORD	x,y,wx,wy;
	BOOL	 screenlocked=FALSE;

	if (taglist)
	{
		if ((ti=FindTagItem(WA_Title,taglist)))
		{
			// is this a requester?

			for (x=0;x<NUM_REQTITLE;x++)
			{
				if ((STRPTR *)ti->ti_Data == &(reqtitle[x]))
				{
					ti->ti_Data=(LONG)reqtitle[x];
					break;
				}
			}

			if (x<NUM_REQTITLE)
			{
				// find out screen, requester will open on

				if ((ti=FindTagItem(WA_CustomScreen,taglist)))
				{
					scr=(struct Screen *)ti->ti_Data;
				} else if ((ti=FindTagItem(WA_PubScreen,taglist)))
				{
					scr=(struct Screen *)ti->ti_Data;
				} else if ((ti=FindTagItem(WA_PubScreenName,taglist)))
				{
					scr=LockPubScreen((STRPTR)ti->ti_Data);
					if (!scr)
					{
						if (GetTagData(WA_PubScreenFallBack,0,taglist) != 0)
						{
							scr=LockPubScreen(0);
						}
					}
					if (scr) screenlocked=TRUE;
				}

				if (scr && (ReqPos != RPOS_DONTCHANGE))
				{
					// the left/top coordinates will be changed, therefore
					// WA_AutoAdjust will be added to the taglist

					taglist=newtags;

					// calculate visible screen size

					x=scr->Width;
					y=scr->Height;

					if ((displayid=GetVPModeID(&scr->ViewPort)) != INVALID_ID)
					{
						if (QueryOverscan(displayid,&myrect,OSCAN_TEXT))
						{
							x=myrect.MaxX - myrect.MinX + 1;
							y=myrect.MaxY - myrect.MinY + 1;
						}
					}

					// calculate window size

					wx=GetTagData(WA_InnerWidth,1,taglist) + scr->WBorLeft + scr->WBorRight;
					wy=GetTagData(WA_InnerHeight,1,taglist) + scr->WBorTop + scr->Font->ta_YSize + 1 + scr->WBorBottom;

					if (ReqPos == RPOS_CENTER)
					{
						x=(x - wx) / 2;
						y=(y - wy) / 2;
	
						x -= scr->LeftEdge;
						y -= scr->TopEdge;

					} else {
						x=scr->MouseX - (wx / 2);
						y=scr->MouseY - (wy / 2);
					}
					
					if (x<0) x=0;
					if (y<0) y=0;
					
					if ((ti=FindTagItem(WA_Left,taglist)))
					{
						ti->ti_Data=x;
					}
					
					if ((ti=FindTagItem(WA_Top,taglist)))
					{
						ti->ti_Data=y;
					}
					
				} // if (scr)

			} // if (x<NUM_REQTITLE)

		} // if ((ti=FindTagItem(WA_Title, ...
		
	} // if (taglist)
	
	rc=JumpOld_OpenWindowTagList(nw,taglist);

	if (screenlocked && scr) UnlockPubScreen(0,scr);

	return rc;
}

