/*
 *  menstck.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 MENSTCK_DOT_H
#define MENSTCK_DOT_H
#include "dlist.h"
#include "slist.h"
#include "mentyp.h"
class Menu ;
class MenuWindow ;
class MenuViewLine ;
class MenuTreeTraverseObject ;
class MenuLine ;
class HotButton ;
class ostream ;


class StackMenuBase {
protected:
	Menu * TheMenu ;
	const char * WhereFrom ;	// command from previous menu
	int parameter_index ;		// index of command from previous menu
	int in_menu_flag ;
	int the_level ;
public :
	StackMenuBase(Menu *menu, const char * where, int level, int par, int in=1);
	StackMenuBase(StackMenuBase * clone);
	Menu * GetMenu() const {return TheMenu;}
	const char * GetWhereFrom() const { return WhereFrom;}
	void SetSelectColor(MenuWindow * MenWin, Menu * Previous,int Line) ;
	int get_parameter_index() const {return parameter_index;}
	void Dump() const ;
	int is_in_menu() const {return in_menu_flag;}
	void set_in_menu(int val=1) {in_menu_flag=val;}
	int level() const {return the_level;}
	int expanded() const ;
} ;

class StackMenu: public StackMenuBase {
	MenuViewLine& menu_line ;
public:
	StackMenu(MenuViewLine * menu, const char * where, int param,
		int level,int in=1);
	StackMenu(StackMenu * clone);
	StackMenu(StackMenuBase * clone);
	virtual void Dump() const ;
	MenuViewLine& view_line(){return menu_line;}
	int is_visible() const ;
	void find_command(MenuTreeTraverseObject& obj) const ;

};

class StackMenuBaseList : public DoubleList {
public:
	ErrCode Insert(StackMenuBase *nt) {return DoubleList::Insert(nt);}
	ErrCode Append(StackMenuBase *nt) {return DoubleList::Append(nt);}
	StackMenuBase * Get() {return (StackMenuBase *) DoubleList::Get();}
	StackMenuBase * Pop() ;
	void Push(Menu * menu,const char * WhereFrom,int p) ;
	void Push (StackMenuBase * b) {DoubleList::Append(b);}
	StackMenuBase * GetStackMenuNFromTop(int N) ;
	int Size() {return DoubleList::Size();}
	virtual void Dump() const ;
	void record_menu_state(ostream& out, Menu& men);
};

class StackMenuList: public StackMenuBaseList {
	int size ;
public:
	ErrCode Insert(StackMenu *nt) {return StackMenuBaseList::Insert(nt);}
	ErrCode Append(StackMenu *nt) {return StackMenuBaseList::Append(nt);}
	StackMenu * Get()
		{if (size) size--; return (StackMenu *) StackMenuBaseList::Get();}
	StackMenu * Pop() ;
	void Push(MenuViewLine * line,const char * WhereFrom,int p) ;
	StackMenu * GetNFromTop(int N) ;
	StackMenu * GetStackMenuNFromTop(int N) ;
	Menu * GetNthEntry(int N) ;
	StackMenu * GetStackNthEntry(int N) ;
	StackMenuList(StackMenuBaseList * par=0,int size_copy= -1);
	int Size() const {return size;}
	StackMenu * first_visible(int base=0);
	int all_visible(int base=0);
	void Dump() const ;
	int top_visible();
	int top_param();
	int visible_levels();
	const char * name_from_level(int level, int from) const ;
	const StackMenuBase * find_command(MenuTreeTraverseObject& obj) const ;

	HotButton * select_home();
	HotButton * select_end();
	HotButton * select_left(HotButton *);
	HotButton * select_right(HotButton *);
	HotButton * select_up(HotButton *);
	HotButton * select_down(HotButton *);

	HotButton * find_selection(const char * sel);

} ;

class StackMenuListIterator: public DoubleListIterator {
public:
	StackMenuListIterator(const StackMenuList& df):
		DoubleListIterator((DoubleList&) df){}
	StackMenu * operator()()
		{return (StackMenu *) Next();}
};

class StackMenuListReverseIterator: public DoubleListIterator {
public:
	StackMenuListReverseIterator(const StackMenuList& df):
		DoubleListIterator((DoubleList&) df){}
	StackMenu * operator()()
		{return (StackMenu *) Previous();}
};

class StackMenuBaseListIterator: public DoubleListIterator {
public:
	StackMenuBaseListIterator(const StackMenuBaseList& df):
		DoubleListIterator((DoubleList&) df){}
	StackMenuBase * operator()()
		{return (StackMenuBase *) Next();}
};

class StackMenuBaseListReverseIterator: public DoubleListIterator {
public:
	StackMenuBaseListReverseIterator(const StackMenuBaseList& df):
		DoubleListIterator((DoubleList&) df){}
	StackMenuBase * operator()()
		{return (StackMenuBase *) Previous();}
};


class MenuTreeTraverseObject {
	StackMenuBaseList stack ;
	const char * command_name ;
	const StackMenuBase * the_menu ;
	int duplicate_flag ;
	int error_if_not_other ;
	int the_index ;
	ConstStringList * required_history ;
	const char * next_check ;
	Menu * history_constraint ;
	int found_constraint ;
public:
	MenuTreeTraverseObject(const char * cmd, ConstStringList * h=0,
		Menu * constraint=0, int other=0):the_menu(0),
		history_constraint(constraint),
		found_constraint(0),error_if_not_other(other),
		command_name(cmd),duplicate_flag(0),the_index(0),
		required_history(h),next_check(h?h->Pop():0){}
	~MenuTreeTraverseObject();
	const StackMenuBase * found() const {return the_menu;}
	int is_duplicate() const {return duplicate_flag;}
	int is_error() const {return !the_menu || duplicate_flag;}
	void error_message(const char * where) const;
	const char * command() const {return command_name;}
	void stack_menu(const StackMenuBase * men, int ix)
		{the_menu=men; the_index=ix;}
	void duplicate() {duplicate_flag=1;}
	int index() const {return the_index;}
	void push (StackMenuBase * b) {stack.Push(b);}
	void push(Menu * men, const char * where_from, int ix)
		{stack.Push(men,where_from,ix);}
	void pop(){delete (StackMenuBase *) stack.Pop();}
	int size() {return stack.Size();}
	StackMenuBaseList& get_stack() {return stack;}
	const char * next() ; 
	void next_next() {next_check = required_history->Pop();}
	void push_next(const char * hist) {required_history->Append(hist);}
	int constraint_met() { return !history_constraint || found_constraint ;}
	int check_on_enter(Menu *ck) ;
	MenuEnums::ExitStatus check_on_exit(Menu *ck) ;
	int must_be_other() {return error_if_not_other;}
};


#endif /* #ifdef MENSTCK_DOT_H */
