#include <string.h>
#include "shared.h"
#include "remcom.h"
#include "netdescd.h"
#include "network.h"
#include "netlnk.h"
#include "dfnode.h"
#include "intfc.h"
#include "cgidbg.h"
#include "netcnt.h"

// void TestAlloc(const char *msg);


NetNodeDescription::NetNodeDescription(DfNode& node):
	driver_names(0)
{
/*
 *	LogOut << "NetNodeDescription::NetNodeDescription(" <<
 *		node.GetName() << ")\n" ;
 */
	unlinked_flag = ! node.CheckLinked() ;
	element_name = node.GetName();
	InteractiveEntity * this_entity =
		AllEntityLists->GetInteractiveEntityFromObj(element_name);
	if (!this_entity) DbgError("NetNodeDescription::ctor","no entity");
	class_name = this_entity->GetClassName();
	input_channels = node.GetIn();
	output_channels = node.GetOut();
	driver_names = 0 ;
	if (!input_channels) return ;
	// TestAlloc("make driver names");
	driver_names = new const char *[input_channels+1];
	// TestAlloc("make driver names after");
	const char ** next = driver_names ;
	for (int i = 0; i < input_channels; i++)  {
		DfNode * driver = node.GetDriverNode(i) ;
		const char * name = "" ; // for no connection
		if (driver) name = driver->GetName();
		*next++ = name ;
/*
 *		LogOut << "Entry " << i << " `" << node.GetDriverNode(i)->GetName()
 *			<< "'\n" ;
 */
	}
	*next = 0 ;
}


NetBufferDescription::NetBufferDescription(DfNode& node, int chan):
	destination_names(0)
{
	driver_channel=chan;
	driver_name=node.GetName();
	DfNodeOutList& links = *(node.GetOutLink(chan)->
		GetOutLink()->GetOutputLinks());

	// DfNodeLink& out = *(node.GetOutLink(chan)->GetOutLink());
	// number_outputs = out.GetOutSize();
	number_outputs = links.Size();
	if (!number_outputs) {
		TheLog << "Error in going from driver `" << driver_name <<
			"', channel " << driver_channel << "\n" ;
		DbgError("NetBufferDescription::ctor", "no outputs");
	}
	// TestAlloc("make destination names");
	destination_names = new const char * [number_outputs+1] ;
	// TestAlloc("make destination names between");
	destination_input_channels = new int [number_outputs+1];
	// TestAlloc("make destination names after");

	const char ** dest = destination_names ;
	DfNodeOutIterator Next(links);

	for (int i = 0 ; i < number_outputs;i++) {
		const char * name = "" ;
		int channel = GenericArrayElementObject::not_set ;

		DfNodeOut * out_chan = Next();
		channel = out_chan->GetChannel() ;
		DfNode * driven = out_chan->GetNode();
		if (driven) if (driven->GetName()) name = driven->GetName() ;

		destination_input_channels[i] = channel ;
		*dest++ = name ;
	}
	destination_input_channels[number_outputs] =
		GenericArrayElementObject::end_of_values;
	*dest = 0 ;

}

NetworkDescription::NetworkDescription(ProcessNet& net)
{
	name = net.GetName();
	controller_name = net.GetTheController()->GetName();
}

void TransmitNetworkDescription::send_network_terminator()
{
	send(CommunicateNetworkDescription::network_terminator);
}

TransmitNetworkDescription::~TransmitNetworkDescription()
{
	// TestAlloc("Deleting TransmitNetworkDescription");
}


void TransmitNetworkDescription::send(
	CommunicateNetworkDescription::StructType type,
	GenericArrayElement * array)
{
	// LogOut << "TransmitNetworkDescription::send(" << type << ",)\n" ;
	// TestAlloc("enter send");
		
	PacketHeader head(PacketNetworkDescription,type);
	WriteSeg->WritePacket(head);
	// LogOut << "wrote header\n" ;
	if (array) for(GenericArrayElement * tmp = array;;tmp++) 
	{
		int size = tmp->object_size();
		// LogOut << "size = " << size << "\n" ;
		if (size < 0) {
			GenericArrayElement::ElementType typ =
				GenericArrayElement::list_terminator ;
			if (tmp->type() == GenericArrayElement::list) {
				const char ** lst = tmp->get_list();
				if (lst) for (const char ** l = lst; *l ; l++) {
/*
 *					LogOut << "list element is `" << *l << ", type = " <<
 *						tmp->type() << "'.\n" ;
 */
					PacketHeader head(PacketNetworkDescription,
						tmp->type(),strlen(*l)+1);
					WriteSeg->WritePacket(head,*l);
					// LogOut << "wrote " << tmp->type() << "\n" ;
				}
			} else if (tmp->type() == GenericArrayElement::int_list) {
				int * int_list = tmp->get_int_list();
				if (int_list) for (int * x = int_list;
					*x !=  GenericArrayElementObject::end_of_values ; x++) {
					PacketHeader head(PacketNetworkDescription,
						tmp->type(),sizeof(int_list[0]));
					WriteSeg->WritePacket(head,(char *)x);
					// LogOut << "wrote " << tmp->type() << "\n" ;
				}
				typ =  GenericArrayElement::int_list_terminator ;
			} else DbgError("TransmitNetworkDescription::send","bad array");
			PacketHeader head(PacketNetworkDescription,typ);
			WriteSeg->WritePacket(head);
			// LogOut << "wrote list terminator\n" ;
			continue ;
		}
		PacketHeader head(PacketNetworkDescription,tmp->type(),size);
		WriteSeg->WritePacket(head,tmp->ptr_object());
		// LogOut << "wrote object" << tmp->type() << "\n" ;
		if (tmp->is_terminator()) break ;
	}
	// TestAlloc("deleting array");
	delete array;
}

void TransmitNetworkDescription::send(NetNodeDescription& nd)
{
	// TestAlloc("TransmitNetworkDescription::send enter");
	send(node,nd.get_array());
}

void TransmitNetworkDescription::send(NetBufferDescription& buf)
{
	send(buffer,buf.get_array());
}

void TransmitNetworkDescription::send(NetworkDescription& net)
{
	send(network,net.get_array());
}

