/*  dfnode4.C   */
/*  Copyright 1991 Mountain Math Software  */
/*  All Rights Reserved					*/
#include <string.h>
#include <stream.h>
#include <fstream.h>

#include <fcntl.h>
#ifndef __NT_VC__
#define O_BINARY 0
#endif

#include <ctype.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>


#include "portable.h"
#include "debug.h"
#include "outtok.h"
#include "cgidbg.h"
#include "shared.h"
#include "display.h"

#include "network.h"
#include "netlnk.h"
#include "intfc.h"
#include "yacintfc.h"
#include "strmstr.h"
#include "dskchnhd.h"
#include "netcnt.h"
#include "buffer.h"
#include "travparm.h"
#include "tardb.h"
#include "thread.h"
#include "tarnodpar.h"
#include "adjust.h"
#include "bufstat.h"
#include "timing.h"
#include "netdescd.h"
#include "tarparm.h"
#include "mkstr.h"
#include "dosname.h"
#include "outnode.h"
#include "noderep.h"
#include "shared.h"
#include "remcom.h"
#include "editnet.h"
#include "plotnd.h"
#include "plotdat.h"
#include "dyntext.h"
#include "dspe_app.h"
#include "environ.h"
#include "grphio.h"
#include "ObjProDSP/sysconst.h"

// void TestAlloc(const char * msg);


TargetAdjustState DfNode::DoAdjust(Adjustment& TheAdjustment)
{
	// LogOut << "DfNode::DoAdjust for " << GetName() << "\n" ;
	return GetTargetParameters()->DoAdjust(TheAdjustment);
}


TargetAdjustState DfNode::AdjustForward(Adjustment& TheAdjustment)
{
	if (State.IsError()) return TargetAdjustFail ;
	if (IsTraverseFlag(AdjustBit)) return TargetAdjustOK ;
	SetTraverseFlag(AdjustBit);
	TargetAdjustState Return = DoAdjust(TheAdjustment);
	Adjustment Save = TheAdjustment ;
	if (Return == TargetAdjustChange) for (int i = 0 ; i < GetOut() ; i++) {
		Adjustment Use = Save ;
/*
 *		LogOut << "Forward:Use.GetEnlargeBase() = " <<
 *			Use.GetEnlargeBase() <<
 *			", for " << GetName() << "[" << i << "]\n" ;
 */
		TargetAdjustState Temp = GetOutLink(i)->Adjust(Use);
		if (Temp > Return) Return = Temp ;
		if (Return >= TargetAdjustFail) break ;
	}
	ClearTraverseFlag(AdjustBit);
	return Return ;
}

TargetAdjustState DfNode::AdjustBackward(Adjustment& TheAdjustment)
{
	if (State.IsError()) return TargetAdjustFail ;
	if (IsTraverseFlag(AdjustBit)) return TargetAdjustOK ;
	SetTraverseFlag(AdjustBit);
	TargetAdjustState Return = DoAdjust(TheAdjustment);
	Adjustment Save = TheAdjustment ;
	for (int i = 0 ; i < GetIn() ; i++) {
		Adjustment Use = Save ;
/*
 *		LogOut << "Backward:Use.GetEnlargeBase() = " <<
 *			Use.GetEnlargeBase()
 *			<< ", for " << GetName() << "[" << i << "]\n" ;
 */
		DfNodeInLink * TheLink = GetInLink(i);
		Use.SetInLink(TheLink);
		TargetAdjustState Temp = TheLink->Adjust(Use);
		if (Temp > Return) Return = Temp ;
		if (Return >= TargetAdjustFail) break ;
	}
	ClearTraverseFlag(AdjustBit);
	return Return ;
}

TraverseResult DfNode::SetTerminalNodeResampling(TraverseObject& obj)
{
	if (GetOut()) return TraverseOK ;
	BufferStatus & BufStat = *(obj.GetBufferStatus());
	if (BufStat.IsPreInitState()) for (int i = 0 ; i < GetIn(); i++) {
		TimingDescription& Timing = *(GetInLink(i)->GetTiming());
/*
 *		LogOut << "Num = " << Timing.NumeratorSampling << ", Denom = " <<
 *			Timing.DenominatorSampling << "\n" ;
 */
		TargetAdjustState Result = BufStat.NewResamplingForTerminalNode(
			Timing.NumeratorSampling, Timing.DenominatorSampling);
/*
 *		LogOut << "Sampling for `" << GetName() << "', Num = " <<
 *			Timing.NumeratorSampling << ", Den = " <<
 *			Timing.DenominatorSampling << "\n" ;
 */
 
		if (Result >= TargetAdjustFail) {
			BufStat.SetReason( new ReasonForFailure (
			"least common multiple of resample rates overflows",
				GetName(),-1, i, ReasonForFailure::Input));
			return TraverseError ;
		}
	} else if (BufStat.IsPreInitMaxBufState()) {
		// We need to compute buffer size for highest sample rate data.
		if (!BufStat.GetTotalInitExecCountHighestRateNode()) {
			TargetAdjustState Ret = (TargetAdjustState)
				SetTargetInitSequence(obj);
			if (Ret >= TargetAdjustFail) return TraverseError;
		}
	} else DbgError("DfNode::SetTerminalNodeResampling","bad state");
	return TraverseOK ;
}

ErrCode DfNode::EmitNodeSpecificCtorParameters(OutTokens& Out)
{
	ErrCode Return = EmitStaticCtorParameters(Out) ;
	if (TheDfNodeOptions & NetworkReferenceDfNodeOption) 
		*(Out.GetStream()) << ",\n\t&TheNetworkReferenceFor_" <<
			GetNetName() ;
	return Return ;
}

ErrCode DfNode::EmitStaticCtorParameters(OutTokens& )
{
	return OK ;
}

ErrCode DfNode::EmitNodeSpecificInit(OutTokens& Out)
{
	return EmitStaticInit(Out);
}

ErrCode DfNode::EmitStaticInit(OutTokens& )
{
	return OK ;
}

NetworkStateControl** DfNode::GetNetworkReference()
{
	if (!GetActiveNet()) DbgError("DfNode::GetNetworkReference","no net");
	NetworkStateControl ** Ret = new (NetworkStateControl *);
	*Ret = &(GetActiveNet()->GetNetworkReference());
	return Ret ;
}

TraverseResult DfNode::replacement_list(TraverseObject& obj)
{
	// LogOut << "DfNode::replacement_list for `" << GetName() << "'.\n" ;
	NodeReplacementList& list = obj.GetParameters()-> node_replacement_list();
/*
 *	LogOut << "Target name `" << list.target_name() << "', target_created" <<
 *		target_created() << "\n" ;
 */
	if (!strcmp(list.target_name(),NodeReplacement::validate_compare_replace))
			if (!target_created()) return TraverseOK ;
	DfNode * replacement = target_replacement(list.target_name());
/*
 * 	if (replacement) LogOut << "need to replace `" << replacement->GetName()
 *		<< "'.\n" ;
 */
	if (replacement) {
		replacement->target_created(1);
		list.Append(new NodeReplacement(this,replacement));
	}
	return TraverseOK ;
}

TraverseResult DfNode::X_graph_display(TraverseObject& obj)
{
	TransmitNetworkDescription& desc =
		obj.GetParameters()->network_description();
	NetNodeDescription node_desc(*this);
	desc.send(node_desc);
	for (int i = 0 ; i < Out;i++) {
		if (!GetOutLink(i)) continue ;
		if (!GetOutLink(i)->GetOutLink()) continue ;
		{
			NetBufferDescription buf_desc(*this,i);
			desc.send(buf_desc);
		}
	}
	return TraverseOK ;
}

void DfNode::NextFreeInput ()
{
}

void DfNode::NextFreeOutput ()
{
}

void DfNode::new_buffer_channel(int in_channel,int buffer_channel)
{
	if (!CkIn(in_channel,"DfNode::new_buffer_channel")) return ;
	InLinks[in_channel].new_buffer_channel(buffer_channel);
}

void DfNode::EditNetwork(const char * edit_what)
{
/*
 *	LogOut << "DfNode::EditNetwork(" << edit_what << "), ActiveNet = " <<
 *		(void *) ActiveNet << "\n" ;
 */
	if (!ActiveNet) return ;
	NetControl * cnt = ActiveNet->GetTheController();
	// LogOut << "Controller = " << (void *) cnt << "\n" ;
	if (!cnt) return ;
	cnt->EditNetwork(edit_what);
}

void DfNode::Unlink()
{
	
	// LogOut << "DfNode::Unlink() for `" << GetName() << "'\n";
	// TestAlloc(GetName());
	EditNetwork("disconnect");
	// TestAlloc("disconnect");
	// first disconnect inputs
	for (int i = 0 ; i < In; i++) {
		// LogOut<<"at DfNode::Unlink for `"<<GetName()<<"', in = "<<i<<"\n";
		InLinks[i].UnlinkDriven();
		// TestAlloc("In unlink");
	}
	// recursively disconnect outputs
	for (i = 0 ; i < Out; i++) {
		// LogOut<<"at DfNode::Unlink for `"<<GetName()<<"', out = "<<i<<"\n";
		OutLinks[i].Unlink();
		// TestAlloc("Out unlink");
	}
	if (!In) if (ActiveNet) ActiveNet->remove_signal_node(*this);
	if (!DspApplication::make_target_mode()) if (delete_if_unlinked()) {
		// LogOut << "DfNode::Unlink delete exit for `" << GetName() << "\n" ;
		delete this ;
		// TestAlloc("i am deleted");
		return ;
	}
	// TestAlloc("add");
	if (ActiveNet) ActiveNet->add_unlinked_node(this);
	// TestAlloc(GetName());
	// LogOut << "DfNode::Unlink exit\n" ;
}

void DfNode::UnlinkOutputChannel(int channel)
{
/*
 *	LogOut << "DfNode::UnlinkOutputChannel(" << channel << ") for `" <<
 *		GetName() << "'\n";
 */
	// if (!CkOut(channel,"DfNode::UnlinkOutputChannel")) return ;
	if (channel >= Out || channel < 0)  return ;
	OutLinks[channel].UnlinkChannel();
	if (In) return ;
	for (int i = 0 ; i < Out; i++) if (OutLinks[i].is_linked()) return;
	Unlink();
/*
 *	LogOut << "DfNode::UnlinkOutputChannel(" << channel << ") for `" <<
 *		GetName() << "' exit\n";
 */
}

void DfNode::UnlinkInputChannel(int channel)
{
/*
 *	LogOut << "DfNode::UnlinkInputChannel(" << channel << ") for `" <<
 *		GetName() << "'\n";
 */
 
	// if (!CkIn(channel,"DfNode::UnlinkInputChannel")) return ;
	if (channel >= In || channel < 0)  return ;
	InLinks[channel].UnlinkChannel();
	for(int i = 0 ; i < In ; i++) if (InLinks[i].is_linked()) return ;
	Unlink();
	// LogOut << "DfNode::UnlinkInputChannel(" << channel << ") exit\n";
}

void DfNode::RemoveAllLinks()
{
	// TestAlloc("DfNode::RemoveAllLinks");
	int i ;
	if (InLinks) for (i = 0 ; i < In; i++)
		InLinks[i].remove_this_link(this,i);
 
	if (OutLinks) for (i = 0 ; i < Out; i++) OutLinks[i].remove_this_link();
	if (ActiveNet) ActiveNet->remove_unlinked_node(this);
	ActiveNet = 0 ;
	// TestAlloc("DfNode::RemoveAllLinks exit");
}

int DfNode::any_links() const
{
	// if (ActiveNet) return 1 ;
	int i ;
	if (InLinks) for (i = 0 ; i < In; i++) if (InLinks[i].GetInLink()) return 1;
	if (OutLinks) for (i = 0 ; i < Out; i++) 
		if (OutLinks[i].GetOutLink()) return 1;
	return 0 ;
}

void DfNode::disconnect_in(int channel)
{
	if (!CkIn(channel,"disconnect_in")) return ;
	InLinks[channel].disconnect();
}

void DfNode::disconnect_out(int channel)
{
	if (!CkOut(channel,"disconnect_out")) return ;
	OutLinks[channel].disconnect();
}

void DfNode::decrement_buffer_channel(int input_channel,int new_value)
{
	if (!CkIn(input_channel,"decrement buffer channel")) return ;
	InLinks[input_channel].decrement_buffer_channel(new_value);
}

DfNode * DfNode::target_replacement(const char * target)
{
	return 0 ;
}

DfNode * DfNode::default_output_replacement(const char * target)
{
	if (!strcmp(target,NodeReplacement::validate_compare_replace))
		return 0 ;
	// LogOut << "DfNode::default_output_replacement(" << target << ")\n" ;
	char * node_name = Concatenate(GetName(),target,"_OutNode");
	// node_name = AllEntityLists->make_valid_name(node_name) ;
	node_name = DspApplication::force_to_legal_name_del(node_name);

	char * file_name = 0 ;
	const char * dir = DspApplication::OutputNode_replace_directory() ;
	if (dir) file_name = Concatenate(dir,"/",GetName(),".dat");
	else  file_name = Concatenate(GetName(),".dat");
	if (!strcmp(target,TIC30_name)) {
		char * temp = ToDosName(file_name);
		delete file_name ;
		file_name = temp ;
	}
	char * caption = Concatenate("Replacement for ",GetName());
/*
 *	LogOut << "Creating OutputNode(" << node_name << ", " << file_name <<
 *		", 1, " << GetIn() << ", " << GetInEltSize() << ",\n\t" ;
 */
	// LogOut << "128, " << caption << ", 1)\n" ;
	return new OutputNode(node_name,file_name,1,GetIn(),
		128,caption,1);
}

DfNode * DfNode::default_input_replacement(const char * target)
{
	return 0 ;
}

void DfNode::raise_window()
{
	// LogOut << "DfNode::raise_window()\n" ;
	InteractiveEntity * inter_ent = interactive_entity();
	if (!inter_ent) return ;
	if (inter_ent->IsClassMember("PlotNode")) {
		PlotNode * plt = (PlotNode *) this ;
		int plot_id = plt->GetPlotId();
		// LogOut << "raising plot window " << plot_id << "\n" ;
		PacketHeader head = PlotPacketHeader(PacketWindowPlotControl,
			plt->GetPlotId(),PlotControlRaiseWindow);
		WriteSeg->WritePacket(head);
	} else if (inter_ent->IsClassMember("DisplayNodeStr")) {
		DisplayNode * dis = (DisplayNode *) this ;
		int id = dis->window_id();
		if (id > 0) {
			// LogOut << "raising text window " << id << "\n" ;
			PacketHeader head = PlotPacketHeader(PacketWindowTextControl,
				TextControlRaiseWindow,id);
			WriteSeg->WritePacket(head);
		}
	}
	int name_size = strlen(GetName());
	if (name_size >= MaxPacketSize) return ;
	PacketHeader head(PacketNetworkEdit,CppEnums::raise_window_containing_node,
		name_size+1);
	WriteSeg->WritePacket(head,GetName());
	// LogOut <<"wrote request to raise node window for `"<<GetName() << "'\n";
}

void DfNode::clear_buffers()
{
	// LogOut << "DfNode::clear_buffers called for `" << GetName() << "'\n" ;
}

void DfNode::add_to_net_graph()
{
	if (CheckLinked()) {
		if (!GetActiveNet()) {
			State.Error("Node `",GetName(),"' is damaged and cannot be edited");
			return ;
		}
		State.Error("Node `",GetName(),"' is already used in network `",
			GetActiveNet()->GetName(),
			"'.\nIt cannot be edited into another network");
		return ;
	}

	const char * class_name = GetClassName();
	int a_length = strlen(class_name) + 1 + sizeof(int16) * 2 ;
	int16 * buf = new int16[a_length/sizeof(int16) + 1];
	buf[0]= buf[1] = 0 ;
    buf[0] = GetIn();
    buf[1] = GetOut();
    strcpy((char *) (buf+2),class_name);
	if (DspApplication::send_gui(CppEnums::created_node,(char *)buf,
		GetName(),a_length) != OK) *Output + OutputHelp << "Node `" <<
			GetName() << "'\n and class `" << class_name <<
            "'\nare too long to use in an edited network.\n"
            << "The maximum lenght for the sum of these names is: " <<
            MaxPacketSize - sizeof(int16) * 2 - 2 << ".\n" ;
}


DfNode::~DfNode()
{
	// LogOut << "DfNode::dtor `" << GetName()<<"', at "<<(void *)this<<"\n";
	int name_size = strlen(GetName());
	if (!State.is_exiting()) if (name_size < MaxPacketSize) {
		// LogOut << "DfNode::~DfNode(), name_size = " << name_size << "\n" ;
		PacketHeader head(PacketNetworkEdit,CppEnums::delete_node,
			name_size+1);
		WriteSeg->WritePacket(head,GetName());
	}
	ProcessNet * net = GetActiveNet();
	if (net) net->remove_unlinked_node(this);
	if (!CheckLinked()) return ;
	MustBeActiveNet();
	GetActiveNet()->ClearActiveNetwork();
}


int DfNode::InitAfterLinked()
{
	// LogOut << "Base DfNode::InitAfterLinked() for `" << GetName() << "'.\n" ;
	return 1 ;
}

int DfNode::DoInitAfterLinked()
{
	if (State.IsError()) return 0 ;
	if (IsTraverseFlag(GenericTraverseBit)) return 1 ;
	SetTraverseFlag(GenericTraverseBit);
    int init_ok = InitAfterLinked();
	if (init_ok) for (int i = 0 ; i < Out; i++) {
		DfNodeOutLink * link = GetOutLink(i);
		if (!link) {
			State.Error("output link ",Dec(i), " missing in node `",
				GetName(), "'");
			init_ok = 0 ;
			break ;
		}
		if (!link->DoInitAfterLinked()) {
			init_ok = 0 ;
			break ;
		}
	} else State.Error("cannot post link initialize node `", GetName(), "'");
			
	ClearTraverseFlag(GenericTraverseBit);
	return init_ok ;
}

void DfNode::clear_thread()
{
	if (GetIn()) return ; // only meaningful for signals
	DfNodeLink *  lk ;
	for (int i = 0 ; i < GetOut(); i++) if (lk = (OutLinks+i)->GetOutLink())
	{
		if (lk->GetOutSize()) return ;
		if (lk->Size()) return ;
	}
	if (!ActiveNet) return ;
	ActiveNet->clear_signal_node(*this);
}

int DfNode::set_read_integer_flag(int& binary_read_flag)
{
    StreamStr * in = 0 ;
    DfNode * driver = GetDriverNode();
    if (driver) in = driver->GetOutStream();
    if (!in) return 0 ;
    ArithType::ArithCapabilities arith_in = in->GetArithType();
    binary_read_flag = 0 ;
    if (arith_in == TheArithType) return 1 ;
    char buf[32] ;
    switch(arith_in) {
case ArithType::ArithInt32:
        binary_read_flag = 1 ;
        break ;
case ArithType::ArithFloat:
        break;
case ArithType::ArithInt16:
        State.Error("cannot convert from 16 bit integers in `", GetName(),
            "'");
        return 0 ;
default:
	sprintf(buf,"%d",arith_in);
        State.Error("unsupported input arithmetic type (" ,
			buf, ") in `",GetName(), "'");
        return 0 ;
    }
    return 1 ;
}

void DfNode::open_problem(const char * name, const char * exp,
    const char *msg)
{
    if (!name) OutputCurrentChannel << "Null file name.\n";
    else OutputCurrentChannel << (msg?msg:"Cannot open file `") <<
		 name <<  "'.\n";
    expand_name(name,exp);
    if (exp) SystemErrorMessage();
}

void DfNode::create_problem(const char * name, const char * exp, int exists)
{
	if (!name) OutputCurrentChannel << "Null file name.\n";
    else if (exists) OutputCurrentChannel << "File `" << exp <<
		"' already exists.\n";
    else OutputCurrentChannel << "Cannot create file `" <<  exp <<  "'.\n";
    expand_name(name,exp);
    if (!exists && exp) SystemErrorMessage();
}





const char * DfNode::interactive_open_file(const char ** pt_name,
	const char * prompt_file_type, int force_error,
		int * fd, FILE ** fl, ifstream ** str)
{
	const char * name = *pt_name ;
	const char * exp = 0 ;
	for (;;) {
		int useable_name = 0 ;
		if (name) if (*name) useable_name = 1 ;
		else name = 0 ;

		exp = 0 ;
		if (useable_name) {
			exp = open_r(name,fd,fl,str);
			if (good_file(fd,fl,str)) {
				*pt_name = name ;
				return exp;
			}
			if (!State.IsInteractive()) {
				if (!force_error) return 0 ;
				*Output + OutputCppHelp ;
				open_error(name,exp);
				return 0 ;
			} else {
				*Output + OutputPrompt ;
		  		open_problem(name,exp);
			}
		}
		if (!State.IsInteractive()) return 0 ;
		if (!prompt_file_type) prompt_file_type =
			"parameter `FileName' for file" ;
		// FileName must be in prompt to trigger FileChooser option

		*Output + OutputPrompt << "Please enter " << prompt_file_type <<
			" to read or RETURN:\n" ;
		const char * Temp = GetGraphicsRawBufLine(InputPrompt);
		if(!*Temp) if (!force_error) return 0 ;
			else {
				State.Error("bad input file");
				return 0 ;
			}
		if(Temp[0] == '\03') {
            State.Error("user aborted input");
            return 0 ;
        }
		name = Temp ;
	} // should never fall through
	return 0 ;
}

const char * DfNode::interactive_create_file(const char ** pt_name, const char * prompt_file_type,
	int flags, int * fd, FILE ** fl, ofstream ** str)
{
#define force_error (flags&1)
#define check_exists (flags&6)
#define error_if_exists (flags&4)

	const char * name = *pt_name ;
	const char * exp = 0 ;
	int useable_name = 0 ;
	int already_exists = 0 ;
	for (;;) {
		already_exists = 0 ;
		if (name) if (*name) useable_name = 1 ;
		else name = 0 ;
		exp = 0 ;
		if (useable_name) {
			exp = open_w(name,flags,already_exists,fd,fl,str);
			if (!already_exists || ! check_exists) 
			if (good_file(fd,fl,str)) {
				*pt_name = name ;
				return exp;
			}
		}
		if (!State.IsInteractive()) {
			if (force_error) {
				*Output + OutputCppHelp ;
				create_error(name,exp,already_exists);
			}
			return 0 ;
		}
		*Output + OutputPrompt ;
		create_problem(name,exp,already_exists);
		if (!prompt_file_type) prompt_file_type = "file" ;

		*Output + OutputPrompt << "Please enter " << prompt_file_type <<
			" to create or RETURN:\n" ;
		const char * Temp = GetGraphicsRawBufLine(InputPrompt);
		exp = 0 ;
		if(!*Temp) if (!force_error) return 0 ;
			else {
				State.Error("bad output file");
				return 0 ;
			}
		if(Temp[0] == '\03') {
            State.Error("user aborted input");
            return 0 ;
        }
		name = Temp ;
	} // should never fall through
	return 0 ;
}

ErrCode DfNode::propagate_arith_type(int in_channel, int min_bits)
{
	// LogOut << "DfNode::propagate_arith_type `" << GetName() << "'\n" ;
	if (State.IsError()) return FatalError ;
	ErrCode ret = OK ;
	//  LogOut << "DfNode::propagate_arith_type(" << in_channel << ")\n" ;
    DfNode * driver = GetDriverNode(in_channel);
    if (!driver) DbgError(" DfNode::propagate_arith_type","no driver");
    StreamStr * base = driver->GetOutStream();
    if (!base) DbgError(" DfNode::propagate_arith_type","no driver stream");
    ArithType::ArithCapabilities  in_type = base->GetArithType();
    // LogOut << "in_type = " << in_type << "\n" ;
    int bits = 8 * ArithType::SizeInBytes[in_type] ;
    if (min_bits > 0) if ( bits < min_bits) {
        char bufmin_bits[32] ;
        char bufbits[32] ;
        sprintf(bufmin_bits,"%d",min_bits);
        sprintf(bufbits,"%d",bits);
        State.Warning("in `", GetName(), "' bits needed (",
            bufmin_bits,
            ")\n is greater than the physical word size (", bufbits,")");
		ret = Warning ;
	}
	// LogOut << " bits = " << bits << ", min_bits = " << min_bits << "\n" ;
	for (int i = 0 ; i < GetIn(); i++) {
    	StreamStr * in = GetInStream(i);
    	if (!in) DbgError(" DfNode::propagate_arith_type","no in stream");
    	in->SetArithType(in_type);
	}
	for (i = 0; i < GetOut(); i++) {
    	StreamStr * out = GetOutStream(i);
    	if (!out) DbgError(" DfNode::propagate_arith_type","no out stream");
    	out->SetArithType(in_type);
	}
	if (min_bits < 0) if ( bits < -min_bits) {
		ret = FatalError ;
        char bufmin_bits[32] ;
        char bufbits[32] ;
	sprintf(bufmin_bits,"%d",-min_bits);
        sprintf(bufbits,"%d",bits);
        State.Error("in `", GetName(), "' bits needed (",
            bufmin_bits,
            ")\n is greater than the physical word size (", bufbits,")");
	}
	return ret ;
}

TraverseResult DfNode::independent_thread_check(TraverseObject& obj)
{
	DfNode * ck = obj.parameters()->node();
	if (ck->FindNode(this)) obj.parameters()->flag(1);
	return TraverseOK ;
}
