/*  tarnod.C   */
/*  Copyright 1991 Mountain Math Software  */
/*  All Rights Reserved                    */
#include "tarnod.h"
#include "netlnk.h"
#include "debug.h"
#include "cgidbg.h"
#include "timinfo.h"
#include "environ.h"
#include <stream.h>
#include <fstream.h>

#include <fcntl.h>
#ifndef __NT_VC__
#define O_BINARY 0
#else 
#include <io.h>
#endif
#include <ctype.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include "mkstr.h"
#include "usercom.h"
#include "yacintfc.h"
#include "ObjProDSP/sysconst.h"
#ifdef INTERACTIVE
#include "dfnode.h"
#endif



TargetNode::TargetNode(const char * name, int in, int out,
	DfNodeInLink * in_links, DfNodeOutLink * out_links, int ** exec,
	NodeExecuteType type, int32 delay):
		UserEntity(name),
		In(in),
		Out(out),
		InLinks(in_links),
		OutLinks(out_links),
		ExecutionSequences(exec),
		ExecuteType(type),
		Delay(delay),
		FeedbackFlag(0),
		TheTimingInfo(0)
{
	Init();
}

void TargetNode::Init()
{
	if (In < 0 || In > 500) {
		TheLog << "In = " << In << ", for `" << GetName() << "', set to 0.\n";
		In = 0 ;
	}
	if (Out < 0 || Out > 500) {
		TheLog << "Out = " << Out << ", for `" << GetName() << "', set to 0.\n";
		Out = 0 ;
	}
	// LogOut << "TargetNode::ctor for " << GetName() << "\n" ;
	History = 0 ;
	ExecutionIndex = SequenceIndex = 0 ;
	if (ExecutionSequences) ExecutionSequence = ExecutionSequences[0];
	if (TimingCheckOn) TheTimingInfo = new TimingInfo ;
}

ErrCode TargetNode::NodeReset() // Reset to initial parameters
{
	return OK ;
}

TargetNode::TargetNode(const char * Name, int in, int out):
	UserEntity(Name),
	In(in),
	Out(out),
	Delay(0),
	InLinks(0),
	OutLinks(0),
	ExecutionSequences(0),
	ExecuteType(NodeExecuteFixedBound),
	FeedbackFlag(0),
	TheTimingInfo(0)
{
	Init();
	if (In) InLinks = new DfNodeInLink[In] ;
	else In = 0 ;
	if (Out) OutLinks = new DfNodeOutLink[Out] ;
	else Out = 0 ;
}


TargetNode::~TargetNode()
{
}

void TargetNode::SetInputFromDisk(const NodeOutChannelHeader& DiskState,
		int Channel )
{
	// Need body
}

int32 TargetNode::GetOutBlockSize(int chan) const
{
	return OutLinks[chan].GetBlockSize();
}

int32 TargetNode::GetBlockSize(int chan) const
{
	// LogOut << "TargetNode::GetBlockSize(" << chan << ")\n" ;
	return InLinks[chan].GetBlockSize();
}

void TargetNode::SetNodeState(ErrCode new_state)
{
	if (new_state > NodeState) NodeState = new_state;
}
		
/*
 * int32 TargetNode::GetEltSize(int out_channel) const
 * {
 *	return OutLinks[out_channel].GetElementSize();
 * }
 *
 *
 * int32 TargetNode::GetInEltSize(int in_channel) const
 * {
 *	return InLinks[in_channel].GetElementSize();
 * }
 */


int32 TargetNode::GetIncrementOut(int chan) const
{
	return OutLinks[chan].GetIncrementOut();
}

int32 TargetNode::GetIncrementIn(int chan) const
{
	return InLinks[chan].GetIncrementIn();
}

TargetNode * TargetNode::GetDriverNode(int chan) const 
{
	return InLinks[chan].GetDriverNode();
}

/*
int32 TargetNode::GetIncrementIn(int chan);

int32 TargetNode::GetEltSize(int out_channel) const
{
	return OutLinks[out_channel].GetElementSize();
}

int32 TargetNode::GetInEltSize(int in_channel) const
{
	return InLinks[in_channel].GetElementSize();
}
*/

ErrCode TargetNode::DoNode(int32 )
{
	DbgError("TargetNode::DoNode","node base function");
	return FatalError ;
}

void TargetNode::SetSequence(int index)
{
	// LogOut << "SetSequence(" << index << ") for " << GetName() << "\n" ;
	if (!ExecutionSequences) return ;
	ExecutionIndex = 0 ;
	SequenceIndex = index ;
	ExecutionSequence = ExecutionSequences[index] ;
}

DfNodeInLink * TargetNode::GetInLink(int Chan) const
{
	return InLinks+Chan;
}

DfNodeOutLink *TargetNode::GetOutLink(int Chan) const
{
	return OutLinks+Chan;
}

		// These two functions are for short circuiting input and
		// output nodes. They allow direct transfer of data
		// to the first DSP node or from the last output node
		// to an external system interface
int32 TargetNode::ReadInput(MachWord * Data, int32 SizeToRead, int chan)
{
	int32 OrigSize = SizeToRead ;
	if (chan < 0 || chan > In-1) return -1 ;
	int32 AvailData ;
	while (SizeToRead && (AvailData = GetContiguousAvailableData(chan))) {
		int Count = SizeToRead ;
		if (AvailData < Count) Count = AvailData ;
		const MachWord * Ptr = GetReadPtr(chan);
		for (int i = 0 ; i < Count ; i++) *Data++ = *Ptr++ ;
		UpdateRead(Count);
		SizeToRead-=Count ;
	}
	return OrigSize - SizeToRead ;
}

int32 TargetNode::WriteOutput(MachWord * Data, int32 Size, int chan)
{
	int32 OrigSize = Size ;
	if (chan < 0 || chan > Out-1) return -1 ;
	int32 Space ;
	while (Size && (Space = GetContiguousSpace(chan))) {
		int Count = Size ;
		if (Space < Count) Count = Space ;
		MachWord * Ptr = GetWritePtr(chan);
		for (int i = 0 ; i < Count ; i++) *Ptr++ = *Data++ ;
		UpdateWrite(Count);
		Size-=Count ;
	}
	return OrigSize - Size ;
}

NetworkStateControl::NetworkStateControl(void * ref):
	NetworkReference(ref),
	CallAtEnd(0)
{
	
}

ErrCode NetworkStateControl::SetCallAtEnd(EndOfNetwork call)
{
	if (CallAtEnd) return Warning ;
	CallAtEnd = call ;
	return OK ;
}


ErrCode NetworkStateControl::SetReference(void * ref)
{
	if (NetworkReference) return Warning ;
	NetworkReference = ref ;
	return OK ;
}

ErrCode NetworkStateControl::DoCallAtEnd()
{
	if (!CallAtEnd) return Warning ;
	ErrCode Return = (*CallAtEnd)(NetworkReference);
	CallAtEnd = 0 ;
	return Return ;
}

const char * TargetNode::open_r(const char * name,int * fd, FILE ** fl,
	ifstream ** str)
{
	int bad = 1 ;
	if (name) if (*name) bad = 0 ;
	if (bad) return 0 ;
	const char * exp = Environment::expand_file_name(name);
	bad = 1 ;
	if (fd) {
		*fd = open(exp,O_RDONLY | O_BINARY ,OpenFileMode);
		if (*fd > 0)  bad = 0;
		else *fd = 0 ;
	} else if (fl) {
		*fl = fopen(exp,"r");
		if (*fl) bad = 0 ;
		else *fl = 0 ;
	} else {
		*str = new ifstream(exp) ;
		if ((*str)->good()) bad = 0  ;
		else {
			delete *str ;
			*str = 0 ;
		}
	}
	return exp ;
}

void TargetNode::expand_name(const char * name, const char * exp)
{
	if (exp) if (exp != name)
        OutputCurrentChannel << "The name was expanded to `" << exp << "'.\n" ;
}

void TargetNode::open_error(const char * name, const char * exp,
	const char *msg)
{
	if (!name) State.Error("null file name");
	else State.Error(msg?msg:"Cannot open file `", name, "'");
	expand_name(name,exp);
	if (exp) SystemErrorMessage();
}

void TargetNode::create_error(const char * name, const char * exp, int exists)
{
	if (!name) State.Error("null file name");
	else if (exists) State.Error("file `",name,"' already exists");
	else State.Error("Cannot create file `", name, "'");
	expand_name(name,exp);
	if (exp && ! exists) SystemErrorMessage();
}

const char * TargetNode::open_file(const char ** name, const char * prompt_file_type, int force_error,
		int * fd, FILE ** fl, ifstream ** str)
{
#ifdef INTERACTIVE
	return DfNode::interactive_open_file( name, prompt_file_type, force_error,fd, fl, str);
#else
	const char * exp = open_r(*name,fd,fl,str);
	if (good_file(fd,fl,str)) return exp ;
	open_error(*name,exp);
	OutputCurrentChannel << "\n" ;
	return 0 ;
#endif
}


const char * TargetNode::open_w(const char * name, int flags, int& exists, int * fd, FILE ** fl,
	ofstream ** str)
{
#define check_exists (flags&6)

	exists = 0 ;
	int bad = 1 ;
	if (name) if (*name) bad = 0 ;
	if (bad) return 0 ;
	bad = 1 ;
	const char * exp = Environment::expand_file_name(name);
	if (check_exists) {
		struct stat the_stat ;
		if (!stat(exp, &the_stat)) {
			exists = 1 ;
			return exp ;
		}
	}
	if (fd) {
		*fd = open(exp,O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
			OpenFileMode);
		if (*fd > 0) bad = 0  ;
		else *fd = 0 ;
	}
	else if (fl) {
		*fl = fopen(exp,"w");
		if (*fl) bad = 0 ;
		else * fl = 0 ;
	} else {
		*str = new ofstream(exp) ;
		if ((*str)->good()) bad = 0 ;
		else {
			delete *str ;
			*str = 0 ;
		}
	}
	return exp;
}

const char * TargetNode::create_file(const char ** name, const char * prompt_file_type,
	int flags, int * fd, FILE ** fl, ofstream ** str)
{
#ifdef INTERACTIVE
	return DfNode::interactive_create_file( name, prompt_file_type,flags,fd,
		fl, str);
#else
	int exists = 0 ;
	const char * exp = open_w(*name,exists,flags,fd,fl,str);
    if (good_file(fd,fl,str)) return exp ;
    create_error(*name,exp,exists);
	OutputCurrentChannel << "\n" ;
    return 0 ;
#endif
}

int TargetNode::good_file(int * fd, FILE ** fl, ifstream ** str)
{
	if (fd) if (*fd) return 1 ;
	if (fl) if (*fl) return 1 ;
	if (str) if (*str) return 1 ;
	return 0 ;
}

int TargetNode::good_file(int * fd, FILE ** fl, ofstream ** str)
{
	if (fd) if (*fd) return 1 ;
	if (fl) if (*fl) return 1 ;
	if (str) if (*str) return 1 ;
	return 0 ;
}

const char * TargetNode::def_name(const char * nm)
{
	if (nm) if (*nm) return nm ;
	return GetName();
}


