/*
 *	MenuAlloc.c - Copyright © 1990 by S.R. & P.C.
 *
 *	Created:	16 Jun 1990
 *	Modified:	17 Jul 1991  20:58:46
 *
 *	Make>> make
 */

#include "ParMBase.h"

#define MEM_BLOCK_SIZE 1024

extern void RemParMEvents(struct Window *Win);

/* Memory allocation functions */

static void *Malloc(struct ParMConfig *PCfg, size_t size)
{
	void *chunck;

	size += 3;			/* make chuncks long word aligned */
	size &= ~(3L);
	if (size > PCfg->Avail) {
		if (size > MEM_BLOCK_SIZE) {
			SimpleRequest(PCfg->ReqTitle, "Line too long");
			return NULL;
		}
		if (!(PCfg->mem = AllocRemember(&PCfg->MemList, MEM_BLOCK_SIZE, MEMF_PUBLIC|MEMF_CLEAR)))
			return NULL;
		PCfg->Avail = MEM_BLOCK_SIZE;
	}
	chunck = PCfg->mem;
	PCfg->mem += size;
	PCfg->Avail -= size;
	return chunck;
}


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

static char *MallocStr(struct ParMConfig *PCfg, char *str)
{
	char *newstr;

	if (newstr = Malloc(PCfg, strlen(str)+1))
		strcpy(newstr, str);
	return newstr;
}


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

void CleanUp(struct Menu *Menu, short LeftEdge, short ItemHeight)
{
	UWORD maxw, smaxw, txtw, top, stop;
	struct MenuItem *iptr, *sptr;

	for( ; Menu ; Menu = Menu->NextMenu ) {
		Menu->LeftEdge = LeftEdge;
		maxw = Menu->Width = strlen(Menu->MenuName) * 8 + 12;
		LeftEdge += maxw;
		top = 0;
		/* determine max width */
		for( iptr = Menu->FirstItem ; iptr ; iptr=iptr->NextItem ) {
			iptr->TopEdge = top;
			top += (iptr->Height = ItemHeight);
			txtw = IntuiTextLength((struct IntuiText *)iptr->ItemFill)+2;
			if( iptr->Flags & COMMSEQ ) txtw += 48;
			if( txtw > maxw ) maxw = txtw;
		}
		for( iptr = Menu->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 = ItemHeight);
				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;
		}
	}
}


/* allocate and initialize a new MenuItem */

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

	if (!(emi = Malloc(PCfg, sizeof(struct Extended_MenuItem))))
		return FALSE;
	if (!(IT = Malloc(PCfg, sizeof(struct IntuiText))))
		return FALSE;
	emi->emi_MenuItem.Flags = ITEMTEXT+HIGHCOMP+ITEMENABLED;
	IT->FrontPen = PCfg->MenuPen;
	IT->LeftEdge = IT->TopEdge = 1;
	IT->DrawMode = JAM1;
	if (!(IT->IText = (UBYTE *)MallocStr(PCfg, itemstr)))
		return FALSE;
	emi->emi_MenuItem.ItemFill = (APTR)IT;
	return emi;
}


/* allocate and initialize a new Menu */

BOOL AddMenu(struct ParMConfig *PCfg, char *str)
{
	struct Menu *Menu;

	if (!(Menu = Malloc(PCfg, sizeof(struct Menu))))
		return FALSE;
	if (!(Menu->MenuName = MallocStr(PCfg, str)))
		return FALSE;
	Menu->Flags = MENUENABLED;
	PCfg->CurrentMenu->NextMenu = Menu;
	PCfg->CurrentMenu = Menu;
	PCfg->CurrentItem = &Menu->FirstItem;
	return TRUE;
}


BOOL AddSubMenu(struct ParMConfig *PCfg, char *substr)
{
	if (!(*PCfg->CurrentItem = (struct MenuItem *)AllocItem(PCfg, substr)))
		return FALSE;
	PCfg->CurrentSubMenu = *PCfg->CurrentItem;
	PCfg->CurrentItem = &PCfg->CurrentSubMenu->SubItem;
	return TRUE;
}


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

	if (!(emi = AllocItem(PCfg, item)))
		return FALSE;
	emi->emi_Mode = mode;
	if (!(emi->emi_RunInfo.ri_Cmd = MallocStr(PCfg, cmd)))
		return FALSE;
	if (args && !(emi->emi_RunInfo.ri_Args = MallocStr(PCfg, args)))
		return FALSE;
	if (shortcut) {
		emi->emi_MenuItem.Flags |= COMMSEQ;
		emi->emi_MenuItem.Command = shortcut;
	}
	if (win && !(emi->emi_RunInfo.ri_Window = MallocStr(PCfg, win)))
		return FALSE;
	emi->emi_RunInfo.ri_Pri = pri;
	emi->emi_RunInfo.ri_Stack = stk;
	*PCfg->CurrentItem = (struct MenuItem *)emi;
	PCfg->CurrentItem = &emi->emi_MenuItem.NextItem;
	return TRUE;
}


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

void FreeMenus(struct ParMConfig *PCfg)
{
	struct ParMBase *ParMBase;

	FreeRemember(&PCfg->MemList, TRUE);
	PCfg->CurrentMenu = PCfg->LinkMenu;
	PCfg->LinkMenu->NextMenu = NULL;
	PCfg->Avail = 0;
	RemParMEvents(PCfg->Win);
}

