#include <IV-look/kit.h>
#include <InterViews/event.h>
#include <InterViews/action.h>
#include <InterViews/background.h>
#include <InterViews/layout.h>
#include <InterViews/session.h>
#include <InterViews/color.h>
#include <InterViews/border.h>
#include <InterViews/style.h>
#include <InterViews/window.h>
#include <X11/cursorfont.h>
#include <X11/keysym.h>
#include <string.h>
#include "iv_graph.h"
#include "dsp_app.h"
#include "genmenu.h"
#include "cgidbg.h"
#include "mkstr.h"
#include "portable.h"
#include "xk_tab.h"
#include <InterViews/enter-scope.h>
#include <OS/enter-scope.h>
#include "netplot.h"


class WindowMenuNetGraph: public WindowMenu {
	void check_release();
	NetGraph * the_graph ;

	virtual Action * set_action(PullDownEntry * i) ;
public:
	WindowMenuNetGraph(NetGraph * gr):
		WindowMenu(),
		the_graph(gr){}
	void help_display();
	void help_database();
	void help_edit();
	void show_inputs(); 
	void show_outputs(); 
	void show_all(); 
	void clear_show_links(); 
	void enable_edit();
	void disable_edit();
	void redraw_dim();
	void select_home();
	void select_end();
	void select_left();
	void select_right();
	void select_up();
	void select_down();
	void select_none();
	virtual void clear_selected();
	void raise_output_windows();

	void show_label_links();
	void clear_show_label_links();

	void connect_input();
	void connect_output_channel();
	void connect_output_buffer();
	void disconnet_node(); 
	void replace_node();
	void remove_node();

	void node_menu();
	void node_class_menu();
	void network_menu();
	void buffer_descriptor_menu();
	void controller_menu();
	void save_window();
	virtual const char * mouse_selected();
	virtual const char * key_selected();

	virtual void act_select(const char * sel) ;
	virtual void act_deselect() ;
	void clear_graph() {the_graph=0 ;}
};

void WindowMenuNetGraph::act_select(const char * sel)
{
	if (!the_graph) return ;
	the_graph->act_select(sel);
}

void WindowMenuNetGraph::act_deselect()
{
	if (!the_graph) return ;
	the_graph->act_deselect();
}

void WindowMenuNetGraph::clear_selected()
{
	if (!the_graph) return ;
	the_graph->clear_selection();
	the_graph->clear_mouse_selection();
}

const char * WindowMenuNetGraph::key_selected()
{
	return mouse_selected();
}

const char * WindowMenuNetGraph::mouse_selected()
{
	EdibleGlyph * select = the_graph->selection();
	if (!select) return 0 ;
	if (!select->vertical_position()) {
		the_graph->act_deselect();
		return 0 ;
	}
	return select->name();
}

void WindowMenuNetGraph::check_release()
{
	// LogOut << "WindowMenuNetGraph::check_release\n" ;
	the_graph->menu_keyboard()->check_release();
	// LogOut << "WindowMenuNetGraph::check_release exit\n" ;
}

typedef void (WindowMenuNetGraph::*ActionType)();

class ActionWindowMenuNetGraph :  public RecAction  {
	WindowMenuNetGraph * gr ;
	ActionType the_action ;
public:
	ActionWindowMenuNetGraph(MenuKeyboard * key,
		WindowMenuNetGraph * g, PullDownEntry& desc, ActionType a);
	ActionWindowMenuNetGraph(ActionType a):RecAction(0,0),the_action(a){}
	void force_execute() {record(); (gr->*the_action)();}
	void execute() ;
	ActionType action() {return the_action;}
};


ActionWindowMenuNetGraph::ActionWindowMenuNetGraph(MenuKeyboard * key,
	WindowMenuNetGraph * g, PullDownEntry& desc, ActionType a):
		RecAction(key,&desc),
		gr(g),
		the_action(a)
{
	Resource::ref(this);
}

void ActionWindowMenuNetGraph::execute()
{
    if (!DspApplication::user_input_allowed()) return ;
    record();
    (gr->*the_action)();
}


Action * WindowMenuNetGraph::set_action(PullDownEntry * i)
{
	ActionWindowMenuNetGraph * compiler_bug = (ActionWindowMenuNetGraph *)
		i->base_action();

	ActionType compiler_bug_2 = compiler_bug->action() ;

	MenuKeyboard * the_keyboard = keyboard(); 

	ActionWindowMenuNetGraph * this_action = new ActionWindowMenuNetGraph(
		the_keyboard, this, *i, compiler_bug_2);
	i->action(this_action);
	return this_action ;
}

#define declare_WindowMenuNetGraph_member(name) \
static ActionWindowMenuNetGraph name (&(WindowMenuNetGraph::name)) ; \
void WindowMenuNetGraph::name()

declare_WindowMenuNetGraph_member(help_display)
{
	DspApplication::display_help_file("show_links");
	check_release();
}

declare_WindowMenuNetGraph_member(help_database)
{
	DspApplication::display_help_file("net_database");
	check_release();
}

declare_WindowMenuNetGraph_member(help_edit)
{
	DspApplication::display_help_file("net_edit");
	check_release();
}

declare_WindowMenuNetGraph_member(show_inputs)
{
	the_graph->show_selected_inputs();
	check_release();
}
 
declare_WindowMenuNetGraph_member(show_outputs)
{
	the_graph->show_selected_outputs();
	check_release();
}
 
declare_WindowMenuNetGraph_member(show_all)
{
	the_graph->show_selected_inputs();
	the_graph->show_selected_outputs();
	check_release();
}
 
declare_WindowMenuNetGraph_member(clear_show_links)
{
	the_graph->clear_show_selected_links();
}

declare_WindowMenuNetGraph_member(enable_edit)
{
	the_graph->enable_edit();
	check_release();
}

declare_WindowMenuNetGraph_member(redraw_dim)
{
	the_graph->redraw_dim();
	check_release();
}

declare_WindowMenuNetGraph_member(disable_edit)
{
	the_graph->disable_edit();
	check_release();
}

declare_WindowMenuNetGraph_member(select_home)
{
	the_graph->select_home();
	check_release();
}

declare_WindowMenuNetGraph_member(select_end)
{
	the_graph->select_end();
	check_release();
}

declare_WindowMenuNetGraph_member(select_left)
{
	the_graph->select_left();
	check_release();
}

declare_WindowMenuNetGraph_member(select_right)
{
	the_graph->select_right();
	check_release();
}

declare_WindowMenuNetGraph_member(select_up)
{
	the_graph->select_up();
	check_release();
}

declare_WindowMenuNetGraph_member(select_down)
{
	the_graph->select_down();
	check_release();
}

declare_WindowMenuNetGraph_member(select_none)
{
	the_graph->select_none();
	check_release();
}

declare_WindowMenuNetGraph_member(connect_input)
{
	the_graph->connect_selected_input();
	check_release();
}

declare_WindowMenuNetGraph_member(show_label_links)
{
	the_graph->show_label_links();
	check_release();
}

declare_WindowMenuNetGraph_member(clear_show_label_links)
{
	the_graph->clear_show_label_links();
	check_release();
}

declare_WindowMenuNetGraph_member(connect_output_channel)
{
	the_graph->connect_selected_output();
	check_release();
}

declare_WindowMenuNetGraph_member(connect_output_buffer)
{
	the_graph->connect_selected_buffer();
	check_release();
}

declare_WindowMenuNetGraph_member(disconnet_node)
{
	the_graph->disconnect_selected();
	check_release();
}
 
declare_WindowMenuNetGraph_member(replace_node)
{
	the_graph->replace_selected();
	check_release();
}

declare_WindowMenuNetGraph_member(remove_node)
{
	the_graph->remove_selected();
	check_release();
}

declare_WindowMenuNetGraph_member(node_menu)
{
	the_graph->selected_node_menu();
	check_release();
}

declare_WindowMenuNetGraph_member(node_class_menu)
{
	the_graph->selected_node_class_menu();
	check_release();
}

declare_WindowMenuNetGraph_member(controller_menu)
{
	the_graph->controller_menu();
	check_release();
}

declare_WindowMenuNetGraph_member(save_window)
{
	the_graph->print_window_raise();
	check_release();
}

declare_WindowMenuNetGraph_member(buffer_descriptor_menu)
{
	the_graph->show_buffer_descriptor_menu();
	check_release();
}

declare_WindowMenuNetGraph_member(raise_output_windows)
{
	the_graph->raise_output_windows();
	check_release();
}

declare_WindowMenuNetGraph_member(network_menu)
{
	the_graph->network_menu();
	check_release();
}



static PullDownDescribe help_menu[] = {
	{"network display",XK_F6,&help_display},
	{"menu database",XK_F7,&help_database},
	{"editing",XK_F8,&help_edit},
	{0}
};

#define EN PullDownDescribe::none
#define MD X_Character::down
#define MS X_Character::shift
#define MC X_Character::ctrl
#define MA X_Character::any
#define ML X_Character::left
#define MM X_Character::middle
#define MR X_Character::right

#define the_enable_edit_key XK_Tab
#define the_disable_edit_key (XK_s_ + XK_Tab)

const int NetGraph::enable_edit_key = the_enable_edit_key ;
const int NetGraph::disable_edit_key = the_disable_edit_key ;

static PullDownDescribe select_menu[] = {
	{"redraw to existing dimensions",XK_s_ + XK_d, &redraw_dim},
	{"enable editing", the_enable_edit_key, &enable_edit},
	{"disable editing", the_disable_edit_key, &disable_edit},
	{"select upper left", XK_Home, &select_home},
	{"select lower right", XK_End, &select_end},
	{"select left",XK_Left,&select_left},
	{"select right",XK_Right,&select_right},
	{"select up",XK_Up,&select_up},
	{"select down",XK_Down,&select_down},
	{"select end",XK_s_ + XK_End,&select_none},
	{"raise selected outputs", XK_W, &raise_output_windows},
	{0}
};


static PullDownDescribe connect_menu[] = {
	{"show label links", XK_plus, &show_label_links},
	{"clear show label links", XK_minus, &clear_show_label_links},
	{"connect input", XK_I, &connect_input,0,EN,MS + ML},
	{"connect output channel", XK_O, &connect_output_channel, 0, EN, MS + MM},
	{"connect output buffer", XK_B, &connect_output_buffer, 0, EN, MS + MR},
	{"disconnect node", XK_c_ + XK_Delete, &disconnet_node,0,EN, MC + MS + ML}, 
	{"replace node",XK_c_ + XK_R, &replace_node, 0, EN, MC + MS + MR},
	{"remove unlinked node", XK_Delete, &remove_node, 0, EN, MC + MS + MM},
	{"show inputs selected", XK_i, &show_inputs,0,EN,MD + ML}, 
	{"show outputs selected", XK_o, &show_outputs,0,EN,MD + MR}, 
	{"show all links selected", XK_a, &show_all, 0, EN, MD + MM}, 
	{"clear show links selected", XK_space, &clear_show_links,0, EN, MA},
	{0}
};

static PullDownDescribe database_menu[] = {
	{"network menu", XK_c_ + XK_N, &network_menu, },
	{"node menu", XK_c_ + XK_n, &node_menu, 0, EN, MC + ML},
	{"node class menu", XK_c_ + XK_c, &node_class_menu, 0 , EN, MC + MR},
	{"buffer descriptor menu", XK_c_ + XK_b, &buffer_descriptor_menu},
	{"save window image", XK_s_ + XK_c_ + XK_8, &save_window},
	{"controller menu", XK_c_ + XK_C, &controller_menu},
	{0}
};

static PullDownDescribe net_graph_main_menu[] = {
	{ "Help",XK_F1,nil,help_menu},
	{ "Select",XK_F2,nil,select_menu},
	{ "Link",XK_F3,nil,connect_menu},
	{ "Data base", XK_F4, nil, database_menu},
	{0}
};

static PullDownDescribe net_graph_menu_tree = {0,0,0,net_graph_main_menu};

MenuKeyboard * NetGraph::build_menu(WidgetKit& kit, const LayoutKit& layout,
		Style * style, NetGraph&)
{
	// LogOut << "NetGraph::build_menu\n" ;
	// const Color * black = Color::lookup(DspApplication::display(), "black") ;
   //  PullDownEntry * entry = new PullDownEntry(net_graph_menu_tree);
	WindowMenuNetGraph * menu_window = new WindowMenuNetGraph(this) ;
	return new MenuKeyboard(kit,layout, style,menu_window, net_graph_menu_tree);
}

void NetGraph::act_select(const char * sel)
{
	prefer_mouse = 0 ;
	the_mouse_selection = 0 ;
	if (the_selection) the_selection->unselect();
	the_selection = glyphs.select(sel);
	
}

void NetGraph::act_deselect()
{
	the_selection = 0 ;
}
