/*
 *  menu.h from ObjectProDSP 0.2
 *  Copyright (C) 1994 1995, Mountain Math Software. All rights reserved.
 *  
 *  This file is part of ObjectProDSP, a tool for Digital Signal
 *  Processing design, development and implementation. It is free
 *  software provided you use and distribute it under the terms of
 *  version 2 of the GNU General Public License as published
 *  by the Free Software Foundation. You may NOT distribute it or
 *  works derived from it or code that it generates under ANY
 *  OTHER terms.  In particular NONE of the ObjectProDSP system is
 *  licensed for use under the GNU General Public LIBRARY License.
 *  Mountain Math Software plans to offer a commercial version of
 *  ObjectProDSP for a fee. That version will allow redistribution
 *  of generated code under standard commercial terms.
 *  
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *  GNU General Public License for more details.
 *  
 *  You should have received a copy of version 2 of the GNU General
 *  Public License along with this program. See file COPYING. If not
 *  or if you wish information on commercial versions and licensing
 *  write Mountain Math Software, P. O. Box 2124, Saratoga, CA 95070,
 *  USA, or send us e-mail at: support@mtnmath.com.
 *  
 *  You may also obtain the GNU General Public License by writing the
 *  Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
 *  USA.  However if you received a copy of this program without the
 *  file COPYING or without a copyright notice attached to all text
 *  files, libraries and executables please inform Mountain Math Software.
 *  
 *  ObjectProDSP is a trademark of Mountain Math Software.
 */
#ifndef MENU_DOT_H
#define MENU_DOT_H
/*  menu.h   */
/*  Copyright 1989 Mountain Math Software  */
/*  All Rights Reserved                    */
// This file defines the objects for interactive menus
// C files are menu.c, menus.c and menudrv.c
#include "slist.h"
#include "menucmd.h"
#include "mentyp.h"

class OutTokens ;
class Menu ;
class MenuExtension ;
class MenuLine ;
class MenuTreeTraverseObject ;
struct CommandParameters ;

union MenuObject {
	Menu * TheSubMenu;
	CommandParameters * TheCommand ;
	MenuExtension * TheExtension ;
	MenuObject(Menu * men) {TheSubMenu = men;}
	MenuObject(CommandParameters * cmd) {TheCommand = cmd;}
	MenuObject(MenuExtension * ext) {TheExtension = ext;}
	MenuObject(void *, MenuType);
};

struct MenuLine {
	const char * Command ;
	const char * Line ;
	MenuType TheType;
	void * TheObject ;
// TheObject is really type MenuObject but we can't initialize a union!!
	const char ** Conflicts ;	// List of incompatible commands
	struct CommandParameters * Init ;	// Command initialization
					// Used when the same menu occurs
					// in different contexts
	const char ** HelpText ;	// List of text lines for interactive
					// help .
	const char * HelpFileName ;	
	MenuTypeSpecial type_special ;
	DoMenuReturn DoItem(const char *) ;
	const char ** GetConflicts() 	{return Conflicts;}
	void Help(OutTokens&);		// One line explanation
	void HelpExplain(OutTokens&) ;	// Detailed description
	void CheckInit() {if (Init) Init->Execute() ;}
	int Delete() ;
	MenuObject GetMenuObject() ;
	void SetMenuObject (MenuType type, MenuObject object);
	MenuLine& SetMenuLine(const char * cmd, const char *ln,
		MenuType type, MenuObject Object, const char ** conf,
		CommandParameters * init, const char ** help,
		const char * file,
			MenuTypeSpecial spc=MenuTypeSpecialNormal);
	Menu * GetNewMenu();
	CommandParameters * GetDoCommand();
	MenuExtension * GetExtension() ;
	void Dump();
	void ObjectDump();
	const char * GetCommand() {return Command;}
	void AddMenuItem(Menu * TheMenu);
	int is_expanded() const
		{return type_special & MenuTypeSpecialExpanded;}
	int invalid() ;
} ;

class MenuExtension {
	int TotalMenuItems ;
	int NoMenuItems ;
	MenuLine * MenuItems ;
	MenuExtension * SeparatedMenuList ;
public:
	MenuExtension(MenuLine * TheItems, int Number=0);
	MenuLine * GetIndexedMenuLine(int Index, int * NewIndex=0) ;
	void SetMenuItems(MenuLine * MenuItems, int Number);
	MenuLine * GetMenuLines() {return MenuItems;}
	int GetNoMenuItems() {return NoMenuItems;}
	MenuLine * GetEntry(int i) {return MenuItems + i;}
	void AddItem(MenuLine * New);
	MenuExtension * Expand(int Base, int& );
	void SetTotalMenuItems() ;
	MenuExtension * GetNextMenuSegment() {return SeparatedMenuList;}
	void AddMenuSegment(MenuExtension *) ;
	void Dump();
	int Delete(const char * Command);
	int DeleteLocal(const char * Command);
};


const MenuInit = -2 ;
const MenuNext = -1 ;

class Menu {
	const char * Header ;
	MenuLine * MenuItems ;	// Array of menu lines
				// Command name is NULL for last item
	int MultipleUseFlag ;	// if set commands in this menu do
				// not have a unique meaning and cannot
				// be directly executed
	int NoMenuItems ;
	int TotalMenuItems ;
	CommandParameters * Init;	// If present this is executed at start
				// of each menu
	int NextLine;
	int ExpandedMenu;	// indicates a multi line menu 
	MenuLine * Parent ;	// 0 for main menu and menus with MultiUseFlag
	Menu * SeparatedMenuList ;
public :
	Menu(const char * Head, MenuLine * Items,int MulUse = 0,
		CommandParameters * init=0, MenuLine * parent = 0) ;

	Menu(const char * Head, MenuExtension * Ext,int MulUse = 0,
		CommandParameters * init=0, MenuLine * parent = 0) ;

	MenuLine * GetMenuLine(int i = MenuNext) ;
	const char * GetHeader() { return Header ; }
	MenuLine * IsValidCommand(const char * Cmd) ;
	int FindName(const char * Name) ;
	int GetNoItems() {return NoMenuItems;}
	int GetTotalMenuItems() {return TotalMenuItems;}
	int GetMultipleUseFlag() {return MultipleUseFlag;}
	MenuLine * GetMenuLines() {return MenuItems;}
	void SetMenuItems (MenuLine * NewItems) ;
	void Display() ;
	void Help(OutTokens&);
	DoMenuReturn DoItem(int,const char *) ;
	DoMenuReturn DoItem(MenuLine *It,const char * GetHere) 
		{return It->DoItem(GetHere);}
	void CheckInit() {if (Init) Init->Execute() ;}
	DoMenuReturn DoGraphicsMenuItem(const char * Str);
	DoMenuReturn DoGraphicsMenuItem();
		// Only used in graphics interface
	void ExpandIfNeeded(int LineWidth);
	void Expand(int NewMenuStart, const char * NewMenuSelect);
	void CheckExpandNeeded(int LineWidth);
	// void Contract(int Line); // combine lines Line and
				 //   Line + 1 to a single line
	MenuLine * GetParent() {return Parent;}
	void SetParent(MenuLine * parent) {Parent = parent;}
	void InitParent(MenuLine * parent);
	MenuLine * GetIndexedMenuLine(int Index, int * NewIndex=0) ;
	MenuExtension * GetExtensionContaining(int Index, int * BaseIndex = 0,
		int * IndexHere = 0) ;
	void SetTotalMenuItems() ;
	void Dump();
	Menu* GetNextMenuSegment() {return SeparatedMenuList;}
	void AddMenuSegment(Menu *) ;
	MenuLine * FindLineFromCommand(const char * Command, int * index=0,
		int check_expansion=0) ;
	void AddMenuItem(MenuLine * TheItem);
	int expanded() const {return ExpandedMenu ;}
	int command_index(const char * name) const ;
	MenuEnums::ExitStatus execute_command(MenuTreeTraverseObject& obj,
		const char * where_from, int index_from);
	void find_command(MenuTreeTraverseObject& obj, const char * where_from,
		int index_from);
	Menu * find_parent(Menu * menu);
} ;


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

class MenuListIterator:private SingleListIterator {
public:
	MenuListIterator(MenuList& df):SingleListIterator((SingleList&) df){}
	Menu * operator()()
		{return (Menu *) Next();}
};


class AllMenus {
	Menu ** TheMenus ;  		// list of all menus in system
	Menu * MainMenu ;		// Main Menu
	ConstStringList CommandStack ;	// list of all commands recursively
					// executed
	MenuLine * IsValidCommand(const char * Cmd) ;
	const char * IsLegalCommand(MenuLine *) ;
	void CheckMenu (Menu&, MenuList& ) ;
public:
	AllMenus(Menu& MainMenu) ;
	void Init();
	Menu * GetMainMenu() {return MainMenu;}
	void Push (const char * Cmd) {CommandStack.Append(Cmd);}
	void Pop () {CommandStack.Pop();}
	int IsLegal(MenuLine * MenuItem) ;
	void DumpStack(class OutTokens&) ;
	int TestAndDo(const char * command) ;
					// if command is a valid command
					// and does violate recursion rules
					// then do it - in any event return
					// 1 if it is valid and 0 othrerwise
	void Help() ;			// list all commands
	Menu * FindMenuFromCommand(const char * cmd);
	void find_command(MenuTreeTraverseObject& obj);
	int execute_command(MenuTreeTraverseObject& obj);
	Menu * FindParent(Menu *);
};

struct OrphanedMenus {
	const char * Name ;
	Menu * TheMenu ;
	const char * GetName() {return Name;}
	Menu * GetMenu() {return TheMenu;}
};

void AttachOrphan(const char * BaseClass, const char * DerivedClass);

extern OrphanedMenus TheOrphanedMenus[] ;

extern void DoMainMenu() ;
void ReDoMainMenu() ;

extern AllMenus TheMenus;
extern AllMenus AllCgiMenus;
extern AllMenus AllCgiTermMenus;

extern AllMenus * TheCurrentMenus ;
#define Orphan 0

#endif /* #ifdef MENU_DOT_H */
