#include <stdio.h>
#include <stdlib.h>
#include <stream.h>
#include <IV-X11/Xlib.h>
/* #include <IV-X11/xdisplay.h> */
/* #include <IV-X11/xwindow.h> */
#include <IV-X11/xevent.h>
#include <IV-look/kit.h>
#include <InterViews/background.h>
#include <InterViews/patch.h>
#include <InterViews/layout.h>
#include <InterViews/session.h>
#include <InterViews/canvas.h>
#include <InterViews/window.h>
#include <InterViews/label.h>
#include <InterViews/event.h>
#include <InterViews/telltale.h>
#include <InterViews/font.h>
#include <InterViews/color.h>
#include <InterViews/style.h>
#include <InterViews/selection.h>
#include <InterViews/display.h>
#include <InterViews/resource.h>
#include <InterViews/glue.h>
#include <InterViews/glyph.h>
#include <IV-look/dialogs.h>
#include <IV-look/fchooser.h>
#include <OS/string.h>
#include <OS/file.h>

#undef Complex


#include <unistd.h>
#include "helpwin.h"
#include "txtwin.h"
#include "genmenu.h"
#include <InterViews/enter-scope.h>
#include <OS/enter-scope.h>
#include "hot_button.h"
#include "file_view.h"


const ivnil=nil ;


#include "xdrv.h"
#include <InterViews/leave-scope.h>
#include <Dispatch/leave-scope.h>
#include <unistd.h>
#include <stdlib.h>
// #include <Intrinsic.h>
// extern "C" Time XtLastTimestampProcessed(XDisplay*);
#include "dsp_app.h"
#include "portable.h"
#include "newaloc.h"
#include "help.h"
#include "menu.h"
#include "cgidbg.h"
#include "shared.h"
#include "remcom.h"
#include "xgui.h"
#include "hlpfil.h"

#include "mkstr.h"
#include "call_back.h"
#include "menstck.h"
#include "menmgr.h"

static const ivCoord margin = 5.0 ;
static ivLabel * spacer_label = 0 ;

// void TestAlloc(const char * msg);


void MenuView::patch_redraw()
{
	menu_patch->redraw();
}

ivMonoGlyph * MenuView::first_menu_init(MenuKeyboard *menu)
{
	if (menu) menu_glyph.append(menu);

	root_menu_window_line->append_to_menu_glyph();
	menu_patch = new ivPatch(&menu_glyph);

	ivGlyph * kernel = the_layout.hmargin(menu_patch,margin);
	body(the_kit.inset_frame(kernel));
	
	return this ;
}

void MenuView::map()
{
	window()->style(style());
	init = 1 ;
	window()->map();
}

void MenuView::set_active(MenuViewLine * active)
{
	active_line = active ;
	root_window.set_active(this);
}

ivWindow* RootMenuView::get_menu_window()
{
	if (active_menu) return active_menu->get_window();
	return get_window();
}

void RootMenuView::process_help_strings()
{
	if (!help_strings.Size()) return ;
	help_display->replace_page(help_strings);
	new_help_page();

}

void RootMenuView::window_init()
{
	menu_txt_window = new TxtWindow("menu data base command history",
		&session,DspApplication::spacer(),4,
		*(new InputCallback(InputMenu)),this);
	cpp_txt_window = new TxtWindow("DSP++ statement history",
		&session,DspApplication::spacer(),10,
		*(new InputCallback(InputCppEntry)),this);
	int help_index = -1 ;
	MenuLine * help_line = top_menu.FindLineFromCommand("help",&help_index);
	root_menu_window_line = new MenuViewLine(*this,top_menu,0) ;
	init_push(root_menu_window_line,0,0);
	ivGlyph * menu_frame = the_kit.inset_frame(the_layout.
		margin(menu_txt_window->glyph(),margin));
	ivGlyph * cpp_frame = the_kit.inset_frame(the_layout.
		margin(cpp_txt_window->glyph(),margin));
	ivCoord x,y ;
	DspApplication::dimensions(menu_frame,x,y);
	MenuLine * line = root_menu_window_line->get_menu().GetMenuLine(0) ;
	const char ** text = line->HelpText ;
	help_display = TextWindowKit::document_window(x-margin*2,y*2.0,text);
	help_patch = new ivPatch(help_display->glyph());
	menu_glyph.append(cpp_frame);
	menu_glyph.append(menu_frame);
}

void RootMenuView::window_setup(ivGlyph * glyph)
{
	int help_index = -1 ;
	const char * help_command = "help" ;
	MenuLine * help_line = top_menu.FindLineFromCommand(help_command,
		&help_index);

	int text_entry_index = -1 ;
	Menu * help = 0 ;
	if (help_line) help = help_line->GetNewMenu();

	MenuLine * text_entry_line = 0;
	const char * text_entry_command = "manual" ;
	if (help) text_entry_line = help->FindLineFromCommand(text_entry_command,
		&text_entry_index);

	MenuViewLine * help_view_line = 0 ;
	if (help) {
		help_view_line = new MenuViewLine(*this,*help, text_entry_index) ;
		help_view_line->append_to_menu_glyph();
		init_push(help_view_line,help_command,2);
	}

	Menu * text_entry = 0 ;
	MenuViewLine * manual_view_line = 0 ;
	if (text_entry_line) text_entry = text_entry_line->GetNewMenu();
	if (text_entry) {
		manual_view_line = new MenuViewLine(*this,*text_entry);
			
		manual_view_line->append_to_menu_glyph();
		push(manual_view_line,text_entry_command,0);
	}
	window(new ivApplicationWindow(glyph),the_menu_keyboard,0);
	the_menu_keyboard->window(window(),the_menu_keyboard,0);
	
}


void RootMenuView::cpp_scroll(const char * str)
{
	cpp_txt_window->scroll(str);
}

void RootMenuView::scroll(const char * str)
{
	menu_txt_window->scroll(str);
}

void RootMenuView::replace_page(const char **str)
{
	if (!str) return ;
	if (!*str) return ;
	help_display->replace_page(str);
	new_help_page();
}

void RootMenuView::new_help_page()
{
	help_patch->body(help_display->glyph()) ;
	help_patch->redraw();
	help_window()->raise();
}


inline ivWidgetKit& MenuViewLine::kit() {return menu_window.kit();}
inline const ivLayoutKit& MenuViewLine::layout() const
	{return menu_window.the_layout;}
inline ivSession& MenuViewLine::session() const
	{return menu_window.session;}
inline ivGlyph& MenuViewLine::menu_glyph()
	{return menu_window.menu_glyph;}

int MenuViewLine::level()
{
	if (!stack_menu) DbgError("MenuViewLine::level","no stack_menu");
	return stack_menu->level();
}

boolean MenuViewLine::is_other()
{
	const char * cmd = get_command(0);
	if (!cmd) return true ;
	return !strcmp("other",cmd);
}

ivGlyph * MenuViewLine::label_glyph(const char * str)
{
	const ivFont * font = ivFont::lookup("*helvetica-medium-r-normal--12*");
	ivLabel * lab = new ivLabel(str,font,kit().foreground()); 
	return layout().hbox(layout().hglue(0.0),lab, layout().hglue(0.0));
}

void MenuViewLine::append_to_menu_glyph()
{
	ivGlyph& glyph = menu_window.menu_glyph;
	index = glyph.count();
	glyph.append(base_glyph());
}

#undef remove

ivGlyph * MenuViewLine::build_menu(ivCoord width)
{
	// LogOut << "MenuViewLine::build_menu\n" ;
	deck.append(label_glyph(menu.GetHeader()));
	button_glyph = layout().hbox(menu.GetTotalMenuItems()*2);
	MenuLine * line ;
	const char * other = "other" ;
	boolean ExpandAllowed = !is_other() ;
	int maximum_buttons = 0 ;
	for (int count = 0; line = menu.GetIndexedMenuLine(count); count++) 
		if (!line->invalid()) maximum_buttons++ ;
	// LogOut << "maximum_buttons = " << maximum_buttons << "\n" ;
	the_hot_buttons = new HotButton * [maximum_buttons+1];
	
	int next_but = 0 ;
	// add buttons one at a time
	for (count = 0; line = menu.GetIndexedMenuLine(count); count++) {
		if (line->invalid()) continue ;
		button_glyph->append(layout().hglue(2.0));
		// LogOut << "deck.append(label(" << line->Line << "));\n" ;
		HotButton * button = hot_button(*line,next_but,next_but==active_menu);
		button->glyph_index(button_glyph->count());
		button_glyph->append(button);
		if (next_but >=maximum_buttons) DbgError("MenuViewLine::build_menu",
			"too many buttons");
		int this_button = next_but++ ;
		the_hot_buttons[this_button] = button ;
		if (this_button==active_menu) active_button = button ;
		ivCoord x,y ;
		DspApplication::dimensions(button_glyph,x,y);
		if (count > 1) if (width > 0.0) if (x*1.142 > width) if (x > width ||
			menu.GetIndexedMenuLine(count+1)) if (ExpandAllowed) {
			menu.Expand(count-1,other);
			delete the_hot_buttons ;
			the_hot_buttons = 0 ;
			while(deck.count() > 0) deck.remove(0);
			// for (int j = this_button-1 ; j >= 0 ; j--) deck.remove(j);
			return 0 ;
		}
		deck.append(label_glyph(line->Line));
	}
	the_hot_buttons[next_but] = 0 ;
	button_glyph->append(layout().hglue(2.0));
	if (!spacer_label) spacer_label=
		new ivLabel(DspApplication::spacer(),kit().font(),kit().foreground()); 
	deck.append(spacer_label);
	// LogOut << "exit\n" ;
	return button_glyph ;
}

MenuViewLine::MenuViewLine(MenuView& window, Menu& men, int down_index):
	active_menu(down_index),
	active_button(0),
	menu_window(window),
	menu(men),
	the_hot_buttons(0),
	index(0),
	unique_name(0),
	deck(*layout().deck())
{
	// LogOut << "active_menu = " << active_menu << "\n" ;

	// make menu header forst deck entry
	ivGlyph * button_glyph = build_menu(window.width());
	if (!button_glyph) button_glyph = build_menu(0.0);
	patch = new ivPatch(&deck);
	// append this glyph to root gluph
	base_gl = new ivPatch(layout().vmargin(
			layout().vbox(layout().vglue(0.0),patch,layout().vglue(5.0),
					button_glyph,layout().vglue(0.0)),5.0));

	deck.flip_to(0);
}

MenuViewLine::~MenuViewLine()
{
	// LogOut << "MenuViewLine::~\n" ;
	delete unique_name ;
}

void MenuViewLine::you_are_invisible()
{
	// LogOut << "you_are_invisible: " << glyph_index() << "\n" ;
	index= -1;
	base_gl = 0;
}

static MenuLine * get_menu_line(Menu& menu, int button_index)
{
	if (button_index < 0 || button_index >= menu.GetTotalMenuItems()) return 0 ;
	int but_ix = 0 ;
    MenuLine * line ;
    for (int count = 0; line = menu.GetIndexedMenuLine(count); count++)  {
        if (line->invalid()) continue ;
        if (button_index == but_ix) break ;
        but_ix++ ;
    }
	if (button_index != but_ix) DbgError("get_menu_line","bad ix");
	return menu.GetMenuLine(count);
}

int MenuViewLine::is_menu_select(int index) const
{
	MenuLine * lin = get_menu_line(menu,index);
	if (!lin) return 0 ;
	return lin->TheType == MenuTypeMenu || lin->TheType == MenuTypeExtension ;
}

int MenuViewLine::execute(int index, const char * cmd)
{
	// LogOut << "MenuViewLine::execute(" << index << ", " << cmd << ")\n" ;
	// MenuLine * line = menu.GetIndexedMenuLine(index);
	MenuLine * line = get_menu_line(menu,index);
	if (!line) return 0 ;
	Menu * sub_menu = line->GetNewMenu();
	if (!sub_menu) return 0 ;
	int dum ;
	line = sub_menu->FindLineFromCommand(cmd,&dum,1);
	if (line) if (line->GetDoCommand()) {
		menu_window.stack_offset(1);
		menu_window.scroll(line->Command);
		line->GetDoCommand()->Execute();
		menu_window.stack_offset(0);
		return 1 ;
	}	
	return 0 ;
}

void MenuViewLine::peel_off_menu(int index)
{
	control_execute(index);
}

void MenuViewLine::raise_windows(int index)
{
	const char * cmd = get_command(index) ;
	if (!cmd) return ;
	if (DspApplication::execute_menu_command(&menu,"Raise","exec",cmd))
		menu_window.scroll("Raise");
}

void MenuViewLine::execute_restore(int index, int help_flag, HotButton *b)
{
	menu_window.set_active(this);
	MenuViewLine::release_return ret=execute_release_kernel(index,help_flag,b);
	if (ret & MenuViewLine::execute_stay_in) b->press();
		else b->release();
	if (ret & MenuViewLine::execute_release_moved) 
		get_menu_window().root().set_button_to_leave(b);
}

void MenuViewLine::do_command(int index)
{
	// LogOut << "MenuViewLine::do_command(" << index << ")\n" ;
	execute_restore(index,0,button(index));
}

void MenuViewLine::help_paragraph(int index)
{
	MenuLine*  line = get_menu_line(menu,index);
	if (line->HelpText) display_help_text(line->HelpText);
}

void MenuViewLine::cond_help_paragraph(int index)
{
	// LogOut << "MenuViewLine::cond_help_paragraph\n" ;
	if (!HelpDo.All()) return ;
	help_paragraph(index);
}

void MenuViewLine::help_file(int index)
{
	// LogOut << "MenuViewLine::help_file(" << index << ")\n" ;
	execute_restore(index,1,button(index));
}

void MenuViewLine::create_default(int index)
{
	if (execute(index,"create default")) return ;
	const char * cmd = get_command(index) ;
	if (!cmd) return ;
	if (DspApplication::execute_menu_command( &menu,"Edit","exec",cmd)) {
		menu_window.scroll ("Edit");
		return ;
	}
	if (DspApplication::execute_menu_command( &menu,"AssignToEdit","exec",cmd))
		menu_window.scroll ("AssignToEdit");
}

void MenuViewLine::create_instance(int index)
{
	execute(index,"create");
}



MenuViewLine::release_return MenuViewLine::modifier_execute(
	const ivEvent& event, int index)
{
	const char * cmd = get_command(index) ;
	if (event.control_is_down()) {
		if (event.middle_is_down()) {
			if ( DspApplication::execute_menu_command(
				&menu,"Raise","exec",cmd)) menu_window.scroll ("Raise");
		} else if (event.left_is_down()) control_execute(index);
	} else if (event.shift_is_down()) 
	  if (event.left_is_down()) {
		execute(index,"create default");
		if (cmd) {
			if (DspApplication::execute_menu_command(
				&menu,"Edit","exec",cmd)) menu_window.scroll ("Edit");
			else if (DspApplication::execute_menu_command(
					&menu,"AssignToEdit","exec",cmd))
						menu_window.scroll ("AssignToEdit");
		}
	} else if (event.right_is_down()) execute(index,"create");
	return index == active_menu ?
		execute_stay_in : execute_release_null ;
}

void MenuViewLine::control_execute(int index)
{
	menu_window.control_execute(stack_menu,index,level());
}

void MenuViewLine::execute_enter(int ix)
{
	// LogOut << "MenuViewViewLine::execute_enter(" << ix << ")\n" ;
	deck.flip_to(ix+1);
	base_gl->redraw();
}

void MenuViewLine::press(int,const ivEvent& event,HotButton*)
{
	menu_window.press(event);
}

void MenuViewLine::display_help_text(const char ** text)
{
	menu_window.replace_page(text);
}

void MenuView::press(const ivEvent& e)
{
	root_window.set_active(this);
	if (!DspApplication::user_input_allowed()) return ;
	// LogOut << "MenuView::press\n" ;
	prefer_mouse_selection();
	the_menu_keyboard->object_press(e);
	prefer_keyboard_selection();
}

void MenuViewLine::release(const ivEvent& e)
{
	menu_window.release(e);
}


void MenuView::release(const ivEvent& e)
{
	if (!DspApplication::user_input_allowed()) return ;
	root_window.set_active(this);
	prefer_mouse_selection();
	the_menu_keyboard->object_release(e) ;
	prefer_keyboard_selection();
}

void MenuView::display_help_file(const char * name, const char * win_name)
{
	// LogOut << "MenuView::display_help_file\n" ;
	if (!name) return ;
	if (!*name) return ;
	const char * full_name = GetHelpFileName(name);
	// LogOut << "full_name = `"  << full_name << "'.\n" ;
	FILE * tst_open = fopen(full_name,"r");
	if (!tst_open) return ;
	fclose(tst_open);
	
	if ('T' == name[strlen(name)-1]) {

		const ivFont * font = the_kit.font() ; // DspApplication::tty_font() ;
		char *win_name = Concatenate("help ",name);
		win_name[strlen(win_name)-1] = '\0' ; // get rid pf 'T'.
		ivStyle& style = DspApplication::style() ;
    	style.attribute("name", win_name);
    	style.attribute("iconName", win_name);

		new FileWindow(the_kit,the_layout,style,full_name,
			font,the_kit.background());
		delete win_name ;
	} else {
		ivTopLevelWindow * help_win = TextWindowKit::document_view(full_name,
			win_name);
		if (help_win) help_win->map();
	}
}

/**********************
MenuViewLine::release_return MenuViewLine::execute_release(int ix,
	const ivEvent& event, HotButton *b)
{
	menu_window.set_active(this);
	int sum = event.middle_is_down() + event.left_is_down() +
		event.right_is_down() ;
	if (sum != 1 || (event.shift_is_down() && event.control_is_down()))
		return ix == active_menu ? execute_stay_in : execute_release_null ;

	if (event.shift_is_down() || event.control_is_down())
		return modifier_execute(event,ix) ;

	MenuLine*  line = get_menu_line(menu,ix);
	menu_window.scroll(line->Command);
	return execute_release_kernel(ix,event.control_is_down(),b);
}
*************************/

MenuViewLine::release_return MenuViewLine::execute_release_kernel(int ix,
	int help_flag, HotButton * b)
{
	// LogOut << "MenuViewLine::execute_release_kernel, index = " << ix << "\n" ;
 
	MenuLine*  line = get_menu_line(menu,ix);
	line->CheckInit();
	if (help_flag) {
		if (line->HelpFileName)
			menu_window.display_help_file(line->HelpFileName);
		return active_menu==ix?execute_stay_in:execute_release_null ;
	}
	menu_window.scroll(line->Command);
	// LogOut << "Scrolled `" << line->Command << "'\n" ;
	if (is_menu_select(ix)) {
		if (ix == active_menu && menu_window.all_visible())
			return execute_stay_in ;
		if (active_menu > -1) {
			active_button->clear_menu_selection();
			active_button->release();
		}
		active_menu = ix ;
		active_button = b ;
		active_button->set_menu_selection();
		b->press();
		// determine if we need to pop existing menus from stack and display
		int to_pop = menu_window.stack_size() - level() - 1 ;
/*
 *		LogOut << "Size = " << menu_window.stack_size() << "\n" ;
 *		LogOut << "to_pop = " << to_pop << "\n" ;
 *		LogOut << "level = " << level() << ", top = " <<
 *			menu_window.stack_size() << "\n" ;
 */
		menu_window.pop(to_pop);
		// determine if we can add this line or if we have to remove
		// existing menus
		// add new menu
		Menu * new_menu = 0 ;
		MenuViewLine * new_window_line = 0 ;
		if (line) new_menu= line->GetNewMenu();
		if (new_menu) {
			ivCoord x,y_menu_line, y_size ;
			DspApplication::dimensions(base_glyph(),x,y_menu_line);
			DspApplication::dimensions(&(menu_window.menu_glyph),x,y_size);
/*
 *			LogOut << "y_size = " << y_size << ", y_menu_line = " <<
 *				y_menu_line << ", max_height = " << menu_window.max_height
 *				<< "\n" ;
 */
			int did_resize=0 ;
			if (y_size+ y_menu_line > menu_window.max_height) {
				// menu_window.menu_stack.Dump();
				menu_window.visible_pop();
				// menu_window.menu_stack.Dump();
			}
			new_window_line = new MenuViewLine(menu_window,*new_menu);
			if (!new_window_line) DbgError("MenuViewLine::execute",
				"error making new MenuViewLine");
			new_window_line->append_to_menu_glyph() ;
			menu_window.push(new_window_line,line->Command,ix);
			if (&menu_window != &(menu_window.root())) if (to_pop != 1)  {
				menu_window.resize();
				did_resize = 1 ;
			}
			menu_window.patch_redraw();
			return (MenuViewLine::release_return)
				(execute_stay_in | ((did_resize || to_pop != 1) ?
				execute_release_moved: execute_release_null)) ;
		}
		
	} else if (line->GetDoCommand()) {
		line->GetDoCommand()->Execute();
		return execute_release_null ;
	} else {
		menu_window.display_help_file(line->HelpFileName,line->Command);
		return active_menu==ix? execute_stay_in:execute_release_null;
	}
	return execute_release_null ;
}

void MenuViewLine::redraw()
{
	base_gl->redraw();
}

void MenuViewLine::execute_leave(int ix)
{
	// LogOut << "MenuViewLine::execute_leave " << ix << "\n" ;
	deck.flip_to(0); 
	// patch->reallocate();
	// patch->redraw();
	if (base_gl) base_gl->redraw();
}

ivGlyphIndex MenuViewLine::button_index(HotButton * check)
{
	int count = 0 ;
	for (HotButton ** ck = the_hot_buttons; *ck;ck++,count++)
		if (*ck == check) return count ;
	return -1 ;
}

ivGlyphIndex MenuViewLine::number_buttons() const
{
	int count = 0 ;
	for (HotButton ** ck = the_hot_buttons; *ck;ck++) count++ ;
	return count ;
}

HotButton * MenuViewLine::button(ivGlyphIndex ix) const
{
/*
 *	LogOut << "MenuViewLine::button(" << ix << ", the_hot_buttons = " <<
 *		(void *) the_hot_buttons << "\n" ;
 */
	if (ix < 0) return 0 ;
	if (!the_hot_buttons) return 0 ;
	// LogOut << "count = " << count << "\n" ;
	if (ix >= number_buttons()) return 0 ;
	return the_hot_buttons[ix] ;
}

void MenuViewLine::release_button()
{
	if (active_menu > -1) the_hot_buttons[active_menu]->release();
	active_menu = -1 ;
}

const char * MenuViewLine::get_unique_name(ivGlyphIndex ix)
{
	delete unique_name ;
	unique_name = 0 ;
	const char * cmd = get_command(ix);
	if (!cmd) cmd = "NULL" ;
	char * char_index = Concatenate(DspApplication::int_string(index));
	unique_name =
		 Concatenate(cmd,"_",DspApplication::int_string(ix),"_",char_index);
	delete char_index ;
	return unique_name ;
}

const char * MenuViewLine::get_command(ivGlyphIndex index)
{
	MenuLine * line = get_menu_line(menu,index) ;
	// MenuLine * line = menu.GetIndexedMenuLine(index) ;
	const char * cmd = 0 ;
	if (line) cmd = line->GetCommand();
	return cmd ;
}

HotButton * MenuViewLine::hot_button(MenuLine& item, int index, int is_down)
{
	// LogOut << "MenuViewLine::hot_button(, "<<index<<", "<<is_down<<")\n";
	kit().begin_style("PushButton", "Button");
	const char * this_font ;
	this_font = "*helvetica-bold-r-normal--12*" ;
	if (is_menu_select(index))
		this_font = "*helvetica-medium-r-normal--12*" ;

	const ivFont * font = ivFont::lookup(this_font);
	if (!font) font = kit().font() ;
	ivLabel * label = new ivLabel(item.Command,font,kit().foreground());
	ivLabel * blink_label = new ivLabel(item.Command,font,
		kit().foreground()->brightness(1)) ;
	Blinker * blinker = new Blinker(label,blink_label,kit().style());
	ivTelltaleState * telltale =
		new ivTelltaleState(ivTelltaleState::is_enabled | 
			(is_down? ivTelltaleState::is_active :0));
	ivGlyph * button_look = kit().push_button_look(blinker,telltale);
	HotButton * button = new HotButton(blinker, button_look, kit().style(),
		telltale, *this,index);
	kit().end_style();
	return button ;
}

/*
 * static const char * dummy_list[] = {
 *	"\n", "\n", "\n", "\n", "\n", "\n",
 *	"\n", "\n", "\n", "\n", "\n", "\n",
 *	"\n", "\n", "\n", "\n", "\n", "\n",
 *	0
 * };
 */

RootMenuView::RootMenuView(ivStyle *sty, Menu & menu, ivSession& sess):
		MenuView(sty,menu,sess,0,*this),
		active_menu(this),
		read_file_name(0),
		overwrite_flag(0),
		init_return_id(0),
		prompt(0),
		info(0),
		disallow_check_remote(0),
		direct_command(0),
		freeze_flag(0),
		the_cursor_window(0),
		hard_freeze_flag(0),
		to_unmap(0),
		network_edit_mode(0),
		button_to_leave(0),
		read_action_file_mode(0),
		prompt_response(0),
		pending_prompt_response(0),
		prompt_buf_length(0),
		wait_for_dsp_flag(0),
		prompt_buf(0)
{
    HelpDo.SetHelpLevel(HelpLevelAll);
	menu_glyph.append(the_menu_keyboard);
	window_init();
	window_setup(first_menu_init());
	// window()->place(0.0,0.0);
	map();
	

	ivStyle * sty = new ivStyle(style());
	sty->attribute("name", DspApplication::info_window);
	sty->attribute("iconName", "Help");
	ivGlyph * help_frame = the_kit.inset_frame(the_layout.
		margin(help_patch,margin));

	the_help_window = new ivTopLevelWindow(help_frame);
	the_help_window->style(sty);
	help_display->view()->window(the_help_window,0);
	// the_help_window->place(0.0,window()->height()+48.);
	the_help_window->map();
		

	max_height = window()->height();
	init_prompt();
	init_info();
	while (!window()->is_mapped()) while(event_check());
	while (!the_help_window->is_mapped()) while(event_check());
}

RootMenuView::~RootMenuView()
{
	// LogOut << "RootMenuView::~RootMenuView()\n" ;
	delete menu_txt_window ;
	delete cpp_txt_window ;
}

void RootMenuView::set_button_to_leave(HotButton * button)
{
	// if(button_to_leave) button_to_leave->do_move();
/**********
	if(button_to_leave)
		button_to_leave->line().replace_button(button_to_leave);
**************/
	button_to_leave = button ;
}

int MenuView::all_visible()
{
/*
 *	LogOut << "MenuView::all_visible, stack_base_size = " << stack_base_size <<
 *		"\n" ;
 */
	return menu_stack.all_visible(stack_base_size);
}

void MenuView::repair()
{
	window()->repair() ;
}

int MenuView::stack_size()
{
	int Return = menu_stack.Size();
	return Return ;
}

void MenuView::init_push(MenuViewLine* line, const char* where, int ix)
{
	push(line,where,ix);
	HotButton * but = line->button(ix);
	if (!but) return ;
	line->set_active(but,ix) ;
	but->down_state();
	but->set_menu_selection();
}

void MenuView::push(MenuViewLine* line, const char* where, int ix)
{
/*
 *	LogOut << "MenuView::push(," << (where ? where: "NULL") << ", "
 *		<< ix << ")\n" ;
 */
	clear_mouse_selection();
	set_selection(0);
	menu_stack.Push(line,where,ix);
}

void MenuView::resize()
{
	if (init) window()->resize();
}

ivCoord RootMenuView::width() const
{
	ivCoord x,y ;
	if (!spacer_label) spacer_label=
		new ivLabel(DspApplication::spacer(),the_kit.font(),the_kit.foreground()); 
	DspApplication::dimensions(spacer_label,x,y);
	return x ;
}

MenuView * MenuView::new_menu(Menu & menu, const char * command,
	StackMenuBaseList * base, int lim)
{
	char * temp = Concatenate("menu ", command);
	ivStyle * sty = new ivStyle(ivSession::instance()->style());
	sty->attribute("name", temp);
	sty->attribute("iconName", temp);
	// delete temp ;
	return new MenuView(sty, menu, session, command, root(), base, lim);
}

MenuView::MenuView(ivStyle * sty,Menu & menu, ivSession& sess,
	const char * command,
	RootMenuView& root, StackMenuBaseList * base, int lim):
	DspActiveHandler(0,sty),
	init(0),
	session(sess),
	keyboard_interface(0),
	the_kit(*ivWidgetKit::instance()),
	the_layout(*ivLayoutKit::instance()),
	menu_glyph(*the_layout.vbox(8)),
	// root_glyph(&menu_glyph,style()),
	root_window(root),
	top_menu(menu),
	menu_stack(base,lim),
	stack_base_size(lim),
	the_stack_offset(0),
	the_selection(0),
	the_mouse_selection(0),
	prefer_mouse(0),
	active_line(0),
	the_menu_keyboard(0),
	the_fail_select(0),
	action_failed(0)
{
	the_menu_keyboard = build_menu_keyboard(the_kit,the_layout,style(), *this);
	body(&menu_glyph);
	DspApplication::menu_manager().Append(this);
	if (&root == this) return ;
	root_menu_window_line = new MenuViewLine(*this,top_menu) ;
	push(root_menu_window_line,command,0);
	// init_push(root_menu_window_line,command,2);

 	ivTopLevelWindow *win = new ivTopLevelWindow(first_menu_init(
		the_menu_keyboard));
	win->style(style());
	window(win,the_menu_keyboard) ;
	the_menu_keyboard->window(win,the_menu_keyboard);

	map();
	if (DspApplication::root_window()->reading_action_file())
		while(!win->is_mapped()) DspApplication::event_check();
	max_height=10*win->height();
}

MenuView::~MenuView()
{
	DspApplication::menu_manager().RemoveEntry(this);
}
	
int MenuView::visible_levels()
{
	return menu_stack.visible_levels();
}

void MenuView::visible_pop()
{
	StackMenu * first_visible = menu_stack.first_visible(1);
/*
 *	LogOut << "WhereFrom first_visible is " << first_visible->GetWhereFrom()
 *		<< "\n" ;
 */
	if (!first_visible) {
		// LogOut << "visible_pop no first visible!\n" ;
		return ;
	}
	MenuViewLine& first_visible_line = first_visible->view_line();
	menu_glyph.remove(first_visible_line.glyph_index());
	// LogOut << "Making " << first_visible_line->glyph_index() << " invisible.\n" ;
	first_visible_line.you_are_invisible();

	StackMenuListIterator next(menu_stack);
	StackMenu * s_m ;
	next(); // skip base 
	while (s_m = next()) if (s_m == first_visible) break  ; // skip base
	if (s_m) while(s_m = next()) {
		MenuViewLine * line = &(s_m->view_line());
		line->dec_glyph_index();
/*
 *		LogOut << "Decremented to " << line->glyph_index() << ", `" <<
 *				s_m->GetWhereFrom() << "'\n" ;
 */
	}
}

void MenuView::control_execute(const char* cmd,int level, Menu& menu)
{
	if (!cmd) cmd = "ObjectProDSP" ;
	new_menu(menu,cmd,&menu_stack,level);
/*
 *	MenuView * temp = new MenuView(menu,session,cmd,root_window,
 *		&menu_stack,level);
 */
}

void MenuView::control_execute(StackMenu *stack_menu,int index, int level)
{
	if (!stack_menu) DbgError("MenuView::control_execute","no stack menu");
	Menu * menu = stack_menu->GetMenu() ;
	if (!menu) DbgError("MenuView::control_execute","no menu");

	// if a menu selection do sub level otherwise do this level
	MenuLine * line = get_menu_line(*menu,index);
	Menu * new_menu = 0 ;
	if (line) new_menu = line->GetNewMenu();
	if (new_menu) {
		control_execute(line->Command,level+1,*new_menu);
		return ;
	}
	control_execute(stack_menu->GetWhereFrom(),level,*menu);
}

void MenuView::pop(int to_pop)
{
	// LogOut << "MenuView::pop(" << to_pop << ")\n" ;
	// menu_stack.Dump();
	if (!to_pop) return ;
	if (to_pop < 0) DbgError("MenuView::pop","bad index");
	if (to_pop >= menu_stack.Size()) DbgError("MenuView::pop","bad list or ix");
	clear_mouse_selection();
	set_selection(0);
	for (int i = 0 ; i < to_pop; i++) {
		StackMenu * stack_elt = menu_stack.Pop();
		MenuViewLine * line = &(stack_elt->view_line());
		int visible = stack_elt->is_visible();
		delete stack_elt ;
		if (visible) {
			// LogOut << "removing " << line->glyph_index() << "\n" ;
			menu_glyph.remove(line->glyph_index());
			// LogOut << "removed\n" ;
		}
		// LogOut << "Deleting line\n" ;
		delete line ;
		// LogOut << "Deleted\n" ;
	}
	// menu_stack.Dump();
	ivResource::flush();
}

int RootMenuView::process_event(ivEvent& e)
{
		XEvent xe = e.rep()->xevent_ ;
		int ev_type = xe.type ;
		if (ev_type ==30) {
			e.handle();
			if (!disallow_check_remote) ReadSeg->CheckPacketRead();
			return ev_type ;
		} 
		if (ev_type == 33) {
			session.unread(e);
			session.run();
			return ev_type ;
		} else e.handle(); 
		return ev_type ;
}

int RootMenuView::event_wait()
{
	ivEvent tmp ;
	int ret = 0 ;
	while (ReadSeg->CheckPacketRead()) ret =  1 ;
	if (ret) return 1 ;
	ReadSeg->block();
	if (session.read(0,500000,tmp)) {
		process_event(tmp);
		ret = 1 ;
	}
	while (ReadSeg->CheckPacketRead()) ret = 1;
	return ret ;
}

int RootMenuView::event_check()
{
	ivEvent tmp ;
	if (!session.read(0,0,tmp)) return 0 ;
	process_event(tmp);
	return 1 ;
}

int RootMenuView::run()
{
	// copied from Session::run with modification to find Atom event
	ivEvent e;
	boolean done = False ;
	done = false;
	disable_remote_com();
	// if (DummyTest == '5') ExitCleanUp() ;
	do {
		set_button_to_leave(0);
		if (to_unmap) set_window_to_unmap(0);
		enable_remote_com();
		check_wait_for_dsp();
		ReadSeg->block();
		session.read(e);
		disable_remote_com();
		if (process_event(e) == 33) return 0;
	} while (!done)	;
	return 0 ;
}

/*********
 *void RootMenuView::select_setup()
 *{
 *	// Establish an atom
 *	ivDisplay * display = session.default_display();
 *	if (!display) {
 *		TheLog << "Can't get display.\n" ;
 *		exit(1);
 *	}
 *
 *
 *	_XDisplay * disp = session.default_display()->rep()->display_ ;
 *	Atom sel = XInternAtom(disp,"SECONDARY",True);
 *
 *	XWindow the_owner = XGetSelectionOwner(disp,sel);
 *	// LogOut << "the_owner = " << the_owner << "\n" ;
 *
 *	XWindow win = window()->ivWindow::rep()->xwindow_ ;
 *
 *}
 ************/


const char * RootMenuView::menu_stack_name(int ix)
{
/*
 *	LogOut << "RootMenuView::menu_stack_name(" << ix << ")\n" ;
 *	LogOut << "direct_command = " << (void *) direct_command << "\n" ;
 */
	if (direct_command) {
		StackMenuBase * find = direct_command->GetStackMenuNFromTop(ix-1) ;
		if (!find) DbgError("RootMenuView::menu_stack_name",
			"bad direct stack");
		// LogOut << "returning `" <<  find->GetWhereFrom() << "'\n" ;
		return find->GetWhereFrom();
	}
	// LogOut << "RootMenuView::menu_stack_name(" << ix << ")\n" ;
	int last_select = active_menu->active()->level();
	last_select += active_menu->stack_offset();
	// LogOut << "last_select = " << last_select << "\n" ;
	const StackMenuList& stack = active_menu->get_menu_stack();
	return stack.name_from_level(last_select,ix);
	// return active_menu->get_menu_stack_name(last_select-ix);
}


int RootMenuView::do_menu_command(const char * cmd)
{
	// LogOut << "RootMenuView::do_menu_command(" << cmd << ")\n" ;
	if (!cmd) return 0 ;
	if (!*cmd) return 0 ;
	MenuTreeTraverseObject obj(cmd);
	TheCurrentMenus->find_command(obj);
	if (obj.is_error()) {
		obj.error_message("full menu tree");
		*Output + OutputHelp << "Command not executed.\n" ;
		return 0 ;
	}
	const StackMenuBase * entry = obj.found();
	Menu * men = entry->GetMenu();
	int index = obj.index();
	// MenuLine * line = men->GetIndexedMenuLine(index);
	MenuLine * line = get_menu_line(*men,index);

	switch (line->TheType) {
case MenuTypeCommand:
		// set up menu stack
		direct_command = &(obj.get_stack());
		line->GetDoCommand()->Execute();
		direct_command = 0 ;
		return 1 ;
case MenuTypeMenu:
		Menu * menu = line->GetNewMenu();
		if (!menu) DbgError("RootMenuView::do_command","no menu");
		const char * icon_name = line->Command ;
		// LogOut << "about to copy into new menu_stack.\n" ;
		// obj.get_stack().Dump();
		new_menu(*menu,icon_name,&(obj.get_stack()),obj.size());
/*
 *		MenuView * temp = new MenuView(*menu,session,icon_name,root_window,
 *			&(obj.get_stack()),obj.size());
 */
		return 1 ;
case MenuTypeHelp:
				display_help_file(line->HelpFileName,line->Command);
				return 1 ;
		case MenuTypeInvalid:
		case MenuTypeExtension:
		default:
				DbgError("RootMenuView::do_command","bad menu line type");
				break ;
			}
			return 0 ;
		}

		int MenuView::do_command(const char * cmd)
		{
			// Check if command is in visible menu in main window and is unique

			if (!cmd) return 0 ;
			if (!*cmd) return 0 ;
			root_window.set_active(this);
			MenuTreeTraverseObject obj(cmd);

			StackMenu * a_menu = (StackMenu *) get_menu_stack().find_command(obj);
			if (a_menu) {
				MenuViewLine& line = a_menu->view_line() ;
				// a_menu->Dump() ;
				// LogOut << "index = " << obj.index() << "\n" ;
				HotButton * but = line.button(obj.index()) ;
		if (!but) DbgError("RootMenuView::do_command","no button");
		line.execute_restore(obj.index(),0,but) ;
		but->down_state();
/*
 *		if (line.execute_release_kernel(obj.index(),0,but) &
 *			MenuViewLine::execute_stay_in)
 *			but->state()->set(ivTelltaleState::is_active, true);
 */
		return 1 ;
	}
	// if not check to see if command is unique in menu tree
	return root_window.do_menu_command(cmd);
}

static void WriteResponsePacket(const char * string, InputType typ, void *)
{ 
	PacketHeader ReturnHead(PacketGraphicsStringSend,typ,strlen(string)+1);
	WriteSeg->WritePacket(ReturnHead,string);
}

void RootMenuView::remote_prompt(const char * str)
{
	// if (str) if (*str) help_strings.Append(Concatenate(str));
	UserPrompt * Prompt = new UserPrompt(InputPrompt,str, WriteResponsePacket);
	InputPost(Prompt);

}

void RootMenuView::RemoteServer(OutputType type, const char* str,
		OutputType next)
{
	static OutputType last_type = OutputNotInitialized ;
/*
 *	LogOut << "RemoteServer(" << type << ", \"" << str << "\", " << next <<
 *		")\n" ;
 */
	if (type == OutputNotInitialized) type = last_type ;
	if (str) if (*str) switch (type) {
case OutputHelp:
case OutputCppHelp:
	if (network_edit_mode) edit_info_strings.Append(Concatenate(str));
	else help_strings.Append(Concatenate(str));
	if (type == OutputCppHelp) cpp_scroll(str);
	break ;
case OutputPrompt:
	// We need to accumulate stings in a buffer and then process them
	if (!read_action_file_mode) prompt_strings.Append(Concatenate(str));
	else if (HelpDo.All()) cpp_scroll(str);
	// discard prompt string while reading action file
	break ;
case OutputMenu:
case OutputPlot:
case OutputAcknowledge:
case OutputCppEntry:
/*
 *		TheLog << "RootMenuView::RemoteServer type " << type <<
 *			" not implemented yet.\n" ;
 */
		break ;
case OutputInfo:
	info_strings.Append(Concatenate(str));
	break ;
default:
	DspApplication::dynamic_text(type,str,next);
	break ;
case OutputEndOfOutputTypes:
case OutputNotInitialized:
case OutputUndefined:
		DbgError("RootMenuView::RemoteServer","bad type");
	}
	last_type = type ;
}

void RootMenuView::check_wait_for_dsp()
{
	if (wait_for_dsp_flag) DspApplication::wait_for_dsp();
	wait_for_dsp_flag = 0 ;
}

void RootMenuView::set_wait_for_dsp()
{
	wait_for_dsp_flag = 1 ;
}


void RootMenuView::focus_dpp()
{
	clear_focus();
	if (cpp_txt_window) {
        ScrollFieldEditor *editor =  cpp_txt_window->get_editor();
        if (editor) {
			request_focus(*editor);
		}
    }
}

void RootMenuView::focus_menu()
{
	clear_focus();
	if (menu_txt_window) {
        ScrollFieldEditor *editor =  menu_txt_window->get_editor();
        if (editor) {
			request_focus(*editor);
		}
    }

}

void RootMenuView::focus_buttons()
{
	clear_focus();
}

void RootMenuView::focus_clear()
{
/*
 *	if (menu_txt_window) {
 *		ScrollFieldEditor *editor =  menu_txt_window->get_editor();
 *		if (editor) {
 *			editor->clear_focus();
 *		}
 *	}
 *	if (menu_txt_window) {
 *	ScrollFieldEditor *editor =  menu_txt_window->get_editor();
 * 	if (editor) {
 *		editor->clear_focus();
 *	}
 *	clear_focus();
 */
}

/*
 * void RootMenuView::focus_clear()
 * {
 * if (menu_txt_window) {
 *		ScrollFieldEditor *editor =  menu_txt_window->get_editor();
 *		if (editor) editor->focus_out();
 *	}
 *	if (cpp_txt_window) {
 *		ScrollFieldEditor *editor =  cpp_txt_window->get_editor();
 *		if (editor) editor->focus_out();
 *	}
 * }
 */




