/* patch.c */

#include <OSIncludes.h>

#pragma header

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

#include "soundmessage.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 WORD AllocSoundMessage(void)
{
	WORD i,rc=-1;

	// a soundmsg is free, when it's ln_Name = 1
		
	Forbid();
	for (i=0;i<NUM_SOUNDMESSAGE;i++)
	{
		if (soundmsg[i].ExecMessage.mn_Node.ln_Name == (char *)1)
		{
			// mark message as used

			soundmsg[i].ExecMessage.mn_Node.ln_Name=(char *)0;
			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;
	BYTE activegad;
	BYTE numgadgets;

	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);
		ModifyIDCMP(req,req->IDCMPFlags|IDCMP_REFRESHWINDOW|IDCMP_RAWKEY);
		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;
			
			numgadgets=0;
			while (FindGadget(req,numgadgets))
			{
				numgadgets++;
			}
			re->numgadgets=numgadgets;
		}

		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>

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

	
	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 (icode >= numgadgets) 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;
			
			case IDCMP_RAWKEY:
				// SHIFT + TAB does not send a IDCMP_VANILLAKEY message :(
				
				if ((icode == 66) && (!(Flags&PFLG_NOTAB)))
				{
					if (iquali & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
					{
						icode=activegad-1;
						if (icode < 0) icode=numgadgets-1;
						
						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;
	struct MsgPort *soundport,*replyport;
	char *taskname;
	WORD	msgid,usedreqtitle=-1,a,b,numgadgets;

	if (Flags&PFLG_SOUNDDAEMON)
	{
		if ((replyport=CreateMsgPort()))
		{
			if ((msgid=AllocSoundMessage()) != -1)
			{
				taskname=GetTaskName();

				numgadgets=1;
				b=strlen(es->es_GadgetFormat);
				for (a=0;a<b;a++)
				{
					if (es->es_GadgetFormat[a] == '|') numgadgets++;
				}

				Forbid();
				if ((soundport=FindPort(SOUNDPORTNAME)))
				{
					soundmsg[msgid].messageType=SND_PLAY;
					soundmsg[msgid].numGadgets=numgadgets;
					soundmsg[msgid].taskName=taskname;
					soundmsg[msgid].requestBody=es->es_TextFormat;
					soundmsg[msgid].requestArgs=args;
	
					soundmsg[msgid].ExecMessage.mn_ReplyPort=replyport;
					PutMsg(soundport,&soundmsg[msgid].ExecMessage);
				}
				Permit();
				
				if (soundport)
				{
					WaitPort(replyport);
					GetMsg(replyport);
				}
				
				// mark soundmsg as free
				soundmsg[msgid].ExecMessage.mn_Node.ln_Name=(char *)1;
	
			} // if ((msgid=AllocSoundMessage()) != -1)
			DeleteMsgPort(replyport);

		} // if ((replyport=CreateMsgPort()))
		
	} // if (Flags&PFLG_SOUNDDAEMON)

	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;
}

void NEW_BuildSysRequest(struct Window *win,struct IntuiText *body,struct IntuiText *pos,struct IntuiText *neg,ULONG flags,LONG width,LONG height)
{
	struct MsgPort *soundport,*replyport;
	char *taskname;
	WORD msgid;
	
	if (Flags&PFLG_SOUNDDAEMON)
	{
		if ((replyport=CreateMsgPort()))
		{
			if ((msgid=AllocSoundMessage()) != -1)
			{
				taskname=GetTaskName();

				Forbid();
				if ((soundport=FindPort(SOUNDPORTNAME)))
				{
					soundmsg[msgid].messageType=SND_PLAY;
					soundmsg[msgid].numGadgets=2;
					soundmsg[msgid].taskName=taskname;
					soundmsg[msgid].requestBody=0;
					soundmsg[msgid].requestArgs=0;

					soundmsg[msgid].ExecMessage.mn_ReplyPort=replyport;
					PutMsg(soundport,&soundmsg[msgid].ExecMessage);
				}
				Permit();
				
				if (soundport)
				{
					WaitPort(replyport);
					GetMsg(replyport);
				}
				
				// mark soundmsg as free
				soundmsg[msgid].ExecMessage.mn_Node.ln_Name=(char *)1;
	
			} // if ((msgid=AllocSoundMessage()) != -1)
			DeleteMsgPort(replyport);

		} // if ((replyport=CreateMsgPort()))
		
	} // if (Flags&PFLG_SOUNDDAEMON)
}

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 TagItem cmtags[]={VTAG_VIEWPORTEXTRA_GET,0,
									 TAG_DONE};
		
	struct Window *rc;
	struct Screen *scr=0;
	struct ViewPortExtra *vpe;
	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
					// (now partly based on Term (from Olaf Barthel) source!!)

					if(!VideoControl(scr->ViewPort.ColorMap,cmtags))
					{
						vpe=(struct ViewPortExtra *)cmtags[0].ti_Data;
					} else {
						vpe=scr->ViewPort.ColorMap->cm_vpe;
						if(!vpe)
						{
							vpe=(struct ViewPortExtra *)GfxLookUp(&scr->ViewPort);
						}
					}

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

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

					}

					// 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;
}

