/*
 *	MenuAlloc.c - Copyright © 1990 by S.R. & P.C.
 *
 *	Created:	16 Jun 1990
 *	Modified:	20 Nov 1990  21:18:16
 *
 *	Make>> make
 */

#include "Menu.h"
#include "Tokens.h"

#define NO_MENUS 4

#define MEM_BLOCK_SIZE 1024

struct MemBlock {
	struct MinNode mb_MinNode;
	char mb_MemBlock[MEM_BLOCK_SIZE];
};


/*****				 global functions					*****/

void AddMenu(char *);
void AddSubMenu(char *);
void AddEntry(char *, char *, char*, char*, char, char, long, short);
void EndSubMenu(void);
void CleanUp(void);
void FreeMenus(void);
void InitMenuAlloc(void);

extern void Bye(short);

/*****				 global variables					*****/

extern struct Menu Menu1;
extern UBYTE menu_pen;
extern char *ReqTitle;


/*****				 local variables					*****/

static struct Menu *CurrentMenu;
static struct MenuItem *CurrentSubMenu, **CurrentItem;
static struct MinList MemList;
static size_t Avail;


void InitMenuAlloc(void)
{
	MemList.mlh_Head = (struct MinNode *)&MemList.mlh_Tail;
	MemList.mlh_TailPred = (struct MinNode *)&MemList;
}


/* Memory allocation functions */

static void *Malloc(size_t size);
#pragma regcall(Malloc(d0))


static void *Malloc(size_t size)
{
	struct MemBlock *mb;
	static char *mem;
	void *chunck;

	size += 3;			/* make chuncks long word aligned */
	size &= ~(3L);
	if (size > Avail) {
		if (size > MEM_BLOCK_SIZE) {
			SimpleRequest(ReqTitle, "Line too long");
			Bye(NO_MENUS);
		}
		if (!(mb = AllocMem(sizeof(struct MemBlock), MEMF_PUBLIC|MEMF_CLEAR)))
			Bye(NO_MENUS);
		AddTail((struct List *)&MemList, (struct Node *)mb);
		mem = mb->mb_MemBlock;
		Avail = MEM_BLOCK_SIZE;
	}
	chunck = mem;
	mem += size;
	Avail -= size;
	return chunck;
}


/* clean up widths and other info now that menu is all built */

void CleanUp(void)
{
	UWORD maxw, smaxw, txtw, top, stop, left;
	struct Menu *mptr;
	struct MenuItem *iptr, *sptr;

	left = Menu1.Width;
	for( mptr = Menu1.NextMenu ; mptr ; mptr=mptr->NextMenu ) {
		mptr->LeftEdge = left;
		maxw = mptr->Width = (strlen(mptr->MenuName)+2) * 8;
		left += maxw;
		top = 0;
		/* determine max width */
		for( iptr = mptr->FirstItem ; iptr ; iptr=iptr->NextItem ) {
			iptr->TopEdge = top;
			top += iptr->Height;
			txtw = IntuiTextLength((struct IntuiText *)iptr->ItemFill)+2;
			if( iptr->Flags & COMMSEQ ) txtw += 48;
			if( txtw > maxw ) maxw = txtw;
		}
		for( iptr = mptr->FirstItem ; iptr ; iptr=iptr->NextItem ) {
			iptr->Width = maxw;
			stop = smaxw = 0;
			for( sptr=iptr->SubItem ; sptr ; sptr=sptr->NextItem ) {
				sptr->LeftEdge = maxw;
				sptr->TopEdge = stop;
				stop += sptr->Height;
				txtw = IntuiTextLength((struct IntuiText *)sptr->ItemFill)+2;
				if( sptr->Flags & COMMSEQ ) txtw += 48;
				if( txtw > smaxw ) smaxw = txtw;
			}
			for( sptr=iptr->SubItem ; sptr ; sptr=sptr->NextItem )
				sptr->Width = smaxw;
		}
	}
}


/*****  make (and Mallocate) a copy of the passed string *****/

static char *MallocStr(char *str)
{
	char *newstr;
	newstr = Malloc(strlen(str)+1);
	strcpy(newstr, str);
	return newstr;
}


/* allocate and initialize a new MenuItem */

struct Extended_MenuItem *AllocItem(char *itemstr)
{
	struct IntuiText *IT;
	struct Extended_MenuItem *emi;

	emi = Malloc(sizeof(struct Extended_MenuItem));
	IT = Malloc(sizeof(struct IntuiText));
	emi->emi_MenuItem.Height = 10;
	emi->emi_MenuItem.Flags = ITEMTEXT+HIGHCOMP+ITEMENABLED;
	IT->FrontPen = menu_pen;
	IT->LeftEdge = IT->TopEdge = 1;
	IT->DrawMode = JAM1;
	IT->IText = (UBYTE *)MallocStr(itemstr);
	emi->emi_MenuItem.ItemFill = (APTR)IT;
	return emi;
}


/* allocate and initialize a new Menu */

void AddMenu(char *str)
{
	struct Menu *Menu;

	Menu = Malloc(sizeof(struct Menu));
	Menu->MenuName = MallocStr(str);
	Menu->Flags = MENUENABLED;
	CurrentMenu->NextMenu = Menu;
	CurrentMenu = Menu;
	CurrentItem = &Menu->FirstItem;
}


void AddSubMenu(char *substr)
{
	*CurrentItem = (struct MenuItem *)AllocItem(substr);
	CurrentSubMenu = *CurrentItem;
	CurrentItem = &CurrentSubMenu->SubItem;
}


void EndSubMenu(void)
{
	CurrentItem = &CurrentSubMenu->NextItem;
}


void AddEntry(	char *item,
				char *cmd,
				char *args,
				char *win,
				char shortcut,
				char mode,
				long stk,
				short pri )
{
	struct Extended_MenuItem *emi;

	emi = AllocItem(item);
	emi->emi_Mode = mode;
	emi->emi_Cmd = MallocStr(cmd);
	if (args) emi->emi_Args = MallocStr(args);
	if (shortcut) {
		emi->emi_MenuItem.Flags |= COMMSEQ;
		emi->emi_MenuItem.Command = shortcut;
	}
	if (win)
		emi->emi_Window = MallocStr(win);
	emi->emi_Pri = pri;
	emi->emi_Stack = stk;
	*CurrentItem = (struct MenuItem *)emi;
	CurrentItem = &emi->emi_MenuItem.NextItem;
}


/* free up all space taken up by our menus */

void FreeMenus( void )
{
	struct MemBlock *mb;

	while( mb = (struct MemBlock *)RemTail((struct List *)&MemList) )
		FreeMem(mb, sizeof(struct MemBlock));
	CurrentMenu = &Menu1;
	Menu1.NextMenu = NULL;
	Avail = 0;
}

