/*
 *  dfnode.h from ObjectProDSP 0.1
 *  Copyright (C) 1994, Mountain Math Software. All rights reserved.
 *  
 *  This file is part of ObjectProDSP, a tool for Digital Signal
 *  Processing design, development and implementation. It is free
 *  software provided you use and distribute it under the terms of
 *  version 2 of the GNU General Public License as published
 *  by the Free Software Foundation. You may NOT distribute it or
 *  works derived from it or code that it generates under ANY
 *  OTHER terms.  In particular NONE of the ObjectProDSP system is
 *  licensed for use under the GNU General Public LIBRARY License.
 *  Mountain Math Software plans to offer a commercial version of
 *  ObjectProDSP for a fee. That version will allow redistribution
 *  of generated code under standard commercial terms.
 *  
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *  GNU General Public License for more details.
 *  
 *  You should have received a copy of version 2 of the GNU General
 *  Public License along with this program. See file COPYING. If not
 *  or if you wish information on commercial versions and licensing
 *  write Mountain Math Software, P. O. Box 2124, Saratoga, CA 95070,
 *  USA, or send us e-mail at: support@mtnmath.com.
 *  
 *  You may also obtain the GNU General Public License by writing the
 *  Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
 *  USA.  However if you received a copy of this program without the
 *  file COPYING or without a copyright notice attached to all text
 *  files, libraries and executables please inform Mountain Math Software.
 *  
 *  ObjectProDSP is a trademark of Mountain Math Software.
 */
#ifndef DFNODE_DOT_H
#define DFNODE_DOT_H

#include "ObjProGen/errcode.h"
#include "ObjProGui/basic.h"
#include "ObjProDSP/portable.h"
#include "ObjProGen/debug.h"
#include "ObjProGen/slist.h"
#include "ObjProArith/hrdarth.h"
#include "ObjProDSP/timenum.h"
#include "ObjProDSP/entenm.h"
#include "ObjProGui/nodenm.h"
#include "ObjProDSPcom/tarnod.h"
#include "ObjProGui/tarnodpar.h"
#include "ObjProGui/strmstr.h"

class DfNode ;
class DfNodeLink ;
class DfNodeOut ;
class OutTokens ;
class GraphInfo ;
class ProcessNet ;
class TimingDescription ;
class StreamStr ;
class NodeOutChannelHeader ;
class Buffer ;
class TargetNodeParameters ;
class BufferStatus ;
class TraverseParameters ;
class TraverseObject ;
class TargetBufferParameters ;
class ExecutionSequence ;
class Adjustment ;
class BufferDescript ;
class NetworkStateControl ;

// Definition of generic node class all other processing nodes that
// conform to the uniform data flow model should be derived from
// this class.


typedef TraverseResult (DfNode::*MemberFunc)(TraverseObject& obj) ;
typedef TargetAdjustState (ExecutionSequence::*ProcessConsumerSequence)
	(DfNodeOut* one_consumer,TraverseObject& Obj);

class TraverseObject {
	OutTokens& Out ;
	const char * DoingWhat ;
	ostream& HeaderOut ;
	TraverseParameters * Params ;

	MemberFunc ForwardAction ;
	MemberFunc BackwardAction ;

public:
	enum TraverseType {TraverseStandard,TraverseOutputNodesFirst,
		TraverseInputNodesFirst} TheType;

	TraverseObject(OutTokens& out, const char * doing_what,
		ostream& head, TraverseParameters* params=0,
		TraverseType type=TraverseStandard,
		MemberFunc forward=0, MemberFunc backward=0);

	~TraverseObject();
	OutTokens& GetOut() const {return Out;}
	const char * GetDoingWhat() const {return DoingWhat; }
	ostream& GetHeaderOut() {return HeaderOut;}
	ostream& GetMainOut();
	TraverseParameters * GetParameters() const ; // abort if null
	TraverseParameters * parameters() const {return Params;}
	void SetParameters(TraverseParameters * params) {Params=params;}
	void ClearParameters();
	BufferStatus * GetBufferStatus() const ;
	void SetForwardAction(MemberFunc forward);
	void ClearForwardAction() {ForwardAction=0;}
	void SetBackwardAction(MemberFunc backward);
	void ClearBackwardAction() {BackwardAction=0;}
	void SetTraverseType(TraverseType type) {TheType = type;}
	TraverseType GetTraverseType() const {return TheType;}
	TraverseResult DoForwardAction(DfNode& node);
	TraverseResult DoBackwardAction(DfNode& node);
	MemberFunc forward_action() const {return ForwardAction;}
	MemberFunc backward_action() const {return BackwardAction;}
};


class DfNode: public TargetNode {
	enum TraverseFlags {ClearBits=0, FindBit=1,TimeAdjustSourceBit = 2,
		TimingChangeVisit = 4, FreeNodeBit = 8, GenericTraverseBit = 16,
		GenericTraverseComplete = 32, GenericTraverseTouch=64,
		AdjustBit=128};

	int UseInLink ;

	TraverseFlags Flags ;	// Flags bit 31 used for FindNode

	ProcessNet * ActiveNet ;

	int TimingVisitChannel; // Used in setting network timing
	int ChangeTimingIndex;

	int32 ExecCount ;
	int32 ExecLimit ;
	int was_target_created ;

	enum link_delete_state {no_delete_if_unlinked,
		delete_after_buffers_assigned,
		do_delete_if_unlinked} delete_link_state ;
protected:
	enum DfNodeOptionFlags{ClearDfNodeOptions,
		NetworkReferenceDfNodeOption=1} TheDfNodeOptions;
	void delete_if_unlinked(link_delete_state state)
		{delete_link_state = state ;}
	void set_delete_if_unlinked() {delete_link_state =
		delete_after_buffers_assigned;}
private:

	TargetNodeParameters * TargetParameters ;

	void SetTraverseFlag(TraverseFlags flag)
		{Flags = (TraverseFlags) (Flags | flag);}

	void ClearTraverseFlag(TraverseFlags flag)
		{Flags = (TraverseFlags) (Flags & ~flag);}

	int IsTraverseFlag(TraverseFlags flag) const
		{return Flags & flag; }

	void Init() ;
public:
	int32 GetExecCount() const {return ExecCount;}
	int32 GetExecLimit() const {return ExecLimit;}
	void SetExecCount(int32 count) {ExecCount = count;}
	void SubtractExecCount(int32 count) ;

	DfNode(const char * name, int16 in, int16 out, int32 EltSz =1,
		int32 NodeDelay=0, int32 DeltaIn =1, int32 DeltaOut=1,
		int32 Overlap= 0, int32 DelayIn=0, int32 EltSzOut=0,
		int32 BlockSize=1,TimingType timing_type = TimingTypeLinear) ;
	DfNode(const char * name, int16 in, int16 out,
		StreamStr * stream_str_in, StreamStr * stream_str_out = 0,
		int32 NodeDelay=0, int32 DeltaIn =1, int32 DeltaOut=1,
		int32 Overlap= 0, int32 DelayIn=0,
		TimingType timing_type = TimingTypeLinear) ;
	virtual ~DfNode();
	virtual int check_safe_delete();
	virtual DfNode& Clone() ;
	virtual const char * EmitTargetState(OutTokens& Out) ;
	virtual void EmitTargetCtor(OutTokens& Out) ;
	virtual const char * GetCaption() const ;
	virtual ErrCode EmitStaticInit(OutTokens& Out);
	virtual ErrCode EmitStaticCtorParameters(OutTokens& Out);
	virtual int InitAfterLinked();
	int DoInitAfterLinked();
	ErrCode EmitNodeSpecificCtorParameters(OutTokens& Out);
	ErrCode EmitNodeSpecificInit(OutTokens& Out);
	void StreamStrReset(StreamStr * str_out);

	TargetNodeParameters * GetTargetParameters() const
		{return TargetParameters;}
	int IsTargetDefined() const {return TargetParameters != 0;}

	int IsTraverseComplete() const
		{return IsTraverseFlag(GenericTraverseComplete);}

	int AllInputsTraversed() const ;
	int AllOutputsTraversed() const ;

	void SetTargetParameters(TargetNodeParameters * target_param)
		{TargetParameters = target_param ; }

	int GetOut() const {return Out;}
	int MultipleOutputs(){return Out > 1;}
	int GetIn() const {return In;}

	int32 GetEltSize(int index=0) ;
	int32 GetInEltSize(int index=0) ;
	int32 GetInDataPerExe(int chan=0);
	int32 GetDriverElementSize(int chan=0) ;
	void SetElementSizeOut(int OutChannel, int32 ElementSize) ;
	void SetElementSizeIn(int InChannel, int32 ElementSize) ;
	void SetFromDisk(const NodeOutChannelHeader& DiskState,
		int Channel = 0);
	void SetInputFromDisk(const NodeOutChannelHeader& DiskState,
		int Channel = 0);
	NodeOutChannelHeader * GetDiskState(int Channel = 0);
	NodeOutChannelHeader * GetOutDiskState(int Channel = 0);
	void DisplayInputTiming(int16 Channel);
	void DisplayOutputTiming(int16 Channel);

	DfNodeOutLink * GetOutLink(int i=0) const ;
	int GetFreeOutLink();
	int IsFeedbackHead() const ;
	int IsInFeedbackLoop() const ;
	void SetInLink(DfNodeLink * lk, int i, int OutputChan) ;

	void ClearHistory() { History = 0;}

	void Clear() ;
	ErrCode Append(DfNode * node, int OutputLk=0, int InputLk = 0,
		int Flag=1) ;
		// If InputLk is negative then UseInLink should be used
	DfNode * FindTail(int OutChannel) ;
	DfNodeInLink * GetInLink(int i=0) const ;
	void Display();
	void NameDisplay();
	int AssignBuffers(BufferDescript * Des);
	int CheckComplete();
	int net_complete();
	int32 ExecuteNode(int32 k) ; 
	int ExecuteTail() ;
	int DoTail() ;
	int32 GetInDataPerExe(int Channel=0) const ;
	int32 GetOutDataPerExe(int Channel=0) const ;

	void SetTimingVisitChannel(int channel ){TimingVisitChannel = channel;}
	void ClearTimingVisitChannel() {TimingVisitChannel = -1;}
	int GetTimingVisitChannel() {return TimingVisitChannel;}

	DfNode * FindNode(const char *) ;
	DfNode * FindNode(const DfNode *) ;
	DfNodeOutLink * GetDriverOutputChannel(int InChannel = 0) ;
	DfNode * GetDriverNode(int InChannel = 0);
	void GraphDisplay(GraphInfo&, int channel= -1);
	DfNode& LinkIn( int Chan) { UseInLink = Chan ; return *this; }
	int GetUseInLink() {return UseInLink ;}
	int GetFreeInLink() ;
	void ClearUseInLink() {UseInLink = 0 ;}
	virtual void Describe(OutTokens&, ListEntity) ;
		// interactive execution descrive
	int AssignTiming(TimingDescription&, int InputChannel = -1 );
	virtual TimingDescription * GetInitTiming(int InputChannel);
	virtual double TimeFirst(DfNodeInLink *In, DfNodeOutLink * Out) ;
	virtual double AlignChannels(int ChannelAdjust) ;
	TimingDescription * GetTiming(int Index);
	int32 GetIncrementIn(int Index) const ;
	int32 GetIncrementOut(int Index) const ;
	int32 GetDelay(int Index) const  ;
	int32 GetOverlap(int Index) const ;
	int ClearBuffers();
	int DeleteAllLinks(class DfNodeList * List = 0);
	int DeleteNetwork();
	int ChangeTiming(class TimingAdjustment& Adjust, int SkipIndex = -1) ;
	const char * GetFreeNodeIn();
	const char * GetFreeNodeOut();
	int SetActiveNet (ProcessNet * Net) ;
	ProcessNet * GetActiveNet() const {return ActiveNet;}
	const char * GetNetName() const ;
	int CheckNetComplete() ;
	int check_complete() ;
	int CheckLinked() ;
	void MustBeActiveNet() ;
	virtual void NewSampleRate();
	void SetSampleRate(double Rate, int16 Channel);
	void AdjustSampleRate(TimingDescription& timing) ;
					     // adjust consistent with this
	int32 GetBlockSize(int Channel=0) ;
	double GetMinimumX(int Channel=0) ;
	double GetMaximumX(int Channel=0) ;
	const StreamStr * GetOutputStreamStr(int Channel = 0) const ;
	void AdjustOutputLinks(const StreamStr * strm_str);
	int ExactCountExecute() const ;
	int CheckBufferSpace() const ;
	Buffer* GetInputBuffer(int chan = 0) const ;
	Buffer* GetOutputBuffer(int chan = 0) const ;
	ErrCode GetNodeState() const {return NodeState ; }

	TargetAdjustState ProcessConsumerSequences(
		ProcessConsumerSequence process,
		class ExecutionSequence& seq, class TraverseObject& obj) ;

	TraverseResult WriteObject(TraverseObject& obj);
	TraverseResult WriteTargetState(TraverseObject& obj);
	TraverseResult SetTargetInitSequence(TraverseObject& obj);
	TraverseResult ReconcileTargetInitSequence(TraverseObject& obj);

	TraverseResult AssignMultiples(TraverseObject& obj);

	TraverseResult SetTargetSequence(TraverseObject& obj);
	TraverseResult ReconcileTargetSequence(TraverseObject& obj);
	TraverseResult CheckTargetBufferSize(TraverseObject& obj);
	TraverseResult WriteTargetBuffers(TraverseObject& obj);
	TraverseResult ClearTargetParameters(TraverseObject& obj);

	TraverseResult EmitThreadTable(TraverseObject& obj);
	TraverseResult SetTerminalNodeResampling(TraverseObject& obj);

	TraverseResult X_graph_display(TraverseObject& obj);
	TraverseResult replacement_list(TraverseObject& obj);
	TraverseResult independent_thread_check(TraverseObject& obj);
	

	void ClearTargetInParameters(int InChan);
	TraverseResult Traverse(TraverseObject& obj) ;
	void ClearTraverse() ;
	TargetBufferParameters * GetTargetBufferIn(int InChan) const ;
	TargetAdjustState AdjustTargetBufferIn(int InChan, int32 NewSize) ;

	TargetAdjustState DoAdjust(Adjustment& adjust);
	TargetAdjustState AdjustForward(Adjustment& adjust);
	TargetAdjustState AdjustBackward(Adjustment& adjust);
	ErrCode DoReset();
	int32 GetMinInBufferSize(int InChan) const ;
	int32 GetMinOutBufferSize(int OutChan) const ;
	NetworkStateControl** GetNetworkReference();
	StreamStr * GetInStream(int Chan = 0) const ;
	StreamStr * GetOutStream(int Chan = 0) const ;
	void InitArithType(ArithType::ArithTypes type);
	void InitArithType(ArithType::ArithCapabilities type);

    void NextFreeInput ();
    void NextFreeOutput ();

    void Unlink();
	void UnlinkInputChannel(int channel);
	void UnlinkOutputChannel(int channel);

	void RemoveAllLinks();
	int any_links() const ;
	void disconnect_in(int channel);
	void disconnect_out(int channel);
	void decrement_buffer_channel(int input_channel, int new_value);
	virtual DfNode * target_replacement(const char * target);
	DfNode * default_output_replacement(const char * target);
	DfNode * default_input_replacement(const char * target);
	virtual void clear_buffers();
	virtual void input_linked(int in_channel);
	void raise_window();
	void add_to_net_graph();
	void DeassignBufferDescriptor(BufferDescript * des);
	void new_buffer_channel(int in_channel,int buffer_channel);
	void EditNetwork(const char * edit_what);
	int delete_if_unlinked()
		{return delete_link_state == do_delete_if_unlinked ;}
	void clear_thread() ; // if in thread list and no output links remove
						  // prevents error from `operator+' geerated by
						  // graphical editing 
// set_read_binary is obsolete
#define set_read_binary_flag set_read_integer_flag

	int set_read_integer_flag(int& flg);
	ErrCode propagate_arith_type(int in_channel, int min_bits = 0);

	void target_created(int set) {was_target_created = set;}
	int target_created() const {return was_target_created;}

	static const char * interactive_create_file(const char ** name,
		const char * prompt_file_type, int flags, int * fd,
		FILE ** fl, ofstream ** str) ;

	static const char * interactive_open_file(const char ** name,
		const char * prompt_file_type, int force_error,
        int * fd, FILE ** fl, ifstream ** str) ;

	static void open_problem(const char * name, const char * exp,
		const char *msg=0);

	static void create_problem(const char * name, const char * exp, int exists);
	
};

#endif /* #ifdef DFNODE_DOT_H */
