/*
 *  network.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.
 */
// This file contains the definitions to build a network.

// A Net may have several unrelated threads.
// Each thread can be a tree structure.
// Multiple threads may be input to a single process.
// Feedback is a special case. 

// There is a time scale associated with each thread and
// a time delay associated with each node.
// The scale is necessary whenever two threads are connected
// to the same inputs of a single node. They must be synchronized
// based on this delay. 

// Each link must have a single input node and can have any
// number of output nodes. Since nodes can be added at any time
// a link list is needed for this.

#ifndef NETWORK_DOT_H
#define NETWORK_DOT_H
#include "ObjProGen/debug.h"
#include "ObjProNet/dfnode.h"
#include "ObjProGui/nodelst.h"

class ProcessNet ;
class NetControl ;
class StreamStr ;
class BufferDescript ;
class Buffer ;
class DfNodeOutList ;
class OutTokens ;
class TimingDescription ;
class DfNodeList ;
class ThreadList ;
class Thread ;
class TargetBufferParameters ;
class Adjustment ;
class NodeReplacementList ;

class GraphInfo {
	uint32 Flags;
		// First bit set indicates detailed graphical display
		// Second bit indicates timing display
		// Third bit indicates state dump in C++ format
		// Fourth bit indicates continuation of a thread
	OutTokens * Out ;
public:
	const char * NodeName ;
	const char * NetName ;
	int OutChannel ;
	OutTokens * GetOut() {return Out;}
	GraphInfo(OutTokens& out) ;

	int DoTime() { return Flags&2; }
	void SetTime() { Flags |= 2 ;}
	void ClearTime() {Flags |= ~2;}
	
	int DoFull() { return Flags&1;}
	void SetFull() {Flags |= 1;}
	void ClearFull() {Flags &= ~1;}

	int DoCpp() {return Flags&4;}
	void SetCpp() {Flags |= 4;}
	void ClearCpp() {Flags &= ~4;}

	int Continuation() {return Flags&8;}
	void SetContinuation() {Flags |= 8;}
	void ClearContinuation() {Flags &= ~8;}

	void ClearFlags() {Flags = 0 ;}
	void OutErrorEnd(const char *EndMsg);
};

class DfNodeIn { // Node that generates this data
	DfNode * TheNode ;
	int Index ; // Output channel of `Node' for this link
public:
	DfNodeIn (DfNode * Nd, int Ix) {TheNode = Nd ; Index = Ix ; }
	DfNode * GetNode() const { return TheNode ; }
	int GetIndex() const { return Index ;}
	int32 GetEltSize() ;
	void NameDisplay() ;
	int32 GetIncrementOut() ;
	TimingDescription *  GetTiming() ;
	int GetChannel() {return Index; }
	int DeleteAllLinks(DfNodeList * List = 0);
	const StreamStr * GetDriverStreamStr() const ;
	DfNodeOutLink * GetOutLink() const ;
	TargetAdjustState Adjust(Adjustment& );
	int32 GetMinBufferSize() const
		{return TheNode->GetMinOutBufferSize(Index);}
	void Unlink();
} ;

class DfNodeOut {
	DfNode * TheNode ;   	// Node data is sent to
	int Index ;		// Input channel of `Node' for this link
	int SelfLink ;		// If set this is the base of a feedback loop
	
	int NullNodeCk(const char * Routine) ;
public:
	DfNodeOut (DfNode * Nd, int Ix, int Self=0) ;
	DfNode * GetNode() const { return TheNode ; }
	int GetIndex() const { return Index ;}
	int DoTail() { return TheNode->DoTail();}
	DfNode * FindNode(const char *) ;
	DfNode * FindNode(const DfNode *) ;
	int CheckComplete() ;
	int AssignBuffers(BufferDescript* Des) ;
	void Display() ;
	void NameDisplay() ;
	void GraphDisplay(GraphInfo& GraphOut) ;
	int AssignTiming(TimingDescription& Timing)
		{return TheNode->AssignTiming(Timing,Index);}
	int GetChannel() {return Index; }
	int ClearBuffers();
	int DeleteAllLinks(DfNodeList * List = 0);
	TraverseResult Traverse(TraverseObject& obj) ;
	void ClearTraverse() ;
	int IsFeedbackHead() const {return SelfLink;}
	int AnyConsumerOverlap() const ;
	DfNodeInLink * GetConsumerLink() const ;
	DfNodeOutLink * GetFeederLink() const ;
	int IsTargetDefined() const ;
	int IsTraverseComplete() const ;
	TargetAdjustState Adjust(Adjustment& );
	ErrCode Reset();
	int32 GetMinBufferSize() const
		{return TheNode->GetMinInBufferSize(Index);}
	ErrCode CheckArithType(const StreamStr&) const ;
	void remove_this_link();
	void decrement_buffer_channel(int new_value)
		{TheNode->decrement_buffer_channel(Index, new_value);}
	void DeassignBufferDescriptor(BufferDescript * des);
	void new_buffer_channel(int new_chan);
	void Unlink();
} ;


class DfNodeLink {
	DfNodeIn * InputLink ;
	DfNodeOutList * OutputLinks ;
	DfNodeOut ** OutputArray ;
	int OutSize ;
	BufferDescript * descriptor ;
	Buffer * DataBuffer ;
public:
	DfNodeLink(DfNode * Source, int Index) ;
	~DfNodeLink();
	int CkNullBuffer(const char * name) ;
	void Display();
	void NameDisplay();
	DfNodeOut * GetDfNodeOut(int i) const ;
	DfNodeInLink * GetConsumerLink(int i) const
		{return GetDfNodeOut(i)->GetConsumerLink();}
	DfNode * FindTail() ;
	DfNode * GetInputNode() {return InputLink->GetNode();}
	DfNode * GetOutputNode(int i) {return OutputArray[i]->GetNode();}
	int AppendOut(DfNode * node, int InIndex, int SelfLink=0) ;
	Buffer * GetDataBuffer() const {return DataBuffer;}
	DfNodeIn * GetInputLink() { return InputLink;}
	int CheckComplete(const char * nm) ;
	int Size() ;
	int GetOutSize() const {return OutSize;}
	int AssignBuffers(BufferDescript * Des);
	int32 GetEltSize() ;
	int DoTail() ;
	void UpdateRead(int32 Size,int chan); // Add Size words to read pointer
	MachWord * GetBase() ;
	MachWord * GetEnd()  ;
	const MachWord * GetReadPtr(int chan) ;
	const BinMachWord * GetBinReadPtr(int chan)
		{return (BinMachWord *) GetReadPtr(chan);}
	void UpdateWrite(int32 Size); // Add Size words to read pointer
	MachWord * GetWritePtr() ;
	BinMachWord * GetBinWritePtr()
		{return (BinMachWord *) GetWritePtr();}
	void WriteCxWord(CxMachWord Data) ;
	CxMachWord ReadCxWord(int Index) ;
	void WriteBinary(BinMachWord Data) ;
	void WriteWord(MachWord Data) ;
	int GetSpace() ;
	int GetContiguousSpace() ;
	BinMachWord ReadBinary(int Index) ;
	MachWord ReadWord(int Index) ;
	int GetAvailableData(int Ix);
	int GetContiguousAvailableData(int Ix);

	DfNode * FindNode(const char *) ;
	DfNode * FindNode(const DfNode *) ;
	void GraphDisplay(GraphInfo&);
	TimingDescription * GetTiming() ;
	int AssignTiming(TimingDescription& Timing) ;
	int ChangeTiming(TimingAdjustment& Adjust) ;
	int ChangeInTiming(TimingAdjustment& Adjust) ;
	int GetOutputNodeInputChannel(int BufferChannel) {return OutputArray ?
		OutputArray[BufferChannel]->GetChannel() : -1;}
	int GetInputNodeOutputChannel() {return InputLink ?
		InputLink->GetChannel() : -1;}
	DfNodeOutLink * GetDriverOutputChannel(int DriverOutChannel);
	int ClearBuffers();
	int DeleteAllLinks(const char * Name,DfNodeList * List = 0);
	const char * GetFreeNodeIn();
	const char * GetFreeNodeOut();
	void AdjustInputSampleRate(TimingDescription& timing) ;
	void AdjustOutputSampleRate(TimingDescription& timing) ;
					     // adjust consistent with this
	const StreamStr * GetDriverStreamStr() const ;
	TraverseResult Traverse(TraverseObject& obj) ;
	void ClearTraverse() ;
	int IsFeedbackHead() const ;
	int AnyConsumerOverlap() const ;
	int GetDriverOutputChannelIndex() const
		{return InputLink->GetIndex();}
	int GetDriverOutputChannel() const ;
	int IsTargetDefined() const ;
	int IsTraverseComplete() const ;
	TargetAdjustState AdjustTargetBuffer(int32 NewSize) ;
	void ClearTargetParameters();
	TraverseResult CheckTargetBufferSize(TraverseObject& obj);
	TargetBufferParameters * GetTargetBuffer() const ;

	TargetAdjustState AdjustForward(Adjustment& TheAdjustment);
	TargetAdjustState AdjustBackward(Adjustment& TheAdjustment);
	ErrCode Reset();
	int32 GetMinBufferSize() const ;
	ErrCode CheckArithType() const ;
	DfNodeOutList * GetOutputLinks() const {return OutputLinks;}
	void remove_this_input_link();
	void remove_this_output_link(DfNode * driven, int input_channel);
	void clear_output_array();
	void DeassignBufferDescriptor(BufferDescript * des);
	void UnlinkDriven(int buffer_channel);
	void Unlink();
	int DoInitAfterLinked();
} ;

class ProcessNet : public UserEntity {
friend NetControl ;
	ThreadList * Threads ;
	DfNodeList unlinked_nodes ;
	DfNode * LastAccessed ; 	// where to append a new node
	int NextOut ;			// output channel index to append to

	DfNode * LastMultipleAccessed ; // where to append a node if
					// LastAccessed has no free links

	int TheFlag ;			// if clear we can allow multiple
					// taps from a single buffer
	NetControl * TheController;
	int displayed ;
	NetworkStateControl TheNetworkReference ;
	void UpdateAccess(DfNode * node) ;
protected:
	int in_validate ;
	int exact_timing ;
public:
	ProcessNet(const char * name) ;
	NetworkStateControl& GetNetworkReference() {return TheNetworkReference;}
	virtual ~ProcessNet();
	virtual int check_safe_delete();
	void Init() ;
	void CreateController();
	ProcessNet& Link(const char *, int OutChannel=0) ;
	ProcessNet& Link(DfNode& , int OutChannel=0) ;
	ProcessNet& Link(int OutChannel) {NextOut=OutChannel; return *this ;}
	void Display() ;
	void GraphDisplay(char FullDisplay = 0, int16 x = -1, int16 y = -1);
	void GraphDisplay(int16 x, int16 y);
	// void Describe(OutTokens&,enum ListEntity);

	ProcessNet& operator>>(DfNode& node) ;

	ProcessNet& operator+(DfNode& node) ;
	ProcessNet& AddThread(DfNode& node) ;
	ProcessNet& SelfLink(DfNode& , DfNode&  ,
		int SourceChannel=0, int DestChannel=0);
	ProcessNet& SelfLink(char *, char *,
		int SourceChannel=0, int DestChannel=0);
	void ReplaceNode(DfNode& ToReplace, DfNode& Replacement);
	DfNode * FindNode(const char *) ;
	DfNode * FindNode(const DfNode *) ;
	DfNode * GetFirstThreadEntry() ;
	ThreadList * GetThreads() { return Threads;}
	const char * GetFreeNodeIn();
	const char * GetFreeNodeOut();
	const char * DoStateEmit(OutTokens& Out);
	int DeleteAllLinks(DfNodeList * list = 0) ;
	void ClearActiveNetwork();
	void SetTheController(NetControl * cnt) ;
	void clear_controller() ;
	void unedit();
	NetControl * GetTheController() {return TheController; }
	int CheckNodeNetwork(DfNode& node) ;
	void Execute(int32 InputSamples);
	void AssignBuffers(BufferDescript& Desc);
	void set_buffer_descriptor(BufferDescript& Desc);
	void ClearBuffers();
	void ClearNetwork();

	void WriteKernelNodes(TraverseObject& Obj) ;
	void WriteTargetState(TraverseObject& Obj) ;
	void TraverseNetwork(TraverseObject& obj) ;
	void ClearTraverse() ;

	void CreateStaticExecutionTables(TraverseObject& Obj);
	void ClearTargetParameters(TraverseObject& Obj) ;

	void EmitThreadTable(TraverseObject& Obj, const char *StateName,
		const char *IncludeName=0) ;
	void EmitThreadTable(TraverseObject &Obj);
	void Traverse(TraverseObject&);
	void TraverseThread(TraverseObject&, DfNode& node);

	int CheckComplete();
	ErrCode Reset();
	void InitArithType(ArithType::ArithTypes type) ;
	void X_graph_display(int16 x, int16 y);
	void list_replacements(NodeReplacementList& list);
	void remove_signal_node(DfNode& node); // sets warn_flag
	void clear_signal_node(DfNode& node, int warn_flag=0);
	void DeassignBufferDescriptor(BufferDescript * des);
	int DoAssignBuffers(BufferDescript* Des) ;
	void add_unlinked_node(DfNode * node);
	void remove_unlinked_node(DfNode * node);
	int is_displayed() const {return displayed;}
	void set_displayed() {displayed = 1 ;}
	void set_redisplay() { if (displayed & 1) displayed = 3 ;}
	int need_redisplay() const {return displayed & 2;}
	int independent_thread(Thread* a, Thread *b);
	int is_exact_timing() const {return exact_timing;}
} ;

void ProcessNetsInit() ;
const char * DefaultNotLegal(UserEntity *);
const char * GetFreeNodeIn(UserEntity * TheNet);
const char * GetFreeNodeOut(UserEntity * TheNet);

#endif /* #ifdef NETWORK_DOT_H */
