/*****************************************************************************
;  :Module.		winmem.c
;  :Author.		Bert Jahn
;  :EMail.		wepl@whdload.org
;  :Address.	Franz-Liszt-Straße 16, Rudolstadt, 07404, Germany
;  :Version.	$Id: winmem.c 1.1 2000/03/22 18:48:14 jah Exp $
;  :History.	21.03.00 separated from main
;  :Copyright.	All Rights Reserved
;  :Language.	C
;  :Tabsize.	4
;  :Translator.	SAS 6.58
****************************************************************************/

#include <string.h>

#include <exec/execbase.h>

#include <clib/alib_protos.h>
#include <clib/muimaster_protos.h>
#include <clib/utility_protos.h>

#include <pragmas/muimaster_pragmas.h>

#include <mui/HexEdit_mcc.h>

#include "whddump.h"
#include "WHDLoadGCI.h"

/****************************************************************************/
/* Compiler Stuff                                                           */
/****************************************************************************/

#define REG(x) register __ ## x
#define ASM    __asm
#define SAVEDS __saveds

/****************************************************************************/
/* defines																	*/
/****************************************************************************/

#define MAXWINMEM 10		/* amount of possible memory hexdump windows */

/****************************************************************************/
/* extern variables															*/
/****************************************************************************/

extern APTR						app,win;
extern struct whddump_header	*header;
extern struct NewMenu			MenuData1[];
extern struct Library			*MUIMasterBase;

extern APTR						mem,emem,slave;

/****************************************************************************/
/* static variables															*/
/****************************************************************************/

APTR win_mem[MAXWINMEM];	/* memory hexdump windows */

static struct MUI_CustomClass *HexClass;

void *	winmem_init		(void);
void	winmem_finit	(void);

/****************************************************************************/
/* function declarations													*/
/****************************************************************************/

void *	winmem_init		(void);
void	winmem_finit	(void);

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

struct HexData {
	int low_bound;
	int high_bound;
	int base_address;
	int len_base;
	int len_off;
};

SAVEDS ULONG
mNew(
	struct IClass *cl,
	Object *obj,
	Msg msg
) {
	struct TagItem *tags,*tag;
	int i;
	struct HexData tmp = {0,0,0,0,0};

	for (tags=((struct opSet *)msg)->ops_AttrList;tag=NextTagItem(&tags);)
	{
		switch (tag->ti_Tag)
		{
			case MUIA_HexEdit_LowBound: tmp.low_bound = tag->ti_Data; break;
			case MUIA_HexEdit_HighBound: tmp.high_bound = tag->ti_Data; break;
			case MUIA_HexEdit_BaseAddressOffset: tmp.base_address = tag->ti_Data; break;
			case MUIA_HexEdit_AddressChars:
				i = tmp.high_bound + tmp.base_address;
				tmp.len_base =	i < 0x10000 ? 4 :
								i < 0x100000 ? 5 :
								i < 0x1000000 ? 6 :
								i < 0x10000000 ? 7 : 8;
				if (tmp.low_bound + tmp.base_address) {
					i = tmp.high_bound - tmp.low_bound;
					tmp.len_off =	i < 0x1000 ? 3 :
									i < 0x10000 ? 4 :
									i < 0x100000 ? 5 : 6;
				} else {
					tmp.len_off = 0;
				}
				tag->ti_Data = tmp.len_base + (tmp.len_off ? 1 + tmp.len_off : 0);
				break;
		}
	}

	if (!(obj = (Object *)DoSuperMethodA(cl,obj,msg))) return(0);

	memcpy(INST_DATA(cl,obj), &tmp, sizeof(tmp));

	return ((ULONG)obj);
}

SAVEDS ULONG
mCreateDisplayAddress(
	struct IClass *cl,
	Object *obj,
	struct MUIP_HexEdit_CreateDisplayAddress *msg
) {
	struct HexData *d = INST_DATA(cl,obj);
	ULONG address;
	UBYTE i;
	UBYTE *hextable = "0123456789ABCDEF";

	address = (d->base_address + msg->address) << (32 - d->len_base * 4);
	for(i = 0; i < d->len_base; i++)
	{
		*(*msg->cp)++ = hextable[address >> (32 - 4)];
		address <<= 4;
	}

	address = (msg->address - d->low_bound) << (32 - d->len_off * 4);
	if (d->len_off) {
		*(*msg->cp)++ = (unsigned char) '·';
		for(i = 0; i < d->len_off; i++)
		{
			*(*msg->cp)++ = hextable[address >> (32 - 4)];
			address <<= 4;
		}
	}

	return(TRUE);
}

SAVEDS ASM ULONG
HexDispatcher(
	REG(a0) struct IClass *cl,
	REG(a2) Object *obj,
	REG(a1) Msg msg
) {
	switch (msg->MethodID)
	{
		case OM_NEW								: return(mNew					(cl,obj,(APTR)msg));
		case MUIM_HexEdit_CreateDisplayAddress	: return(mCreateDisplayAddress	(cl,obj,(APTR)msg));
	}
	return(DoSuperMethodA(cl,obj,msg));
}

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

void* winmem_init() {
	return HexClass = MUI_CreateCustomClass(NULL,MUIC_HexEdit,NULL,sizeof(struct HexData),HexDispatcher);
}

void winmem_finit() {
	if (HexClass) MUI_DeleteCustomClass(HexClass);
}

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

void
make_win_mem(
	int adr		/* start address (logical) of memory to display */
) {
	int n;
	APTR strip_mem, prop, hex;
	ULONG open;
	APTR low,high;
	ULONG off,cur;
	char *title;
	
	/*
	 *  check if there is a free window left
	 *  if window closed dispose it
	 */
	for (n=0; (n<MAXWINMEM) && win_mem[n]; n++) {
		get(win_mem[n],MUIA_Window_Open,&open);
		if (!open) {
			DoMethod(app,OM_REMMEMBER,win_mem[n]);
			MUI_DisposeObject(win_mem[n]);
			win_mem[n] = NULL;
			break;
		}
	}
	if (n==MAXWINMEM) {
		MUI_Request(app,win,0,NULL,"Ok","Sorry, too many windows already open.");
		return;
	}
	
	/*
	 *  check which memory is requested
	 */
	if (adr < header->wdh_BaseMemSize) {
		title = "Base Memory (Chip)";
		low = mem;
		high = ((UBYTE*)mem) + header->wdh_BaseMemSize - 1;
		off = -(ULONG)mem;
		cur = adr;
	} else if ((adr >= header->wdh_ExpMemLog) && (adr < header->wdh_ExpMemLog + header->wdh_ExpMemLen)) {
		title = "Expansion Memory (Fast)";
		low = emem;
		high = ((UBYTE*)emem) + header->wdh_ExpMemLen - 1;
		off = header->wdh_ExpMemLog - (ULONG)emem;
		cur = adr - header->wdh_ExpMemLog;
	} else if ((adr >= header->wdh_SlaveLog) && (adr < header->wdh_SlaveLog + header->wdh_SlaveLen)) {
		title = "Slave Memory";
		low = slave;
		high = ((UBYTE*)slave) + header->wdh_SlaveLen - 1;
		off = header->wdh_SlaveLog - (ULONG)slave;
		cur = adr - header->wdh_SlaveLog;
	} else {
		MUI_Request(app,win,0,NULL,"Ok","Sorry, address is outside the defined memory.");
		return;
	}

	/*
	 *  create the window
	 */
	win_mem[n] = WindowObject,
		MUIA_Window_Title, title,
		MUIA_Window_ID   , n + MAKE_ID('M','E','M','0'),
		MUIA_Window_Menustrip, strip_mem = MUI_MakeObject(MUIO_MenustripNM,MenuData1,0),
		WindowContents, HGroup,
			Child, hex = NewObject(HexClass->mcc_Class,0, VirtualFrame,
				MUIA_HexEdit_LowBound, low,
				MUIA_HexEdit_HighBound, high,
				MUIA_HexEdit_BaseAddressOffset, off,
				MUIA_HexEdit_AddressChars, 0,	/* must be after Low, High and BaseAddressOffset! */
				MUIA_HexEdit_EditMode, TRUE,
				MUIA_HexEdit_SelectMode, MUIV_HexEdit_SelectMode_Byte,
				MUIA_HexEdit_CursorAddress, cur,
				MUIA_CycleChain, 1,
				End,
			Child, prop = ScrollbarObject,
				MUIA_Prop_UseWinBorder, MUIV_Prop_UseWinBorder_Right,
				End,
			End,
		End;
	if (!win_mem[n]) {
		MUI_Request(app,win,0,NULL,"Ok","Couldn't open window.");
		return;
	}

	set(hex,MUIA_HexEdit_BaseAddressOffset,off);
	set(hex,MUIA_HexEdit_AddressChars,2);

	/*
	 *  add window to application and open it
	 */
	DoMethod(app,OM_ADDMEMBER,win_mem[n]);
	set(hex,MUIA_HexEdit_PropObject,prop);
	DoMethod(win_mem[n],MUIM_Notify,MUIA_Window_CloseRequest,TRUE,win_mem[n],3,MUIM_Set,MUIA_Window_Open,FALSE);
	set(win_mem[n],MUIA_Window_Open,TRUE);

}

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

