#include <math.h>
#include <string.h>
#include <IV-look/kit.h>
#include <InterViews/label.h>
#include <InterViews/session.h>
#include <InterViews/style.h>
#include <InterViews/window.h>
#include <InterViews/layout.h>
#include <InterViews/polyglyph.h>
#include <InterViews/brush.h>
#include <InterViews/canvas.h>
#include <strstream.h>

#include "netplot.h"
#include "genmenu.h"

#include "newaloc.h"
#include "mkstr.h"
#include "netdescg.h"
#include "linlist.h"
#include"cgidbg.h"
#include "dsp_app.h"
#include "editnet.h"
#include "remcom.h"
#include "mpacket.h"
#include "editnet.h"
#include "shared.h"
#include "xdrv.h"
#include "xgui.h"
#include <InterViews/enter-scope.h>

// void TestAlloc(const char * Msg=0);
static const char *** label_names = 0 ;

static int level_index = 0 ;
static int label_index = 0 ;

static const label_limit = 26 ;
static int level_limit = 0 ;

implementEditLinearList(NodeDescription)
implementEditLinearList(BufferDescription)

void NodeDisplayParameters::clear_labels()
{
	label_index = 0 ;
	label_index = 0 ;
}

const char * NodeDisplayParameters::next_label()
{
	// LogOut << "NodeDisplayParameters::next_label enter\n" ;
	for(;;) {
/*
 *		LogOut << "level_index = " << level_index << ", limit = " <<
 *			level_limit << "\n" ;
 */
		if (level_index < level_limit) {
/*
 *			LogOut << "label_index = " << label_index << ", limit = " <<
 *				label_limit << "\n" ;
 */
			if (label_index < label_limit) {
				const char * Return = label_names[level_index] [label_index++] ;
/*
 *				LogOut << "NodeDisplayParameters::next_label returning \"" <<
 *					Return << "\"\n" ;
 */
				return Return ;
			}
			label_index = 0 ;
			level_index++;
			continue ;
		}
		char * base = 0 ;
		if (level_index) {
			const char * from = label_names[level_index-1][0] ;
			int length = strlen(from);
			for (int ck = length-2; ck > -1; ck++) {
				if (from[ck] < 'Z') {
					base = Concatenate(from);
					base[length-1] = 0 ;
					base[ck++]++ ;
					for (; ck < length-1 ; ck++) base[ck] = 'A' ;
				} else {
					base = new char[length+2] ;
					for (int i = 0 ; i <= length+1; i++) base[i] = 'A' ;
				}
			}
		}
		const char *** temp = new char **[level_limit+1];
		for (int i = 0 ; i < level_limit;i++) temp[i] = label_names[i] ;
		delete label_names ;
		label_names = temp ;
		char ** new_row = new char *[label_limit] ;
		label_names[level_limit++] = new_row ;
		int length = strlen(base) + 1;
		char c_b[2] ;
		strcpy(c_b,"A") ;
		for (i = 0 ; i < label_limit;i++) {
			new_row[i] = new char[length+1];
			strcpy(new_row[i],base);
			strcat(new_row[i],c_b);
			c_b[0]++;
		}
		delete base ;
	}
}

NodeDisplayParameters::NodeDisplayParameters(NodeDescription& nd):
	the_node(nd)
{
	clear();
}

int NodeDisplayParameters::current_input_channel() const
{
	if (!the_current_driver) {
		// LogOut << "no current driver\n" ;
		return -1 ;
	}
	NodeDisplayParameters*  param = the_current_driver->display_parameters();
	const BufferDescription * buf= 0;
	if (param) buf = the_current_driver->buffer(param->channel());
	if (!param || !buf) {
		TheLog << "param = " << (void *) param << ", buf = " << (void *) buf
			<< "\n" ;
		DbgError("NodeDisplayParameters::current_input_channel","null ptr");
	}
	// LogOut << "channel = " <<  param->buffer_channel() << "\n" ;
	return buf->destination_channels()[param->buffer_channel()];
}

NodeDescription::NodeDescription(GenericArrayElement_LinearList *l):
		the_next_input(0),
		the_next_output(0),
		NetNodeDescription(l),
		the_node_glyph(0),
		the_displayed_buffer(0),
		display_param(0),
		buffers(0)
{
	if (is_linked()) display_param = new NodeDisplayParameters(*this);
}

NodeDescription::NodeDescription(const char * class_nm, const char * node_nm,
	int inputs, int outputs):
		NetNodeDescription(class_nm,node_nm,inputs,outputs),
		the_next_input(0),
		the_next_output(0),
		the_node_glyph(0),
		the_displayed_buffer(0),
		display_param(0),
		buffers(0)
{
/*
 *	LogOut << "NodeDescription::ctr(\"" << class_nm << "\", \"" << node_nm
 *		<< "\", " << inputs << ", " << outputs << ")\n" ;
 */
}
		

NodeDescription::~NodeDescription()
{
	// LogOut << "NodeDescription dtor `" << name() << "'\n" ;
	delete buffers ;
	delete display_param ;
}

void NodeDescription::draw_connect_all(Canvas* c, const Allocation& a,
	const NodeConnector *conn) const
{
	if (the_next_output) the_next_output->draw_to(c,conn);
	if (the_next_input) the_next_input->draw_from(c);
}

int NodeDescription::identical_channels(NodeDescription& check)
{
	if (in() != check.in()) return 0 ;
	if (out() != check.out()) return 0 ;
	return 1 ;
}

void NodeDescription::next_input(EdibleInputLabel * lab)
{
/*
 *	LogOut << "NodeDescription::next_input for `" << name() << "', lab = " <<
 *		(void *) lab << "\n" ;
 */
	if (the_next_input) lab->next_input(the_next_input);
	the_next_input = lab ;
}

void NodeDescription::next_output(EdibleOutputLabel * lab)
{
/*
 *	LogOut << "NodeDescription::next_output for `" << name() << "', lab = " <<
 *		(void *) lab << "\n" ;
 */
	if (the_next_output) lab->next_output(the_next_output);
	the_next_output = lab ;
}

BufferDescription * NodeDescription::buffer(int i) const
{
	if (!buffers) return 0 ;
	if ((i < 0) || (i >= out())) return 0 ;
	return buffers[i] ;
}

NodeDescription * NodeDescription::current_node_driven()
{
	if (!display_param) return 0 ;
	BufferDescription * current_buffer = buffer(display_param->channel());
	if (!current_buffer) return 0 ;
	return current_buffer->driven_node(display_param->buffer_channel());
}

EdibleOutputLabel * NodeDescription::driver_output_label(TraverseObj& obj)
{
 	// LogOut<<"NodeDescription::driver_output_label for '" << name() << "'\n" ;
	NodeDescription * driver = display_parameters()->current_driver();
	if (!driver) DbgError("NodeDescription::driver_output_label","no_driver");

	EdibleOutputLabel * Return =
		new EdibleOutputLabel(obj, *driver);
	return Return ;
}

void NodeDescription::terminate_branch(TraverseObj& obj)
{
	int input_channel = display_parameters()->current_input_channel();
	EdibleInputLabel * input_lab = new EdibleInputLabel(obj,*this,
		input_channel);
	if (!obj.is_start_line() && obj.is_room_for(input_lab)) {
		obj.vertical_position()->append(*input_lab);
		obj.clear_last_connect();
		return ;
	}
	obj.add(driver_output_label(obj),input_lab);
	obj.clear_last_connect();
}

void NodeDescription::traverse(TraverseObj& obj)
{
	// LogOut << "traversing node `" << name() << "'\n" ;
	if (display_param->traverse_standard()) {
		terminate_branch(obj);
		// LogOut << "standard terminate\n" ;
		return ;
	}
	display_param->set_traverse_standard();
	// display_param->link();
	NodeMemberFunction func = obj.action();
	int not_done = 1 ;
	if (buffers) for (int i = 0 ; i < out(); i++) {
		if (i) display_param->next_channel();
		BufferDescription * buf = buffers[i];
		if (!buf) continue ;
		if (not_done) (this->*func)(obj);
		not_done = 0 ;
		buf->traverse(obj);
		if (obj.error()) break ;
	}
	if (not_done) (this->*func)(obj);
}

void NodeDescription::clear_traverse() const
{
	if (!display_param->traverse_standard()) return ;
	display_param->clear();
	if (buffers) for (int i = 0 ; i < out(); i++) {
        BufferDescription * buf = buffers[i];
		if (!buf) continue ;
		buf->clear_traverse();
	}
}

void NodeDescription::display_network(TraverseObj& obj)
{
/*
 *	LogOut << "NodeDescription::display_network\n" ;
 *	LogOut << "channel = " << display_parameters()->channel() << ", buf chan = "
 *		<< display_parameters()->buffer_channel() << "\n" ;
 */
	NodeConnector * conn = 0 ;
	NodeGlyph* node_glyph = new NodeGlyph(*this,obj.kit(),obj.layout(),
		obj.style());
	if (buffers) if (out()) {
		for (int i = 0 ; i < out() ; i++) if (buffers[i]) break ;
		if (i < out()) {
			conn = new NodeConnector(i,obj,*this,buffers[i]->driven_node(0));
			displayed_buffer(conn);
		}
	}
	obj.add(*this, node_glyph, conn);
}


void NodeDescription::color_input_labels(const Color *color)
{
/*
 * 	LogOut << "color for `" << name() << "', the_next_input = " <<
 *		(void *) the_next_input << "\n" ;
 */
	if (the_next_input) the_next_input->color_input_labels(color);
}

void NodeDescription::color_output_labels(const Color *color)
{
/*
 *	LogOut << "color for `" << name() << "', the_next_output = " <<
 *		(void *) the_next_output << "\n" ;
 */
	if (the_next_output) the_next_output->color_output_labels(color);
}

void NodeDescription::clone_from(NodeDescription&nd)
{
	the_next_input = nd.next_input();
	the_next_output = nd.next_output();
	the_displayed_buffer = nd.displayed_buffer();
	if (the_next_input) the_next_input->new_node(*this);
	if (the_next_output) the_next_output->new_node(*this);

	buffers = nd.get_buffer_array();
	int i ;
	if (buffers) for (i = 0 ; i < out(); i++) buffers[i]->driver_node(this);

	NetworkDescriptionFull& full=the_node_glyph->graph().network_description();
	the_node_glyph->ref();
	driver_names = nd.drivers();
	if (driver_names) for (i = 0 ; i < in() ; i++) {
		if (driver_names[i]) full.change_driven(driver_names[i],nd,*this);
	}
}

void NodeDescription::clear_connections()
{
	the_next_input = 0 ;
	the_next_output = 0 ;
	the_displayed_buffer = 0 ;
	buffers = 0 ;
	driver_names = 0 ;
}

void NodeDescription::change_driven(NodeDescription& old_node,
	NodeDescription& new_node)
{
	if (buffers) for (int i = 0 ; i < out(); i++) if (buffers[i])
		buffers[i]->change_driven(old_node,new_node);
}

int NodeDescription::in_channel_for(const char * name)
{
	if (!name) return -1 ;
	if (!*name) return -1 ;
	if (!driver_names) return -1 ;
	for (int i = 0 ; i < input_channels ; i++) if (driver_names[i])
		if (!strcmp(driver_names[i],name)) return i;
	return -1 ;
}

int NodeDescription::new_buffer_output(EditLink& driver, EditLink& driven)
{
	int size = out();
	if (size < 1) return -1 ;
	if (!buffers) {
		buffers = new BufferDescription * [size] ;
		for (int i = 0 ; i < size;i++) buffers[i] = 0 ;
	}
	int channel = driver.channel();
	if (!buffers[channel]) buffers[channel] =
		new BufferDescription(channel,name()) ;
	int Return = buffers[channel]->link(driven);
	return Return ;
}

void NodeDisplayParameters::clear()
{
	channel_index = buffer_channel_index = 0 ;
	the_traverse_flags = none ;
	the_current_driver = 0 ;
}

void NodeDisplayParameters::next_buffer_channel()
{
	if (buffer_channel_index < the_node.buffer(channel_index)->out()-1)
		buffer_channel_index++ ;
}

void NodeDisplayParameters::next_channel()
{
	buffer_channel_index = 0 ;
	if (channel_index < the_node.out()-1) channel_index++ ;
}

char * NodeDisplayParameters::node_channel_name() const
{
	// LogOut << "NodeDisplayParameters::node_channel_name\n" ;
	const BufferDescription& drive_buffer =
		*(the_node.buffer(channel_index));
	int buffer_channels = drive_buffer.out();
	// LogOut << "buffer_channels = " << buffer_channels << "\n" ;

	char * first_index = 0 ;
	char * buffer_index = 0 ;
	if (channel_index) first_index =
		Concatenate(" ",DspApplication::int_string(channel_index));
	if (buffer_channel_index) {
		char * tmp =
			Concatenate(" B", DspApplication::int_string(buffer_channel_index));
		if (first_index) buffer_index = tmp;
		else first_index = tmp ;
	}
	char * input_name = Concatenate(" ",the_node.name(),
		first_index,buffer_index);
	delete first_index ;
	delete buffer_index ;
	return input_name ;
}

NetworkDescriptionFull::NetworkDescriptionFull( NetDescription& n,
		NodeDescription_LinearList& edit_nodes):
			the_net(n),
			the_nodes(edit_nodes),
			buffers(* new BufferDescription_LinearList),
			the_graph(0),
			window(0),
			now_in_resize(0),
			complete_flag(0),
			the_net_glyph(0),
			x_size(-1),
			y_size(-1),
			in_map(0)
{
	ivResource::ref(this);
}




NetworkDescriptionFull::NetworkDescriptionFull( NetDescription& n,
		NodeDescription_LinearList& all_nodes,
		BufferDescription_LinearList& all_buffers,int16 x, int16 y):
			the_net(n),
			the_nodes(all_nodes),
			buffers(all_buffers),
			the_graph(0),
			window(0),
			now_in_resize(0),
			complete_flag(0),
			x_size(x),
			the_net_glyph(0),
			y_size(y)
{
	ivResource::ref(this);
	int complete = 1 ; /* the_nodes.number()  ; */
	NodeDescription_LinearList the_signals ;
	the_nodes.next(0);
	NodeDescription * node ;
	while (node = the_nodes.next()) 
		if (!node->drivers()) if (node->is_linked()) the_signals.add(node);

	// find all signal nodes
	NodeDescription ** sig =
		new NodeDescription * [the_signals.number()+1];
	the_signals.next(0);
	for (int i= 0 ; (node=the_signals.next());i++) sig[i]=node ;
	sig[i] = 0 ;
	the_net.set_signals(sig);

	// establish links from buffers to the nodes they drive 
	buffers.next(0);
	BufferDescription * buf ;
	while (buf = (BufferDescription *) buffers.next()) {
		const char ** the_names = buf->destinations();
		NodeDescription ** dest_nodes =
			new NodeDescription *[ListLength((void **)the_names)+1];
		const NodeDescription ** dest_ptr = dest_nodes ;
		for (const char ** dest = the_names; *dest;dest++) {
			node = the_nodes.find(*dest);
			if (!node) DbgError("NetworkDescriptionFull::ctor","no node");
			*dest_ptr++ = node ;
		}
		*dest_ptr = 0 ;
		buf->set_nodes(dest_nodes);
	}

	// establish links from nodes to buffers they feed and back
	// this requires searching all buffers for the name of the single
	// node driving each buffer
	NodeDescription * a_node ;
	the_nodes.next(0);
	while (a_node = (NodeDescription *) the_nodes.next()) {
		if (!a_node->is_linked()) continue ;
		int size = a_node->out() ;
		BufferDescription ** out_bufs =
			new BufferDescription *[size];
		for (int i = 0 ; i < size;i++) out_bufs[i] = 0 ;
		buffers.next(0);
		BufferDescription * buf ;
		while (buf = buffers.next()) 
			if (!strcmp(buf->driver(),a_node->name())) {
				((BufferDescription *)buf)->driver_node(a_node);
				int pos = buf->channel_in_driver() ;
				int error = 1 ;
				if (pos < size) if (!out_bufs[pos]) error = 0 ;
				if (error) DbgError("NetworkDescriptionFull::ctor",
					"bad buffer link");
				out_bufs[pos]=buf ;
		}
		for (i = 0 ; i < size;i++) if (out_bufs[i]) break ;
		if (i >= size) {
			delete out_bufs ;
		}
		else a_node->set_buffers(out_bufs);
	}
	complete_flag = complete ;
}

void NetworkDescriptionFull::unmap()
{
	if (!window) return ;
	Window * win = window ;
	window = 0 ;
	DspApplication::network_manager()->removing(this);
    if (win->is_mapped()) {
		win->unmap();
	}
	// delete win ;
	// delete graph();
}

NetworkDescriptionFull::~NetworkDescriptionFull()
{
	// LogOut<<"NetworkDescriptionFull::~NetworkDescriptionFull\n" ;
	the_net_glyph->clear_full();
	// LogOut<<"NetworkDescriptionFull::dtor for "<<the_net.net_name()<<"\n";
	delete &the_net ;

	the_nodes.next(0);
	NodeDescription * nd ;
	while (nd = the_nodes.next()) delete nd ;
	delete &the_nodes ;

	buffers.next(0);
	BufferDescription * bf ;
	delete &buffers ;
}

void NetworkDescriptionFull::resize()
{
	now_in_resize = 1 ;
	// LogOut << "NetworkDescriptionFull::resize: 1\n" ;
	if (!window->is_mapped()) return ;
	// LogOut << "NetworkDescriptionFull::resize: 2\n" ;
	Canvas * c = window->canvas();
	// LogOut << "NetworkDescriptionFull::resize: 3\n" ;
	if (c) c->damage_all();
	// LogOut << "NetworkDescriptionFull::resize: 4\n" ;
	window->resize();
	// LogOut << "NetworkDescriptionFull::resize: 5\n" ;
	now_in_resize = 0 ;
}


static const Coord do_not_position = 1.e10 ;

Coord NetworkDescriptionFull::height() const
{
	if (net_glyph()) return net_glyph()->height();
	if (y_size > 0) return y_size ;
	return NetworkGlyph::default_height ;
}

Coord NetworkDescriptionFull::width() const
{
	if (net_glyph()) return net_glyph()->width();
	if (x_size > 0) return x_size ;
	return NetworkGlyph::default_width ;
}

void NetworkDescriptionFull::make_window(Coord left, Coord bottom, int edit)
{
	// LogOut << "NetworkDescriptionFull::make_window\n" ;
	in_map = 1 ;
	Style * net_plot_style = new ivStyle(ivSession::instance()->style());
	net_plot_style->attribute("name",name());
	net_plot_style->attribute("iconName",name());
	the_graph = new NetGraph(*this,net_plot_style);
	the_net_glyph =new NetworkGlyph(*this); // depends on `the_graph' 
	window = new TopLevelWindow(the_net_glyph);
	the_graph->window(window,the_graph->menu_keyboard(),0);
	the_graph->menu_keyboard()->window(window,the_graph->menu_keyboard(),0);

	window->style(net_plot_style);
	window->group_leader(window);
	if (left != do_not_position && bottom != do_not_position) {
/*
 *		LogOut << "H = " << window->height() << ", l = " <<
 *			left << ", t = " << bottom << "\n" ;
 */
		window->place(left,bottom);
	}
	window->map();
	int enable = 0 ;
	RootMenuView * root = DspApplication::root_window() ;
	while (!window->is_mapped()) {
		if (!root->remote_com_disallowed()) {
			// LogOut << "remote com allowed\n" ;
			root->disable_remote_com();
			enable = 1 ;
		}
		for (int i = 0; i < 100;i++) DspApplication::event_check();
	}
	if (enable) root->enable_remote_com();
	the_graph->add_unlinked_nodes();
	in_map = 0 ;
	ivResource::unref(); // is now referenced from the_net_glyph
}

void NetworkDescriptionFull::new_node(NodeDescription * node)
{
	the_nodes.add(node);
	add_unlinked_node_to_network(node);
}

void NetworkDescriptionFull::add_unlinked_node_to_network(NodeDescription * node)
{
	int buf_size = strlen(node->name()) + strlen(name()) + 2;
	if (buf_size >= MaxPacketSize) {
		DspApplication::flush_help_info();
		*Output + OutputInfo <<
			"Warning:Total length of network and node names:\n`"
			<< name() << "' and`\n" << node->name() << "'\n" 
			<< "is greater then " << MaxPacketSize <<
			". There may be descrepencies between the network display " <<
			"and the network state.\n" ;
		DspApplication::write_help_info();
		return ;
	}
	char * buf = new char[buf_size] ;
    for (int i = 0 ; i < buf_size; i++) buf[i] = '\0' ;
    strcpy(buf,name());
    strcpy(buf+strlen(buf) + 1,node->name());
    PacketHeader head(PacketNetworkEdit,CppEnums::add_unlinked_node_to_network,
        buf_size);
    WriteSeg->WritePacket(head,buf);
    // LogOut << "Sent packet to add_unlinked_node_to_network\n" ;
    delete buf ;
}

void NetworkDescriptionFull::raise_window_node(const char * node_name)
{
	// LogOut<<"NetworkDescriptionFull::raise_window_node("<<node_name<<")\n" ;
	if (!window) return ;
	the_nodes.next(0) ;
	NodeDescription * node ;
	while (node = the_nodes.next()){
		// LogOut << "Checking `" << node->name() << "'\n" ;
		 if (!strcmp(node->name(),node_name)) {
			window->raise();
			return ;
		}
	}
}

int NetworkDescriptionFull::using_node(const char * node_name)
{
	the_nodes.next(0);
	NodeDescription * nod ;
	while (nod = the_nodes.next()) if (!strcmp(nod->name(),node_name)) return 1;
	return 0 ;
}

void NetworkDescriptionFull::Remove(NodeDescription& node, int delete_flag)
{
	NodeDescription * find ;
	the_nodes.next(0);
	for (long index = 0 ;find = the_nodes.next();index++)
	  if (find == &node) {
			the_nodes.Remove(index);
			if (delete_flag) {
				delete find ;
			}
			return ;
	}
}

void NetworkDescriptionFull::delete_node(const char * name)
{
	NodeDescription * find ;
	the_nodes.next(0);
	for (long index = 0 ;find = the_nodes.next();index++)
	  if (!strcmp(find->name(),name)) {
		NodeGlyph *gl = find->node_glyph();
		if (gl) if (the_graph) {
			the_graph->delete_node(gl)  ;
			return ;
		}
		the_nodes.Remove(index);
		delete find ;	
	}
}

void NetworkDescriptionFull::change_driven(const char * driver_name,
	NodeDescription& old_node, NodeDescription& new_node)
{
	NodeDescription * node ;
	the_nodes.next(0);
	while (node = the_nodes.next()) if (!strcmp(node->name(),driver_name)) {
		node->change_driven(old_node,new_node);
		break ;
	}
}


void NetworkDescriptionFull_LinearList::replace(
	NetworkDescriptionFull * rep)
{
	long rep_index = next_index() - 1 ;
	if (rep_index >= number() || rep_index < 0) DbgError(
		"NetworkDescriptionFull_LinearList::replace","bad count");
	NetworkDescriptionFull * old =  get(rep_index);
	DspApplication::network_manager()->unedit(old->graph());
	old->unmap() ;
	LinearList::replace(rep,rep_index);
}

NodeDescription * NodeDescription_LinearList::find(const char * name) const
{
	for (int i = 0 ; i < number() ;i++) if (!strcmp(name,get(i)->name()))
		return get(i);
	return 0 ;
}

NetDescription::NetDescription(const char * nm, const char * cntrl):
	NetworkDescription(nm,cntrl),
	signal_nodes(0)
{
}

NetDescription::~NetDescription()
{
	delete signal_nodes ;
}


void NetDescription::clear_traverse() const
{
	for (const NodeDescription ** sig = signal_nodes; *sig;sig++)
		(*sig)->clear_traverse();
}

void NetDescription::traverse(TraverseObj &obj)
{
	clear_traverse();
	for (NodeDescription **sig = signal_nodes; *sig;sig++) {
		if (!(*sig)->is_linked()) continue ;
		(*sig)->traverse(obj);
		if (obj.error()) break ;
	}
	clear_traverse();
	obj.vertical_glyphs_append();
}

BufferDescription::BufferDescription(int drv_chan,const char * drv_nm):
	NetBufferDescription(drv_chan,drv_nm),
	driven(0),
	the_driver(0)
{
}
	
BufferDescription::~BufferDescription()
{
	delete driven ;
}

void BufferDescription::clear_traverse() const
{
	for (const NodeDescription ** nd = driven; *nd; nd++)
		(*nd)->clear_traverse();
}

void BufferDescription::traverse(TraverseObj& obj)
{
	if (driven) for (NodeDescription ** nd = driven; *nd;nd++) {
		if (nd != driven) the_driver->display_parameters()
			->next_buffer_channel();
		// LogOut << "the_driver = " << (void *) the_driver << "\n" ;
/*
 *		LogOut << "the current driver for `" << (*nd)->name() << "' is `"
 *			<< the_driver->name() << "'\n" ;
 */
		NodeDisplayParameters& to_set = *((*nd)->display_parameters());
		to_set.current_driver(the_driver);
		(*nd)->traverse(obj);
		if (obj.error()) break ;
	}
}

NodeDescription * BufferDescription::driven_node(int i)
{
	if (!driven) return 0 ;
	if ((i < 0) || (i >= out())) return 0 ;
	return driven[i] ;
}

void BufferDescription::change_driven(NodeDescription& old_node,
	NodeDescription& new_node)
{
	for (int i = 0 ; i < number_outputs ; i++)
		if (driven[i] == &old_node) driven[i] = &new_node;
}

int BufferDescription::link(EditLink& to)
{
	int size = number_outputs + 1 ;
	NodeDescription ** new_driven = new NodeDescription *[size];
	const char ** new_destination_names = new char *[size];
	int * new_destination_input_channels = new int [size];
	for (int i = 0 ; i < number_outputs; i++) {
		new_driven[i] = driven[i] ;
		new_destination_names[i] = destination_names[i];
		new_destination_input_channels[i] = destination_input_channels[i];
	}
	NodeDescription& node = to.glyph.node();
	new_driven[number_outputs] = &node ;
	new_destination_names[number_outputs] = node.name();
	new_destination_input_channels[number_outputs] = to.channel() ;
	delete driven ;
	delete destination_names ;
	delete destination_input_channels ;
	driven = new_driven ;
	destination_names = new_destination_names;
	destination_input_channels = new_destination_input_channels;
	return ++number_outputs ;
}


NetworkDisplayManager::NetworkDisplayManager():
	nodes_awaiting_network(new NodeDescription_LinearList),
	the_nodes(new NodeDescription_LinearList),
	the_buffers(new BufferDescription_LinearList),
	type(none),
	the_net(0),
	edit_graph(0),
	x_size(-1),
	y_size(-1)
{
}


NetworkDisplayManager::~NetworkDisplayManager()
{
	nodes_awaiting_network->delete_all();
	
	delete nodes_awaiting_network ;

	the_nodes->delete_all();
	delete the_nodes ;

	the_buffers->delete_all();
	delete the_buffers ;
	delete the_net ;
}

void NetworkDisplayManager::queue_rebuild(NetworkDescriptionFull * net)
{
/*
 *	LogOut << "NetworkDisplayManager::queue_rebuild enter, " << net->name()
 *		<< "\n" ;
 */
	the_networks_to_rebuild.next(0);
	NetworkDescriptionFull * full ;
    while(full = the_networks_to_rebuild.next()) if (full == net) return ;
	the_networks_to_rebuild.add(net);
}

void NetworkDisplayManager::check_rebuild()
{
	NetworkDescriptionFull * full ;
	int index = 0 ;
/*
 *	LogOut << "check_rebuild list is:\n" ;
 *
 *   while(full = the_networks_to_rebuild.get(index++)) LogOut <<
 *		full->name() << "\n" ;
 *		index = 0 ;
 */
    while(full = the_networks_to_rebuild.get(index))
	  if (full->net_glyph()->rebuild()) {
			the_networks_to_rebuild.Remove(index)  ;
			return ;
		}
}

int NetworkDisplayManager::prepare_rebuild(NetGraph * to)
{
	if (to != edit_graph) return !DspApplication::is_busy() ;
	if (!clear_edit()) return 0 ;
	edit_graph = to ; // want to restore position of existing graph
	return 1 ;
}

int NetworkDisplayManager::unedit(NetGraph * to_edit)
{
/*
 *	LogOut << "to_edit = " << (void *) to_edit << ", edit_graph = " <<
 *		(void *) edit_graph  << "\n" ;
 */
	if (to_edit != edit_graph) return 0 ;
	edit_graph = 0 ;
	return 1 ;
}

int NetworkDisplayManager::clear_edit()
{
	if (!edit_graph) return 1 ;
	if (DspApplication::is_busy()) return 0 ;
	if (!edit_graph->clear_edit()) return 0 ;
	edit_graph = 0 ;
}

int NetworkDisplayManager::edit(NetGraph * to_edit)
{
	// LogOut << "NetworkDisplayManager::edit(" << (void *) to_edit << ")\n" ;
	// LogOut << "edit_graph = " << (void *) edit_graph << "\n" ;
	if (DspApplication::state()->IsBusy()) return 0 ;
	// LogOut << "not busy\n" ;
	if (edit_graph) {if (!edit_graph->clear_edit()) return 0;}
	// LogOut << "clear OK\n" ;
	DspApplication::root_window()->no_cpp_entry();
	// LogOut << "no cpp\n" ;
	edit_graph = to_edit ;
	return 1 ;
}



void NetworkDisplayManager::new_network(NetworkDescriptionFull * to_add)
{
	// LogOut << "NetworkDisplayManager::new_network\n" ;
	int make_edit = 0 ;
	Coord new_left_position = do_not_position ;
	Coord new_bottom_position = do_not_position ;
	const NetworkDescriptionFull * net ;
	while (net = the_networks.next())
	  if(!strcmp(to_add->name(),net->name())) {
/*
 *		LogOut << "NetworkDisplayManager::new_network deleting `" <<
 *			net->name() << "'\n" ;
 */

		// check if edit window
		NetGraph * gr = net->graph();
		Window * win = 0 ;
		if (gr) win = gr->window();
		if (win) if (win->is_mapped()) {
			make_edit = gr->is_edit_window();
			new_left_position = win->left();
			new_bottom_position = win->bottom() ;
/*
 *			LogOut << "L = " << win->left << ", B = " <<
 *				win->bottom << ", H = " << win->height() << "\n" ;
 */
		}
		// get location
		// LogOut << "before replace\n" ;
		the_networks.replace(to_add);
		// LogOut << "after replace\n" ;
		break ;
	}
	if (!net) the_networks.add(to_add);
	to_add->make_window(new_left_position, new_bottom_position,make_edit);
	NetGraph * graph = to_add->graph();
	/* if (make_edit) { */
		if (!edit_graph) {
			graph->set_edit();
			edit_graph  = graph ;
		}
	/* } */
	
}

void NetworkDisplayManager::new_network(int16 x, int16 y)
{
	// LogOut << "NetworkDisplayManager::new_network()\n" ;
	NetworkDescriptionFull * to_add =
		new NetworkDescriptionFull(*the_net,*the_nodes, *the_buffers,x,y);
	the_net = 0 ;
	the_nodes = new NodeDescription_LinearList ;
	the_buffers = new BufferDescription_LinearList ;
	the_networks.next(0);
	new_network(to_add);

}


void NetworkDisplayManager::buffer_descriptor_for_net(int size,const char *data)
{
	if (!edit_graph) return ;
	edit_graph->buffer_descriptor_for_net(size,data);
}

void NetworkDisplayManager::set_buffer_descriptor(int size,const char *data)
{
	const char * name = data;
	if (strlen(data) != size -1) {
		TheLog << "NetworkDisplayManager::set_buffer_descriptor, bad length\n" ;
		return ;
	}
	if (!edit_graph) return ;
	const char * net_name = edit_graph->network_name();
	if (!net_name) {
		TheLog << "NetworkDisplayManager::set_buffer_descriptor, bad name\n" ;
		return ;
	}
	if (edit_graph->is_other_edit_operation_warn()) return ;
	if (edit_graph->edit_node()) {
		DspApplication::flush_help_info();
		*Output + OutputInfo <<
			"There is a pending edit in network `" << net_name << ".\n"  <<
		"This edit must be completed before setting the buffer descriptror.\n" ;
		DspApplication::write_help_info();
		return ;
	}
	char * cmd = Concatenate(net_name,".AssignBuffers(", name, ");");
	edit_graph->other_edit_operation(NetGraph::set_buffer_descriptor);
	DspApplication::root_window()->network_edit_command(cmd);
	delete cmd ;
}

static const char * await_message = "nodes awaiting network" ;

void NetworkDisplayManager::create_edit_node(int size,const char *data)
{
	int16 num_inputs ;
	int16 num_outputs ;
	MoveNBytes((char *) &num_inputs,data,sizeof(num_inputs));
	MoveNBytes((char *) &num_outputs,data += sizeof(num_inputs),
			sizeof(num_outputs));
/*
 *	LogOut << "DisplayManager::create_edit_node, in = " << num_inputs <<
 *		", out = " << num_outputs << "\n" ;
 */
	data += sizeof(num_outputs);
	char * class_name = Concatenate(data);
	char * node_name = Concatenate(data+strlen(class_name)+1);
	const char * already_used = where_is_node_being_edited(node_name);
	if (already_used) {
		int await_flag =  !strcmp(already_used,await_message);
		DspApplication::flush_help_info();
		*Output + OutputInfo << "Node `" << node_name <<
			"' is being edited " ;
		if (await_flag) *Output << " as one of the " << await_message << ".\n" ;
		else *Output << "in network `" << already_used << "'.\n" ; 
		DspApplication::write_help_info();
		delete class_name ;
		delete node_name ;
		return ;
	}
/*
 *	LogOut << "class_name = `" << class_name << "', node_name = `" <<
 *		node_name << "'.\n" ;
 */
	NodeDescription * node = new NodeDescription(class_name,node_name,
		num_inputs, num_outputs);
	if (!edit_graph) {
		// LogOut << "create_network\n" ;
		if (!nodes_awaiting_network->number()) {
			PacketHeader head(PacketNetworkEdit,CppEnums::create_network);
			WriteSeg->WritePacket(head);
		}
		// LogOut << "create_network after\n" ;
		nodes_awaiting_network->add(node);
		// LogOut << "nodes_awaiting_network->add(" << node->name() << ")\n" ;
		return ;
	}
	// LogOut << "before edit_graph->new_node(node);\n" ;
	edit_graph->edit_new_node(node);
	the_networks.next(0);
	NetworkDescriptionFull * full ;
	while(full = the_networks.next()) full->delete_node(data);
}

void NetworkDisplayManager::delete_network(int size,const char *data)
{
/*
 *	LogOut << "NetworkDisplayManager::delete_network(" << size <<
 *		", `" << data << "')\n" ;
 */
	if (strlen(data) != size-1) {
		// LogOut << "NetworkDisplayManager::delete_network, bad size\n" ;
		return ;
	}
	the_networks.next(0);
	the_networks_to_rebuild.next(0);
	NetworkDescriptionFull * full ;

	for (int index = 0 ;full = the_networks_to_rebuild.next();index++)
	  if (!strcmp(data,full->name())) the_networks_to_rebuild.Remove(index);

	for (index = 0 ;full = the_networks.next();index++)
	  if (!strcmp(data,full->name())) {
		the_networks.Remove(index);
		// LogOut << "unmapping `" << full->name() << "'\n" ;
		full->unmap() ;
		break ;
	}
}

void NetworkDisplayManager::delete_node(int size,const char *data)
{
	if (strlen(data) != size-1) {
		// LogOut << "NetworkDisplayManager::delete_node, bad size\n" ;
		return ;
	}
	the_networks.next(0);
	NetworkDescriptionFull * full ;
	for (int index = 0 ;full = the_networks.next();index++)
		full->delete_node(data);
}

void NetworkDisplayManager::create_edit_network(int size,const char *data)
{
	char * controller_name = Concatenate(data);
	char * network_name = Concatenate(data + strlen(data) + 1);
/*
 *	LogOut << "NetworkDisplayManager::create network: " <<
 *		controller_name << ", " << network_name << "\n" ;
 */
	NetDescription * net = new NetDescription(network_name,controller_name);
	NetworkDescriptionFull * net_d = new NetworkDescriptionFull(*net,
		*nodes_awaiting_network);
	new_network(net_d);
	NetGraph * tmp = net_d->graph();
	if (edit(tmp)) tmp->set_edit();

	NodeDescription * node ;
    nodes_awaiting_network->next(0);
    while (node = nodes_awaiting_network->next())
        net_d->add_unlinked_node_to_network(node);

	nodes_awaiting_network = new NodeDescription_LinearList ;
}


void NetworkDisplayManager::raise_network(const char * net_name)
{
	the_networks.next(0);
	NetworkDescriptionFull * full ;
	while(full = the_networks.next()) if(!strcmp(net_name,full->name())) {
		 full->win()->raise();
	}
}

void NetworkDisplayManager::raise_window_node(const char * node_name)
{
	the_networks.next(0);
	NetworkDescriptionFull * full ;
	while(full = the_networks.next()) full->raise_window_node(node_name);
}

void NetworkDisplayManager::dump_nets()
{
	if (!the_networks.number()) return ;
	TheLog << "Current editable networks:\n" ;
	the_networks.next(0);
	NetworkDescriptionFull * net ;
	while (net = the_networks.next())
		TheLog << "`" << net->name() << "'\n" ;
	
}

void NetworkDisplayManager::network_edit(int id,int size,const char *data)
{

	// dump_nets();
/*
 *	LogOut << "NetworkDisplayManager::network_edit(" << id << ", " << size
 *		<< ",), edit_graph = " << (void *) edit_graph << "\n" ;
 */

	switch(id) {
case CppEnums::created_node:
		create_edit_node(size,data);
		break;
case CppEnums::created_network:
		create_edit_network(size,data);
		break ;
case CppEnums::statement_ok:
		if (edit_graph) edit_graph->complete_edit();
		break ;
case CppEnums::statement_error:
		if (edit_graph) edit_graph->error_edit();
		break ;
case CppEnums::raise_window_containing_node:
/*
 *		LogOut << "NetworkDisplayManager::network_edit, node = `" <<
 *			data << "'\n" ;
 */
		raise_window_node(data);
		break ;
case CppEnums::raise_network_window:
		DspApplication::network_manager()->raise_network(data);
		break ;
case CppEnums::set_buffer_descriptor:
		set_buffer_descriptor(size,data);
		break ;
case CppEnums::buffer_descriptor_for_net:
        buffer_descriptor_for_net(size,data);
        break ;
case CppEnums::delete_node:
		delete_node(size,data);
		break ;
case CppEnums::delete_network:
		delete_network(size,data);
		break ;
default:
		DbgError("NetworkDisplayManager::network_edit","bad id");
	}
/*
 *	LogOut << "NetworkDisplayManager::network_edit(" << id << ",,) exit\n" ;
 *	dump_nets();
 */
}


void NetworkDisplayManager::network_display(int id,int size,const char *data)
{
/*
 *	LogOut << "NetworkDisplayManager::network_display(" << id << ", " <<
 *		size << ",), type = " << type << "\n" ;
 */
	current_list.dump();
	current_list.dump();
	if (type == none) if (id != GenericArrayElement::window_size) {
		type = (StructType) id ;
		if (type == network_terminator) id = GenericArrayElement::terminator ;
		else {
			return ;
		}
	}
	GenericArrayElement::ElementType elt_type =
		(GenericArrayElement::ElementType) id ;
	switch(elt_type) {
case GenericArrayElement::window_size:
		memcpy(&x_size,data,sizeof(x_size));
		memcpy(&y_size,data+sizeof(x_size),sizeof(y_size));
		return ;
case GenericArrayElement::string:
		current_list.dump();
		current_list.add(new GenericArrayElement(elt_type,Concatenate(data)));
		current_list.dump();
		return ;
case GenericArrayElement::integer:
		current_list.dump();
		current_list.add(new GenericArrayElement(elt_type,data));
		current_list.dump();
		return ;
case GenericArrayElement::list:
		// LogOut << "the_strings.add(\"" << data << "\")\n" ;
		the_strings.add(Concatenate(data));
		return ;
case GenericArrayElement::int_list:
		{
			int val;
			MoveNBytes((char *)&val,data,sizeof(data));
			// LogOut << "the_ints.add(\"" << val << "\")\n" ;
			the_ints.add(val);
			return ;
		}
case GenericArrayElement::int_list_terminator:
		current_list.add(new GenericArrayElement(the_ints));
		current_list.dump();
		the_ints.clear(100);
		return ;
case GenericArrayElement::list_terminator:
		current_list.add(new GenericArrayElement(the_strings));
		current_list.dump();
		the_strings.clear(100);
		return ;
case GenericArrayElement::terminator:
		break ;
default:
		DbgError("NetworkDisplayManager::network_display","bad elt type");
	}
	// LogOut << "type = " << type << "\n" ;
	switch(type) {
case node:
		// LogOut<<"Node:current_list size = "<<current_list.number() << "\n" ;
		current_list.dump();
		the_nodes->add(new NodeDescription(&current_list));
		current_list.clear(100);
		// current_list.dump();
		break ;
case buffer:
		// LogOut <<"Buf:current_list size = "<<current_list.number() << "\n" ;
		current_list.dump();
		the_buffers->add(new BufferDescription(&current_list));
		current_list.clear(100);
		break ;
case network:
		if (the_net) DbgError("NetworkDisplayManager::network_display",
			"multiple nets");
		// LogOut << "Net:current_list size = "<<current_list.number()<< "\n" ;
		current_list.dump();
		the_net = new NetDescription(&current_list);
		current_list.clear(100);
		break ;
case network_terminator:
		if (!the_net) DbgError("NetworkDisplayManager::network_display",
			"no_net");
		// LogOut << "network terminator\n" ;
		new_network(x_size,y_size);
		x_size = -1;
		y_size = -1;
		// LogOut << "network terminator after\n" ;
		break ;
case none:
default:
		DbgError("NetworkDisplayManager::network_display","bad type");
	}
	type = none ;
}

const char * NetworkDisplayManager::where_is_node_being_edited(
	const char * node_name)
{
	the_networks.next(0);
	NetworkDescriptionFull * des ;
	while(des = the_networks.next()) if (des->using_node(node_name))
		return des->name();
	nodes_awaiting_network->next(0);
	NodeDescription * nod ;
	while (nod=nodes_awaiting_network->next())
		if (!strcmp(nod->name(),node_name)) return await_message ;
	return 0 ;
}

void NetworkDisplayManager::removing(NetworkDescriptionFull* rem)
{
	// LogOut<<"NetworkDisplayManager::removing: " << rem->name() << "\n";
	if (edit_graph == rem->graph()) {
		edit_graph = 0 ;
	}
	// the_networks.Remove(rem);
}


TraverseObj::TraverseObj(NodeMemberFunction act,
	WidgetKit & k, LayoutKit& l, Style *s, VerticalGlyphs &vert):
	the_action(act),
	the_kit(k),
	the_layout(l),
	the_style(s),
	error_state(none),
	the_vertical_glyphs(vert),
	the_vertical_position(0),
	last_vertical_position(0),
	last_connect(0),
	is_in_vertical_glyphs(0)
{
}

void TraverseObj::restore_last()
{
	// LogOut << "TraverseObj::restore_last()\n" ;
	if (last_vertical_position) {
		the_vertical_position = last_vertical_position ;
		is_in_vertical_glyphs = 1 ;
/*
 *		LogOut << "last_vertical_position = "
 *			<< (void *) last_vertical_position << "\n" ;
 */
	} else {
		// LogOut << "nothing to restore\n" ;
		the_vertical_position = 0 ;
		is_in_vertical_glyphs = 0 ;
	}
}

void TraverseObj::check_in_vertical_glyphs()
{
/*
 *	LogOut << "TraverseObj::check_in_vertical_glyphs(), is_in = " <<
 *		is_in_vertical_glyphs << "\n" ;
 */
	if (is_in_vertical_glyphs) return ;
	if (the_vertical_position) if (the_vertical_position->size())
		vertical_glyphs_append() ;
}


VerticalPosition * TraverseObj::vertical_position()
{
	if (!the_vertical_position) make_vertical_position();
	return the_vertical_position ;
}

void TraverseObj::vertical_glyphs_append()
{
	// LogOut << "TraverseObj::vertical_glyphs\n" ;
	if (the_vertical_position) if (the_vertical_position->size()) {
		the_vertical_glyphs.append(*the_vertical_position);
		last_vertical_position = the_vertical_position ;
		the_vertical_position = 0 ;
		is_in_vertical_glyphs = 0 ;
	}
}

EdibleSpace * TraverseObj::separator(NodeDescription * node)
{
	if (!the_vertical_position) return 0 ;
	if (!the_vertical_position->size()) return 0 ;
	int need_separator = 1 ;
	if (node) if (node->in()) need_separator = 0 ;
	if (need_separator) return new EdibleSpace(NodeGlyph::hmargin_size);
	return 0 ;
}

void TraverseObj::make_vertical_position()
{
	// LogOut << "TraverseObj::make_vertical_position() enter\n" ;
	if (the_vertical_position) {
		if (!the_vertical_position->size()) return ;
		last_connect = 0 ;
		// LogOut << "before vertical_glyphs\n" ;
		vertical_glyphs_append(); 
		// LogOut << "after vertical_glyphs\n" ;
	}
	the_vertical_position = new VerticalPosition(layout(),vertical_glyphs());
	// LogOut << "TraverseObj::make_vertical_position() exit\n" ;
	is_in_vertical_glyphs = 0 ;
}

Glyph * TraverseObj::label_to_glyph(const char * name) const
{
	return the_layout.vbox(
		the_layout.vglue(),
		the_kit.fancy_label(name),
		the_layout.vglue()
	) ;
}


void TraverseObj::add(EdibleOutputLabel * output_label,
	EdibleInputLabel * input_label)
{
	EdibleSpace * space = separator();
	if (!is_room_for(space,output_label,input_label)) {
		space = 0 ;
		make_vertical_position();
	} 
	if (space) vertical_position()->append(*space) ;
	vertical_position()->append(*output_label);
	vertical_position()->append(*input_label);
}


void TraverseObj::add(NodeDescription& nd, NodeGlyph *node,
	NodeConnector *conn)
{
	EdibleOutputLabel * start = 0 ;
	EdibleSpace * space = separator(&(node->node())) ;
	if (!last_connect) {
		if (nd.in()) {
			start = nd.driver_output_label(*this);
			if (!space) space = separator() ;
		}
		if (!is_room_for(space,start,node,conn,node,node)) {
			make_vertical_position();
			space = 0 ;
		}
	} else if (!is_room_for(space,node,conn)) {
		make_vertical_position();
		space = 0 ;
		if (nd.in()) start = nd.driver_output_label(*this);
	}

	if (space) vertical_position()->append(*space);
	if (start) vertical_position()->append(*start);
	vertical_position()->append(*node) ;
	if (conn) vertical_position()->append(*conn) ;

	last_connect = conn ;
}

void TraverseObj::add(NodeDescription& nd)
{
	NodeGlyph * node_glyph = new NodeGlyph(nd,kit(),layout(),style());
	EdibleSpace * space = separator(&nd) ;
	if (!is_room_for(space,node_glyph)) {
		make_vertical_position();
		space = 0 ;
	}
	if (space) vertical_position()->append(*space);
	vertical_position()->append(*node_glyph);
}

int TraverseObj::is_room_for(Glyph * a, Glyph * b, Glyph * c, Glyph * d,
	Glyph * e, Glyph * f)
{
	if (!the_vertical_position) return 1 ;
	return the_vertical_position->is_room_for(a,b,c,d,e,f);
}


NetworkGlyph::NetworkGlyph(NetworkDescriptionFull &net):
        full(&net),
		the_height(default_height),
		last_height(-1.),
		the_width(default_width),
		last_canvas(0),
		last_allocation(0),
		last_width(-1),
		rebuild_x(-1),
		rebuild_y(-1),
		error_out(0),
		max_draw_height(0),
		check_resize(1),
		max_draw_width(0)
{
	Coord w = full->pixel_width();
	if (w > -1) {
		if (w < min_width) w = min_width ;
		else if (w > max_width) w = max_width ;
		the_width = w ;
	}

	Coord h = full->pixel_height();
	if (h > -1) {
		if (h < min_height) h = min_height ;
		else if (h > max_height) h = max_height ;
		the_height = h ;
	}
	body(net.graph());
	full->ref();
}

NetworkGlyph::~NetworkGlyph()
{
	// LogOut << "NetworkGlyph::~NetworkGlyph\n" ;
	full->unref();
}



const Coord NetworkGlyph::min_width=150 ;
const Coord NetworkGlyph::max_width=2048 ;
const Coord NetworkGlyph::default_width=470 ;

const Coord NetworkGlyph::min_height=150 ;
const Coord NetworkGlyph::max_height=2048 ;
const Coord NetworkGlyph::default_height=700 ;

void NetworkGlyph::check_rebuild()
{
	if (rebuild_x < 0) return ;
	if (!DspApplication::network_manager()->prepare_rebuild(full->graph())) {
		if (!error_out) {
			error_out = 1 ;
			StringList str;
			str.Append(Concatenate(
"The network window cannot be rebuilt with the new window size"));
			str.Append(Concatenate(
"while there is a pending operation on the network. The window will"));
			str.Append(Concatenate(
"be rebuilt when the current operation completes."));
			DspApplication::information(str,full->win());
			DspApplication::network_manager()->queue_rebuild(full);
		}
		return ;
	}
	rebuild();
}

void  NetworkGlyph::rebuild(int w, int h)
{
	if (h < min_height) h = (int) min_height ;
	if (w < min_width) w = (int) min_width ;
	if (h > max_height) h = (int) max_height ;
	if (w > max_width) w = (int) max_width ;
	const buf_size = 1024 ;
	char buf[buf_size+1] ;
	memset(buf,'\0',buf_size+1);
	ostrstream cmd(buf,buf_size);
	cmd << full->graph()->network_name() <<
		".GraphDisplayWindow(" << w << "," << h << ");" ;
	// LogOut << "cmd `" << buf << "'\n" ;
	DspApplication::root_window()->network_edit_command(buf);
}

void NetworkGlyph::rebuild_current()
{
	rebuild((int) width(), (int) height());
}

int NetworkGlyph::rebuild()
{
	if (rebuild_x < 0) return 1 ;
	if (!DspApplication::network_manager()->prepare_rebuild(full->graph()))
		return 0 ;

	int h = (int) rebuild_y ;
	int w = (int) rebuild_x ;
	rebuild(w,h);
	
	rebuild_x = -1 ;
	rebuild_y = -1 ;
	return 1 ;
}

void NetworkGlyph::request(Requisition& r)  const
{
	if (!full) return ;
	MonoGlyph::request(r);
	Requirement& rx = r.x_requirement();
    Requirement& ry = r.y_requirement();
	NetworkGlyph * This = (NetworkGlyph *) this ;
	// This->last_width = rx.natural();
	// This->last_height = ry.natural();
	
/*
 *	LogOut << full->name() << "\n" ;
 *	LogOut << "request: " << full->in_resize() << ", Width = " <<
 *		rx.natural() << ", height = " << ry.natural() << "\n" ;
 */
}

void NetworkGlyph::allocate(Canvas*c, const Allocation& a,Extension &e)
{
	if (!full) return ;
	if (full->mapping()) return ;
/*
 *	LogOut << "l = " << e.left() << ", r = " << e.right()
 *		 << ", t = " << e.top()  << ", b = " << e.bottom() << "\n" ;
 */
	NetworkGlyph * This = (NetworkGlyph *) this ;
	Allotment x = a.x_allotment();
	Allotment y = a.y_allotment();
/*
 *	LogOut << full->name() << "\n" ;
 *	LogOut << "allocate: " << full->in_resize() << ", Width = " << x.span() <<
 *		", height = " << y.span() << "\n" ;
 */
	Coord c_width =  x.span();
	Coord c_height = y.span();
	const lim_x = 20 ;
	const lim_y = 30 ;
	if (c_width > max_draw_width) This->max_draw_width = c_width ;
	if (c_height > max_draw_height) This->max_draw_height = c_height ;
	Coord r_width =  DspApplication::x_req(This);
	Coord r_height =  DspApplication::y_req(This);
	MonoGlyph::allocate(c,a,e);
/*
 *	LogOut << "last_width = " << last_width << ", last_height = " <<
 *		last_height << "\n" ;
 *	LogOut << "c_width = " << c_width << ", c_height = " << c_height << "\n" ;
 *	LogOut << "r_width = " << r_width << ", r_height = " << r_height << "\n" ;
 *	LogOut << "last_width = " << last_width << ", last_height = " <<
 *			last_height << "\n" ;
 */


	// if (max_draw_height + 1 < r_height) return ;
	// if (max_draw_width + 1 < r_width) return ;

	if (last_width > 0) {
		int width_changed = fabs(c_width  - last_width) > lim_x ;
		int height_changed = fabs(c_height - last_height) > lim_y ;
		if (!width_changed && !height_changed) check_resize = 1 ;
		if (c_width < min_width) width_changed = 0 ;
		if (c_height < min_height) height_changed = 0 ; 
		/* if (check_resize) */ if (width_changed || height_changed) {
			This->rebuild_x = c_width ;
			This->rebuild_y = c_height ;
			// This->check_rebuild();
		}
	} 
}

void NetworkGlyph::do_damage()
{
	if (!full) return ;
	if (!last_canvas) return ;
	 last_canvas->damage(last_allocation->left(),last_allocation->bottom(),
        last_allocation->right(),last_allocation->top());

}
void NetworkGlyph::draw(Canvas*c, const Allocation& a) const
{
	if (!full) return ;
	Allotment x = a.x_allotment();
	Allotment y = a.y_allotment();
/*
 *	LogOut << full->name() << "\n" ;
 *	LogOut << "draw: " << full->in_resize() << ", Width = " << x.span()<<
 *		", height = " << y.span() << "\n" ;
 */
	
	NetworkGlyph * This = (NetworkGlyph *) this ;
	MonoGlyph::draw(c,a);
	This->last_canvas = c ;
	This->last_allocation = &a ;
}


void NetworkGlyph::note_auto_resize()
{
	last_width =  DspApplication::x_req(this);
    last_height =  DspApplication::y_req(this);
	check_resize = 0 ;
/*
 *	LogOut << "NetworkGlyph::note_auto_resize, w = " << last_width <<
 *		", h = " << last_height << "\n" ;
 */
}

