/* PowerWindows: Patch.c */

#include <exec/types.h>
#include <exec/ports.h>
#include <exec/interrupts.h>
#include <exec/memory.h>
#include <dos/dos.h>
#include <graphics/gfx.h>
#include <graphics/gfxmacros.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <intuition/imageclass.h>
#include <intuition/gadgetclass.h>
#include <utility/utility.h>
#include <utility/tagitem.h>
#include <libraries/gadtools.h>

#include <devices/input.h>
#include <graphics/layers.h>
#include <graphics/clip.h>
#include <utility/utility.h>
#include <utility/tagitem.h>

#include <pragma/exec_lib.h>
#include <pragma/dos_lib.h>
#include <pragma/intuition_lib.h>
#include <pragma/graphics_lib.h>
#include <pragma/layers_lib.h>
#include <pragma/utility_lib.h>
#include <pragma/gadtools_lib.h>
#include <clib/alib_protos.h>

#pragma header

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "config.h"
#include "PowerWindows.h"
#include "PWDevelopper.h"

static char *DummyReqTitle = " ";

LONG NEW_UpfrontLayer(LONG dummy,struct Layer *lay)
{
	struct ScreenEntry *se;
	struct Layer *targetlayer;
	LONG rc=FALSE;
	
	if (lay)
	{
		
		if ((lay->Flags & LAYERBACKDROP) || (lay->BackFill == &MagicMenuLayerHook))		/* ignore Backdrop-Layers */
		{
			rc=JumpOld_UpfrontLayer(0,lay);
		} else {
			
			ObtainSemaphoreShared(&ScreenListSemaphore);
			if ((se=FindScreen(lay->LayerInfo)))
			{
				LockLayerInfo(lay->LayerInfo);
				targetlayer=se->se_RightLayer->back;
				
				while(targetlayer && (targetlayer != lay))
				{
					if ((targetlayer->BackFill != &IconLayerHook) || (MyConfig.IconDepth!=ID_ALWAYSFRONT))
					{
						UnlockLayerInfo(lay->LayerInfo);
						rc=Jump_MoveLayerInFrontOf(lay,targetlayer);
						ReleaseSemaphore(&ScreenListSemaphore);
						return rc;
					}
					targetlayer=targetlayer->back;
				}
				
				UnlockLayerInfo(lay->LayerInfo);
				/* wenn hier angelant, braucht nichts mehr getan werden! */
				/* oder NEUERDINGS, umschalten auf BehindLayer!! */

				rc=FALSE;

			} else {

				rc=JumpOld_UpfrontLayer(0,lay);
			}

			ReleaseSemaphore(&ScreenListSemaphore);

		}  // if ((lay->Flags & LAYERBACKDROP) || (lay->BackFill == &MagicMenuLayerHook)) else ...

	} // if (lay)

	return rc;
}

void After_OpenScreen(struct Screen *scr)
{
	struct ScreenEntry *se;
	struct TaskEntry *te;
	struct Gadget *gad;
	struct csCheck CheckMsg={CS_CHECK,scr};
	BOOL ok;
		
	ObtainSemaphore(&ScreenListSemaphore);
	ok=!FindScreen(&scr->LayerInfo);		/* already there ? */
	ReleaseSemaphore(&ScreenListSemaphore);
	if (ok)
	{
		if (MyConfig.AnyTasksThere)
		{
			te=CheckTask(0,&TaskList,MyConfig.CaseSensitive);
			{
				if ((te != 0) ^ MyConfig.TaskXOR) ok=FALSE;
			}
		}
	
		if ((*MyConfig.ScreenChecker)((Msg)&CheckMsg)==0) ok=FALSE;
		if (FindTask(0)==MainTask) ok=TRUE;

		if (ok)
		{
			se=AllocVec(sizeof(struct ScreenEntry),MEMF_PUBLIC|MEMF_CLEAR);
			if (se)
			{
				se->se_Screen=scr;
				se->se_NormalWidth=scr->Width;
				se->se_NormalHeight=scr->Height;
				se->se_LayerInfo=&scr->LayerInfo;
				se->se_RightLayer=CreateUpfrontHookLayer(se->se_LayerInfo,scr->RastPort.BitMap,scr->Width,0,16383,16383,LAYERSIMPLE,&SuperLayerHook,0);
				if (!se->se_RightLayer)
				{
					FreeVec(se);
				} else {
					se->se_BottomLayer=CreateUpfrontHookLayer(se->se_LayerInfo,scr->RastPort.BitMap,0,scr->Height,scr->Width-1,16383,LAYERSIMPLE,&SuperLayerHook,0);
					if (!se->se_BottomLayer)
					{
						KillLayer(se->se_RightLayer);
						FreeVec(se);
					} else {

#ifdef ROMHACK
						se->se_TopLayer=CreateUpfrontHookLayer(se->se_LayerInfo,scr->RastPort.BitMap,-16383,-16383,16383,-1,LAYERSIMPLE,&SuperLayerHook,0);
						if (!se->se_TopLayer)
						{
							KillLayer(se->se_RightLayer);
							KillLayer(se->se_BottomLayer);
							FreeVec(se);
						} else {
							se->se_LeftLayer=CreateUpfrontHookLayer(se->se_LayerInfo,scr->RastPort.BitMap,-16383,0,-1,16383,LAYERSIMPLE,&SuperLayerHook,0);
							if (!se->se_LeftLayer)
							{
								KillLayer(se->se_RightLayer);
								KillLayer(se->se_BottomLayer);
								KillLayer(se->se_TopLayer);
								FreeVec(se);
							} else {
#endif
								ObtainSemaphore(&ScreenListSemaphore);
								AddHead(&ScreenList,(struct Node *)se);
								ReleaseSemaphore(&ScreenListSemaphore);

#ifdef ROMHACK
								Forbid();
								se->se_LayerInfo->Flags |= LIF_PATCHED;
								Permit();
#endif

#ifndef ROMHACK
								gad=scr->FirstGadget;
								if (!MyConfig.MultiCX_SM)
								{
									while (gad)
									{
										if ((gad->GadgetType&GTYP_SYSTYPEMASK)==GTYP_SDEPTH)
										{
											Forbid();
											gad->LeftEdge=(scr->Width-gad->Width)+MyConfig.SDepthOffset;
											if (gad->GadgetRender && (gad->Flags&GFLG_GADGIMAGE)) gad->LeftEdge-=((struct Image *)gad->GadgetRender)->LeftEdge;
											gad->Flags&=(~GFLG_RELRIGHT);
											Permit();
											break;
										}
										gad=gad->NextGadget;
									}
								}
#endif

#ifdef ROMHACK							
							} // if (!se->se_LeftLayer) else ...
							
						} // if (!se->se_TopLayer) else ...
#endif
					} // if (!se->se_BottomLayer) else ...

				} // if (!se->se-RightLayer) else ...

			} // if (se)

		} // if (ok)

	} // if (ok)
		
}

void After_OpenWorkBench(struct Screen *scr)
{
	After_OpenScreen(scr);
}

void Before_OpenWindowTagList(struct NewWindow *nw,struct TagItem *taglist)
{
	struct TagItem *tl,*ti;
	WORD i;

	if (MyConfig.SmartWin)
	{

		for (i=1;i<=2;i++)
		{
			tl=0;
			switch(i)
			{
				case 1:
					if (nw)
					{
						if (nw->Flags&WFLG_SIMPLE_REFRESH)
						{
							nw->Flags &= (~WFLG_SIMPLE_REFRESH);
							nw->Flags |= WFLG_SMART_REFRESH;
						}

						if (nw->Flags&WFLG_NW_EXTENDED)
						{
							if ((tl=((struct ExtNewWindow *)nw)->Extension))
							{
								if (ValidTagList(tl)) break;
							}
						}
					} // if (nw)
					tl=0;
					break;
				
				case 2:
					tl=taglist;
					break;

			} // switch(i)
			
			if (tl)
			{					
				if ((ti=FindTagItem(WA_SimpleRefresh,tl)))
				{
					ti->ti_Tag=TAG_IGNORE;
				}
				if ((ti=FindTagItem(WA_Flags,tl)))
				{
					if (ti->ti_Data&WFLG_SIMPLE_REFRESH)
					{
						ti->ti_Data &= (~WFLG_SIMPLE_REFRESH);
						ti->ti_Data |= WFLG_SMART_REFRESH;
					}
				}
			} // if (tl)
			
		} // for (i=1;i<=2;i++)

	}	/* if SmartWin */
	

	if (MyConfig.MagicMenu)
	{
		if (CompareTask("MagicMenu"))
		{
			if ((tl=taglist))
			{
				if ((ti=FindTagItem(WA_BackFill,tl)))
				{
					if (ti->ti_Data == (LONG)LAYERS_NOBACKFILL)
					{
						ti->ti_Data=(LONG)&MagicMenuLayerHook;
					}
				}
			}
		}
	}
	
	if (MyConfig.ForceAutoAdjust)
	{
		if (nw)
		{
			if (nw->LeftEdge<0) nw->LeftEdge=0;
			if (nw->TopEdge<0) nw->TopEdge=0;
		}

		for (i=1;i<=2;i++)
		{
			tl=0;
			switch(i)
			{
				case 1:
					if (nw)
					{
						if (nw->Flags&WFLG_NW_EXTENDED)
						{
							if ((tl=((struct ExtNewWindow *)nw)->Extension))
							{
								if (ValidTagList(tl)) break;
							}
						}
					} // if (nw)
					tl=0;
					break;
				
				case 2:
					tl=taglist;
					break;

			} // switch(i)
			
			if (tl)
			{					
				if ((ti=FindTagItem(WA_Left,tl)))
				{
					if (ti->ti_Data < 0) ti->ti_Data=0;
				}
				if ((ti=FindTagItem(WA_Top,tl)))
				{
					if (ti->ti_Data < 0) ti->ti_Data=0;
				}
			} // if (tl)
			
		} // for (i=1;i<=2;i++)
		
	} /* if (MyConfig.ForceAutoAdjust) */
}

void After_OpenWindowTagList(struct Window *win)	/* Aenderung notwendig wegen Lock/Crash!?!? bei CheckTask?? */
{
	struct Gadget *gad,*gad2;
	struct Image *im=0;
	struct ScreenEntry *se=0;
	struct TaskEntry *te=0;
	struct DrawInfo *di;
	struct cwCheck CheckMsg;

	WORD	leftmost=1,width=0,i,gadpos=0;
	BOOL	IconPos_OK=FALSE;
	
	CheckMsg.MethodID=CW_CHECK;
	CheckMsg.Win=win;
	CheckMsg.Gad_Position=12345;

	ObtainSemaphoreShared(&ScreenListSemaphore);
	
	se=FindScreen(win->WLayer->LayerInfo);

	if ((!se) || (win->BorderTop<10)) goto RealEnde;

	if (MyConfig.AnyIconifyTasksThere)
	{
		te=CheckTask(win,&IconifyTaskList,MyConfig.IconifyCaseSensitive);
	}

	if (
	    (!MyConfig.DoIconify) ||
	    (MyConfig.NoWBWindows && (win->Flags & WFLG_WBENCHWINDOW)) ||
	    ((te != 0) ^ MyConfig.IconifyTaskXOR) ||
		 ((win->Width < MyConfig.MinWinWidth) && ((win->Flags&WFLG_SIZEGADGET)==0))
	   ) goto Ende;
	  
	i=CWR_ICONIFYGAD;
	
	if (MyConfig.WindowChecker_Seg)
	{
		i=(*MyConfig.WindowChecker)((Msg)&CheckMsg);
	}
	if ((i==0) || (!(i&CWR_ICONIFYGAD))) goto Ende;
	
	if (i&CWR_ICONIFYPOS)
	{
		IconPos_OK=TRUE;
	}
	gad=win->FirstGadget;

	i=0;
	while (gad)
	{
		i++;
		if (gad->GadgetType&GTYP_SYSTYPEMASK)
		{
			if (!gadpos) gadpos=i;
		}
		
		if ((gad->TopEdge==0) && (gad->Flags&GFLG_RELRIGHT) && (!(gad->Flags&(GFLG_RELWIDTH|GFLG_RELHEIGHT|GFLG_RELBOTTOM))))
		{
			if (((gad->GadgetType&GTYP_SYSTYPEMASK)==GTYP_WDEPTH) ||
			    ((gad->GadgetType&GTYP_SYSTYPEMASK)==GTYP_WZOOM))
			{
				width=gad->Width;
			}
			if ((gad->LeftEdge<leftmost) && (!IconPos_OK))
			{
				leftmost=gad->LeftEdge;
			}
		}
		gad=gad->NextGadget;
	}

	if ((!width) && (!IconPos_OK))
	{
		width=24;
	}
	
	if (CheckMsg.Gad_Position!=12345) gadpos=CheckMsg.Gad_Position;

	if (MyConfig.IconImageType == ICONIMAGE_VISUALPREFS)
	{
		if ((di=GetScreenDrawInfo(win->WScreen)))
		{
			im=NewObject(0,"tbiclass",
				SYSIA_Which,104,
				SYSIA_DrawInfo,di,
				TAG_DONE);
				
			FreeScreenDrawInfo(win->WScreen,di);
		}
	}
	
	if (!im)
	{
		im=NewObject(MyImageClass,0,SYSIA_Which,IMAGE_ICONIFYGADGET,
										   IA_Left,-1,
											IA_Top,0,
											IA_Width,IconPos_OK ? CheckMsg.Gad_Width: width,
											IA_Height,IconPos_OK ? CheckMsg.Gad_Height : win->BorderTop,
											TAG_DONE);
	}

	if (!im) goto Ende;

	if (!IconPos_OK)	/* auf PowerWindows-Art */
	{
		gad=NewObject(MyButtonClass,0,GA_ID,GADGET_ICONIFY,
											 GA_RelRight,leftmost-im->Width+1,
											 GA_Top,0,
											 GA_Width,im->Width,
											 GA_Height,im->Height,
											 GA_Image,im,
											 GA_RelVerify,TRUE,
//											 GA_TopBorder,TRUE,
											 win->Flags&WFLG_GIMMEZEROZERO ? GA_GZZGadget : TAG_IGNORE,TRUE,
											 CGA_ParentWindow,win,
											 CGA_Task,FindTask(0),
											 TAG_DONE);
	} else {
		gad=NewObject(MyButtonClass,0,GA_ID,GADGET_ICONIFY,
											 (CheckMsg.Gad_Flags&GFLG_RELRIGHT) ? GA_RelRight : GA_Left,CheckMsg.Gad_LeftEdge,
											 (CheckMsg.Gad_Flags&GFLG_RELBOTTOM) ? GA_RelBottom : GA_Top,CheckMsg.Gad_TopEdge,
											 (CheckMsg.Gad_Flags&GFLG_RELWIDTH) ? GA_RelWidth : GA_Width,CheckMsg.Gad_Width,
											 (CheckMsg.Gad_Flags&GFLG_RELHEIGHT) ? GA_RelHeight : GA_Height,CheckMsg.Gad_Height,
											 GA_Image,im,
											 GA_RelVerify,TRUE,
//											 GA_TopBorder,TRUE,
											 win->Flags&WFLG_GIMMEZEROZERO ? GA_GZZGadget : TAG_IGNORE,TRUE,
											 CGA_ParentWindow,win,
											 CGA_Task,FindTask(0),
											 TAG_DONE);
	}
	if (!gad)	/* Koordinaten der Ext. Routine */
	{
		DisposeObject(im);
	} else {
		AddGadget(win,gad,gadpos);
		SetGadgetAttrs(gad,win,0,
			GA_TopBorder,TRUE,
			TAG_DONE);
		RefreshGList(gad,win,0,1);
	}

Ende:
	if (se)
	{
		if ((win->LeftEdge >= se->se_NormalWidth) ||
			 (win->TopEdge >= se->se_NormalHeight))
		{
			width=(se->se_NormalWidth - win->Width)/2;
			i=(se->se_NormalHeight - win->Height)/2;
			
			if (width<0) width=0;
			if (i<0) i=0;
			
			MoveWindow(win,width-win->LeftEdge,i-win->TopEdge);
		}

		if (!MyConfig.NoDGPatch)
		{
			IconPos_OK=TRUE;
			if (te) if (te->te_Flags&TEF_DONTPATCHANYTHING) IconPos_OK=FALSE;

			if (IconPos_OK)
			{
				gad=win->FirstGadget;
				i=0;
				while (gad)
				{
					if ((gad->GadgetType&GTYP_SYSTYPEMASK)==GTYP_WDEPTH)
					{
						if (!IsMyButton(gad) && gad->GadgetRender && (gad->Flags&GFLG_GADGIMAGE))
						{
							gad2=NewObject(MyButtonClass,0,
								GA_ID,GADGET_WINDOWDEPTH,
								GA_RelRight,gad->LeftEdge,
								GA_Top,gad->TopEdge,
								GA_Width,gad->Width,
								GA_Height,gad->Height,
								GA_Image,gad->GadgetRender,
								GA_TopBorder,TRUE,
								win->Flags&WFLG_GIMMEZEROZERO ? GA_GZZGadget : TAG_IGNORE,TRUE,
								GA_RelVerify,TRUE,
								CGA_Task,PATCHEDDEPTHGADGETTASKDUMMY,
								TAG_DONE);
							if (gad2)
							{
								AddGadget(win,gad2,i);
							}
							break;
						}
					}
					gad=gad->NextGadget;i++;
				} // while (gad)
				
			} // if (ok)

		} // if (!MyConfig.NoDGPatch)

	} // if (se)

RealEnde:
	ReleaseSemaphore(&ScreenListSemaphore);

}

void NEW_CloseScreen(struct Screen *scr)
{
	struct ScreenEntry *se;
	
	ObtainSemaphore(&ScreenListSemaphore);
	if ((se=FindScreen(&scr->LayerInfo))) Remove((struct Node *)se);
	ReleaseSemaphore(&ScreenListSemaphore);
	
	if (se)
	{
		RemoveWindows(se);
		KillLayer(se->se_RightLayer);
		KillLayer(se->se_BottomLayer);
		KillLayer(se->se_TopLayer);
		KillLayer(se->se_LeftLayer);
		
#ifdef ROMHACK
		Forbid();
		se->se_LayerInfo->Flags &= (~LIF_PATCHED);
		Permit();
#endif
		
		FreeVec(se);
 	}
}

void NEW_CloseWorkBench(void)
{
	struct Screen *scr;
	
	ObtainSemaphore(&ScreenListSemaphore);
	
	if (WorkbenchOpened())
	{
		if ((scr=LockPubScreen(WORKBENCHNAME)))
		{
			Forbid();
			NEW_CloseScreen(scr);
			UnlockPubScreen(0,scr);
			Permit();
		}
	}
	
	ReleaseSemaphore(&ScreenListSemaphore);
}

void After_CloseWorkBench(void)
{
	struct Screen *scr;

	if (WorkbenchOpened()) // Workbench doch noch da??
	{
		if ((scr=LockPubScreen(WORKBENCHNAME)))
		{
			After_OpenWorkBench(scr);
			ScanWindows(scr);
			UnlockPubScreen(0,scr);
		}
	}
}

void NEW_CloseWindow(struct Window *win)
{
	struct Window *iwin;

	if (win->WLayer->BackFill != &IconLayerHook)		/* must not be Icon-Window */
	{
		while ((iwin=FindIconWindow(win)))
		{
			KillIconWindow(iwin,TRUE);
		}
		KillMyGadgets(win);	
	} else {
		KillIconWindow(win,FALSE);
	}
}

void NEW_FreeSysRequest(struct Window *req)
{
	NEW_CloseWindow(req);
}

void NEW_ActivateWindow(struct Window *win)
{
	struct ActionMsg *MyMsg;
	struct Window *w,*IconWin=0;
	struct Gadget *g;
	WORD	 x1=0,y1=0;
	ULONG l;

	if (MyConfig.WBIconPOP && win && (win->Flags&WFLG_WBENCHWINDOW))
	{
		if (CompareTask(WORKBENCHNAME))
		{
	
			if ((w=FindIconWindow(win)))
			{
				if ((g=FindIconGadget(w)))
				{
					if (GetAttr(CGA_ParentWindow,g,&l))
					{
						if ((struct Window *)l==win)
						{
							IconWin=w;
							l=0;GetAttr(CGA_WindowLeft,g,&l);x1=l;
							l=0;GetAttr(CGA_WindowTop,g,&l);y1=l;
						}
					}
				}
			}
		
			if (IconWin)
			{
				SendActionMsg(MyMsg,win,x1,y1,IconWin,FindScreen(win->WLayer->LayerInfo),AM_MOVEWINDOW);
			}

		} // if (CompareTask(WORKBENCHNAME))

	} // if (MyConfig.WBIconPOP && win && (win->Flags&WFLG_WBENCHWINDOW))
}

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

	if (!MyConfig.DoIconify)
	{
		ret=JumpOld_EasyRequestArgs(window,easystruct,idcmpflags,args);
	} else {
		req=BuildEasyRequestArgs(window,easystruct,idcmpflags ? *idcmpflags : 0,args);
		
		if (!req)
		{
			ret=0;
		} else if (req == (struct Window *)1) {
			ret=1;
		} else {
			while ((ret=SysReqHandler(req,idcmpflags,TRUE))== -2)
			{
			}

			FreeSysRequest(req);
		}
	}
	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 (!MyConfig.DoIconify)
	{
		ret=JumpOld_AutoRequest(window,bodytext,positivetext,negativetext,positiveflags,negativeflags,width,height);
	} else {
		
		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=SysReqHandler(req,&idcmp,TRUE))== -2)
			{
			}
		
			if (ret == -1)
			{
				ret=(idcmp&positiveflags) ? 1 : 0;
			}
			FreeSysRequest(req);
		}
	}
	
	return ret;
}

void NEW_SetWindowTitles(struct Window *win,UBYTE *title)
{
	struct ScreenEntry *se;
	struct MyButtonData *MyData;

	ObtainSemaphoreShared(&ScreenListSemaphore);
	if ((se=FindScreen(win->WLayer->LayerInfo)))
	{
		ObtainSemaphoreShared(&IconListSemaphore);
		MyData=(struct MyButtonData *)IconList.lh_Head;
		while (MyData->node.mln_Succ)
		{
			if (MyData->ParentWindow==win)
			{
				if (!ExtIconRenderer)
				{					
					RefreshIconTitle(MyData->ThisWindow,win->Title);
				} else {
					RefreshIconTitleExt(MyData->ThisWindow,win->Title);
				}
				break;
			}
			MyData=(struct MyButtonData *)MyData->node.mln_Succ;
		}
		ReleaseSemaphore(&IconListSemaphore);
	}
	ReleaseSemaphore(&ScreenListSemaphore);
}

Object *NEW_NewObjectA(struct IClass *cl, char *clid, struct TagItem *taglist)
{
	static char *matchclass = "buttongclass";
	struct TagItem *ti;
	Object *rc;
	BOOL	 goodclass=FALSE;
	
	if (cl)
	{
		if (cl->cl_ID)
		{
			if (strcmp(cl->cl_ID,matchclass)==0) goodclass=TRUE;
		}
	}
	
	if (clid && (!goodclass))
	{
		if (strcmp(clid,matchclass)==0) goodclass=TRUE;
	}
	
	if (goodclass)
	{
		goodclass=FALSE;
		if (taglist)
		{
			if ((ti=FindTagItem(GA_SysGType,taglist)))
			{
				if (ti->ti_Data==GTYP_WDEPTH) goodclass=TRUE;
			}
		}
	}
	
	if (goodclass)
	{
		rc=JumpOld_NewObjectA(MyButtonClass,0,taglist);
	} else {
		rc=JumpOld_NewObjectA(cl,clid,taglist);
	}
	return rc;
}

#ifdef DOROMPATCH
#ifdef ROMHACK

extern "ASM"
{
	void RomPatch(void);
	void RomPatch2(void);
	void RomPatch3(void);
	void RomSearch(void);
	void RomSearch2(void);
	void RomSearch3(void);
	
	UWORD *SearchRom(register __a0 APTR what,register __a1 APTR searchstart,register __a2 APTR searchend,register __d0 ULONG searchsize);
	void CalcROMCheckSum(void);

	UWORD OldROM[],OldROM2[],OldROM3[];
	ULONG RomSearchSize,RomSearch2Size,RomSearch3Size;
};

static UWORD *ROMPOS;
static UWORD *ROMPOS2;
static UWORD *ROMPOS3;

/*
#define ROMPOS (UWORD *)0x68FE6E54
#define ROMPOS2 (UWORD *)0x68FE6FC2
*/

void PatchROM(void)
{
	struct Resident *res;

	UWORD *source=(UWORD *)RomPatch;
	UWORD *dest,*backup=OldROM,w,i;
	
	if (!(res=FindResident("intuition.library"))) Ende("Intuition resident not found!?");
	
	ROMPOS=SearchRom(RomSearch,res,res->rt_EndSkip,RomSearchSize);
	ROMPOS2=SearchRom(RomSearch2,res,res->rt_EndSkip,RomSearch2Size);
	ROMPOS3=SearchRom(RomSearch3,res,res->rt_EndSkip,RomSearch3Size);
	
	if (!ROMPOS || !ROMPOS2 || !ROMPOS3) Ende("Intuition check routines not found!?");

	dest=ROMPOS;

	Disable();
	for (i=0;i<3;i++)
	{
		while ((w = *source++) != 0xAFFE)
		{
			*backup++ = *dest;
			*dest++ = w;
		}
		if (i==0)
		{
			source=(UWORD *)RomPatch2;
			dest=ROMPOS2;
			backup=OldROM2;
		} else if (i==1)
		{
			source=(UWORD *)RomPatch3;
			dest=ROMPOS3;
			backup=OldROM3;
		}
	}
	CalcROMCheckSum();
	Enable();

	CacheClearU();
	
	((struct ExecBase *)SysBase)->KickCheckSum=(APTR)SumKickData();
}

void ResetROM(void)
{
	UWORD *source=OldROM;
	UWORD *dest=ROMPOS,w,i;
	
	Disable();
	for (i=0;i<3;i++)
	{
		while ((w = *source++) != 0xAFFE)
		{
			*dest++ = w;
		}
		if (i==0)
		{
			source=OldROM2;
			dest=ROMPOS2;
		} else if (i==1)
		{
			source=OldROM3;
			dest=ROMPOS3;
		}
	}
	CalcROMCheckSum();
	Enable();
	
	CacheClearU();
	
	((struct ExecBase *)SysBase)->KickCheckSum=(APTR)SumKickData();	
}

#endif
#endif

