/*  dynmen.c   */
/*  Copyright 1989 Mountain Math Software  */
/*  All Rights Reserved                    */
#include <string.h>
#include "slist.h"
#include "menu.h"
#include "dynmen.h"
#include "cgidbg.h"
#include "dsp_app.h"
#include <InterViews/leave-scope.h>
#include <Dispatch/leave-scope.h>

#include "menmgr.h"
// #include "grphmenu.h"

DynamicMenuControl * TheDynamicMenuController = 0;

class DynamicMenuList: public SingleList {
public:
	ErrCode Insert(DynamicMenu *nt) {return SingleList::Insert(nt);}
	ErrCode Append(DynamicMenu *nt) {return SingleList::Append(nt);}
	DynamicMenu * Get()   {return (DynamicMenu *) SingleList::Get();}
	DynamicMenu * Pop() {return (DynamicMenu *) SingleList::Pop();}
	DynamicMenu * GetNFromTop(int N) ;
	DynamicMenu * GetNthEntry(int N) ;
	DynamicMenuList(){;}
	int Size(){return SingleList::Size();}
} ;

class DynamicMenuListIterator: public SingleListIterator {
public:
	DynamicMenuListIterator(DynamicMenuList& df):
		SingleListIterator((SingleList&) df){}
	DynamicMenu * operator()()
		{return (DynamicMenu *) Next();}
};


DynamicMenu::DynamicMenu(const char * Head, MenuLine * Items,int MulUse,
		CommandParameters * init):Menu(Head,
		new MenuExtension(Items),MulUse,init)
{
	// transfer contents of original array to dynamically declared
	// array with addition slots
	// Don't delete original! It was not dynamically declared.
	// So we waste a few bytes!
	
	// LogOut << "DynamicMenu::ctor\n" ;
	if (!TheDynamicMenuController) TheDynamicMenuController = new 
		DynamicMenuControl ;
	MenuLine * TheLine = GetMenuLines();
	if (!TheLine) DbgError("DynamicMenu::DynamicMenu","bad line");
	TheItems = TheLine->GetExtension();
	if (!TheItems) DbgError("DynamicMenu::DynamicMenu","bad items list");
	StaticItemSlots = GetTotalMenuItems();
	MenuLine * NewItems = new MenuLine[StaticItemSlots+5];
	for (int i = 0 ; i < StaticItemSlots;i++)
		NewItems[i] = *TheItems->GetEntry(i);

	while (i<StaticItemSlots+5) NewItems[i++].TheType = MenuTypeInvalid;
	MenuItemSlotsAvailable = StaticItemSlots + 4 ;
	TheItems->SetMenuItems(NewItems,StaticItemSlots) ;

	TheDynamicMenuController->AddMenu(this);
}

DynamicMenu::~DynamicMenu()
{
	MenuLine * Items = GetMenuLines();
	for(MenuLine * ToDelete = Items + StaticItemSlots ; ToDelete->TheType ; 
		ToDelete++) ToDelete->Delete();
	delete Items ;
	SetMenuItems(0);
}

MenuLine * Menu::FindLineFromCommand(const char * Command, int * index,
	int check_expansion)
{
	MenuLine * other_line = 0 ;
	for (int i = 0 ; i < GetTotalMenuItems(); i++) {
		MenuLine * Look = GetMenuLine(i);
		if (!strcmp(Look->Command,Command)) {
			if (index) *index = i ;
			return Look ;
		} else if (check_expansion) if (Look->is_expanded()) {
			Menu * exp_ck = Look->GetNewMenu();
			Look = 0 ;
			if (exp_ck) Look = exp_ck->FindLineFromCommand(Command,index,
				check_expansion);
			if(Look) return Look ;
		}
	}
	return 0;
}

void DynamicMenu::MakeMoreSlots(MenuLine * Addition)
{
	// LogOut<<"MakeMoreSlots: Avail = " << MenuItemSlotsAvailable << "\n" ;
	// transfer contents of original array to dynamically declared
	// array with addition slots
	MenuLine * NewItems = new MenuLine[MenuItemSlotsAvailable+5];
	for (int i = 0 ; i < TheItems->GetNoMenuItems(); i++)
		NewItems[i] = TheItems->GetMenuLines()[i];
	// LogOut << "Items transferred, i = " << i << "\n" ;
	if (Addition) NewItems[i++] = *Addition ;
	int NewSize = i ;
	MenuItemSlotsAvailable += 5 ;
	while (i < MenuItemSlotsAvailable) NewItems[i++].TheType =
		MenuTypeInvalid;
	// LogOut << "Free slots cleared \nCalling SetMenuitems(" << NewSize
	//	<< ")\n" ;
	// delete TheItems->GetMenuLines();
	TheItems->SetMenuItems(NewItems,NewSize) ;
	// LogOut<<"MakeMoreSlotsX: Avail =  "<<MenuItemSlotsAvailable << "\n" ;
}

static void change_parent(Menu * men)
{
	if (!men) return ;
	if (!TheCurrentMenus) return ;
	if (!TheCurrentMenus->GetMainMenu()) return ;
	Menu * found = TheCurrentMenus->GetMainMenu()->find_parent(men);
	if (!found) return ;
	DspApplication::menu_manager().about_to_change_menu(found);
}

void DynamicMenu::AddItem(MenuLine * NewLine)
{
	DspApplication::menu_manager().about_to_change_menu(this);
	if (GetTotalMenuItems()==0) change_parent(this);
	Menu * ToCheck = this ;
	int Count = 0;
	// LogOut << "Checking for duplicate\n" ;
	do {
		if (Count++ > 1000) DbgError("DynamicMenu::AddItem",
			"MenuLinkLoop");
		if (ToCheck->FindLineFromCommand(NewLine->Command)) {
			TheLog << "DynamicMenu::AddItem adding a name that is present:"
				<< NewLine->Command << "\n" ;
			return ;
		}
	} while (ToCheck=ToCheck->GetNextMenuSegment()) ;
	if (TheItems->GetNoMenuItems() >= MenuItemSlotsAvailable)
		MakeMoreSlots();
	TheItems->AddItem(NewLine) ;
	SetMenuItems(GetMenuLines());
}

void DynamicMenu::DeleteItem(const char * Command)
{
	DspApplication::menu_manager().about_to_change_menu(this);
	if (GetTotalMenuItems()==1) change_parent(this);
	if (TheItems->Delete(Command)) SetTotalMenuItems();
	else *Output + OutputHelp << "There is not men item for `"
		<< Command << "' to delete.\n" ;
}


DynamicMenuControl::DynamicMenuControl() 
{
	TheDynamicMenus = new DynamicMenuList();
}
	
DynamicMenuControl::~DynamicMenuControl()
{
	delete TheDynamicMenus ;
}

DynamicMenu * DynamicMenuControl::CheckMenu(DynamicMenu * TheMenu)
{
	DynamicMenuListIterator Next(*TheDynamicMenus);
	DynamicMenu * Test ;
	while (Test = Next()) if (Test == TheMenu) return TheMenu;
	return 0;
}

void DynamicMenuControl::AddMenu(DynamicMenu * TheMenu)
{
	if (CheckMenu(TheMenu)) {
		TheLog << "DynamicMenuControl::AddMenu - already present" <<
			TheMenu->GetHeader() << "\n" ;
		return ;
	}
	TheDynamicMenus->Append(TheMenu);
}

void DynamicMenuControl::AddMenuItem(DynamicMenu * menu, MenuLine * Line)
{
	// LogMsg("DynamicMenuControl::AddMenuItem");
	if (!CheckMenu(menu)) DbgError(
		"DynamicMenuControl::AddMenuItem - not a dynamic menu",
		Line->Command);
	menu->AddItem(Line);
}

void DynamicMenuControl::DeleteMenuItem(DynamicMenu * menu,const char * Command)
{
	if (!CheckMenu(menu)) DbgError(
		"DynamicMenuControl::DeleteMenuItem - not a dynamic menu",
		Command);
	menu->DeleteItem(Command);
}



