/*************************************************************************/
/*	File : CKBehavior.h			 				 						 */
/*	Author :  Nicolas Galinotti											 */	
/*																		 */	
/*	Virtools SDK 														 */	 
/*	Copyright (c) Virtools 2000, All Rights Reserved.					 */	
/*************************************************************************/
#ifndef CKBEHAVIOR_H

#define CKBEHAVIOR_H "$Id:$"

#include "CKObject.h"
#include "XObjectArray.h"
#include "XPriorityQueue.h"

struct BehaviorBlockData;		
struct BehaviorGraphData;		





/**************************************************************************
{filename:CKBehavior}
Name: CKBehavior

Summary: Class for defining behaviors

Remarks:
	+ The CKBehavior class provides functionnalities for defining a behavior as a function or as a graph,
	to set various parameters about how and when the behavior is activated,
	to link them to other behaviors through CKBehaviorLink instances or to create
	them from CKBehaviorPrototype, for creating CKBehaviorPrototype from a behavior.

	+ Each behavior has an owner, which is an instance of CKBeObject. The owner saves its
	behaviors with itself when saved into a file, or with CKSaveObjectState. The behavior
	usually applies to its owner, or to parts of its owner, though it can apply to other
	objects as well. If the behavior is a graph, all of its sub-behaviors inherits the same owner.

	+ A Behavior is considered to as a box with inputs/ouputs and input,output and local parameters.
	Inside this box the behavior may be implemented using a graph of sub-behaviors or using a C++ function, 
	depending on which method UseGraph or UseFunction has been specified. For behaviors using a function,
	the function may be defined internally, or in a external code file (dll, or other depending on the OS).

	+ If you want to implement the behavior with a C++ funtion without defining a prototype, you should specify the function with the
	SetFunction() method. This function will be called at each process cycle, with one argument:
	the elapsed time since the last call, in milliseconds.

	+ Behaviors are real time pieces of algorithm. When a behavior is active and enabled or is waiting for a message, it gets
	called in an iterative fashion at each loop of the process cycle. Each time it is called, the behavior
	does the minimum amount of processing depending on the time elapsed since the last time it was called.
	No behavior should hold on the CPU more than necessary, as each other active behaviors have to be called
	in the process cycle.

	+ Behavior execution is managed by its owner, and by the scene to which its owner belongs.
	A CKBeObject instance is declared in its scene as being active and/or enabled with the CKScene::SetObjectFlags or CKScene::Activate method.
	A disabled object's behaviors are never called. Setting an object as active has the effect of having
	all of its behaviors called during the next process cycle. If you add an object to a scene and
	want its behaviors to be called when the scene is started with CKLevel::LaunchScene, you should
	set the flags accordingly with CKScene::SetObjectFlags.
	If you don't use Scene or have only one scene (the level) setting the flags is not necessary.

	+ If the behavior is implemented using an execution function, this function decides whether the
	behavior should remain active or not. This is done with the return value of the
	function. If the return value is CKBR_OK, the behavior is considered as being over and is set to be inactive
	at the next process cycle. It may become active again at a later time, if one of its entries gets
	activated.

	+ If the behavior is implemented as a graph of sub-behaviors, it is considered active if at least one of its sub-behaviors is active, and
	will be called during the next process cycle.

	+ Behavior prototypes are a sort of model of behaviors. One can create a behavior from a prototype.
	Prototypes are typically used in external pieces of code like dlls.	Prototypes are typically used
	for storing reusable behaviors.

	+ Behaviors usually have inputs and outputs, which may be active or inactive. The inputs and outputs have
	no value, they are like switches which may be on or off. A behavior is activated if at least one of its entries is
	active. When all of the entries are inactive and all of its sub-behaviors are inactive and the behavior is not waiting for a message, the behavior
	is deactivated.

	+ The outputs of a behavior are activated or deactivated by the behavior, as a result of its internal
	processing and states. Outputs of a behavior may be linked to other behaviors through links, in which case
	activating an output will trigger the activation of one or more other behaviors. This is the basic principle
	through which processing travels along behaviors.

	+ A behavior may have zero or more inputs and zero or more outputs. The output of a behavior may be linked to
	an input of the same behavior.

	+ Outputs of a behavior are linked to inputs or other behaviors through instances of CKBehaviorLink.
	These links have an activation delay, which may be 0. If it is zero, the input gets activated at the same
	process cycle which may introduce infinite loops. Such Loops are detected at execution time when exceding
	the value defined by CKSetBehaviorMaxIteration (Default : 8000) 


	+ Behaviors may exchange or store values using parameters, which are instances of
	CKParameterOut, CKParameterIn. These values may be arbitrarily complex, and
	you may define your own type of parameters. CKParameterOut instances are used by the behavior to export values,
	and CKParameterIn instances are used to get values from the outside.

	+ Components of a behavior like parameters, I/O may be named, like all objects of CK. This name
	is only a conveniency and is not mandatory. These names are saved in the state or in the file
	with the behavior and may eat up space, so you should use them carefully if this is an issue for
	your application.

	+ Behaviors may wait for messages. They specify that they wait for messages by registering
	themselves with the message manager, using the CKMessageManager::RegisterWait method and by providing
	an input or an output to activate when a corresponding message is received. 

	+ The class id of CKBehavior is CKCID_BEHAVIOR.




See also: CKBeObject, CKScene, CKParameterOut, CKParameterIn, CKBehaviorLink, CKBehaviorPrototype
************************************************************************************/
class CKBehavior : public CKSceneObject {
friend class CKBehaviorManager;
friend class CKBeObject;
friend class CKFile;
friend class CKParameterIn;
friend class CKParameter;
friend class CKParameterLocal;
friend class CKParameterOut;
friend class CKParameterOperation;
friend class CKBehaviorLink;
friend class CKBehaviorIO;


public :

//----------------------------------------------------------------
// Behavior Typage
	CK_BEHAVIOR_TYPE	GetType();
	void				SetType(CK_BEHAVIOR_TYPE);

	void				SetFlags(CK_BEHAVIOR_FLAGS );
	CK_BEHAVIOR_FLAGS	GetFlags();
	CK_BEHAVIOR_FLAGS	ModifyFlags(CKDWORD Add,CKDWORD Remove);


//---------- BuildingBlock or Graph
	void		UseGraph();	
	void		UseFunction();
	int 		IsUsingFunction();

//----------------------------------------------------------------
// Targetable Behavior
CKBOOL			IsTargetable();
CKBeObject*		GetTarget();
CKERROR			UseTarget(CKBOOL Use=TRUE);
CKBOOL			IsUsingTarget();
CKParameterIn*	GetTargetParameter();
void				SetAsTargetable(CKBOOL target=TRUE);
CKParameterIn*	ReplaceTargetParameter(CKParameterIn* targetParam);
CKParameterIn*	RemoveTargetParameter();

//----------------------------------------------------------------
// Object type to which this behavior applies
	CK_CLASSID			GetCompatibleClassID();
	void				SetCompatibleClassID(CK_CLASSID);

//----------------------------------------------------------------
// Execution Function
	void				SetFunction(CKBEHAVIORFCT fct);
	CKBEHAVIORFCT		GetFunction();	

//----------------------------------------------------------------
// Callbacks Function
	void		SetCallbackFunction(CKBEHAVIORCALLBACKFCT fct);
	int 		CallCallbackFunction(CKDWORD Message); 
	int 		CallSubBehaviorsCallbackFunction(CKDWORD Message,CKGUID* behguid=NULL);


//--------------------------------------------------------------
// RunTime Functions
	CKBOOL		IsActive();
	int			Execute(float deltat);

//--------------------------------------------------------------
// 
CKBOOL		IsParentScriptActiveInScene(CKScene *scn);
int			GetShortestDelay(CKBehavior* beh);

//--------------------------------------------------------------
// Owner Functions
	CKBeObject *GetOwner();
	CKBehavior *GetParent();
	CKBehavior *GetOwnerScript();

//----------------------------------------------------------------
// Creation From prototype 
CKERROR	InitFromPrototype(CKBehaviorPrototype *proto);
CKERROR	InitFromGuid(CKGUID Guid);
CKERROR  InitFctPtrFromGuid(CKGUID Guid);
CKERROR  InitFctPtrFromPrototype(CKBehaviorPrototype *proto);
CKGUID	GetPrototypeGuid();
CKBehaviorPrototype* GetPrototype();
CKSTRING GetPrototypeName();
CKDWORD  GetVersion();
void		SetVersion(CKDWORD version);

//----------------------------------------------------------------
// Outputs 
	void			ActivateOutput(int pos,CKBOOL active=TRUE);
	CKBOOL			IsOutputActive(int pos);
CKBehaviorIO*	RemoveOutput(int pos);
	CKERROR			DeleteOutput(int pos);
CKBehaviorIO*	GetOutput(int pos); 
	int				GetOutputCount();
int				GetOutputPosition(CKBehaviorIO *pbio); 
	int				AddOutput(CKSTRING name);
CKBehaviorIO*	ReplaceOutput(int pos,CKBehaviorIO *io);
 CKBehaviorIO*	CreateOutput(CKSTRING name); 
void			InsertOutput(int pos,CKBehaviorIO *io); 


//----------------------------------------------------------------
// Inputs 
	void			ActivateInput(int pos,CKBOOL active=TRUE);
	CKBOOL			IsInputActive(int pos);
CKBehaviorIO*	RemoveInput(int pos); 
	CKERROR			DeleteInput(int pos);
CKBehaviorIO*	GetInput(int pos); 
	int				GetInputCount();
int				GetInputPosition(CKBehaviorIO *pbio);
	int				AddInput(CKSTRING name);
CKBehaviorIO*	ReplaceInput(int pos,CKBehaviorIO *io);
CKBehaviorIO*	CreateInput(CKSTRING name); 
void			InsertInput(int pos,CKBehaviorIO *io); 

//----------------------------------------------------------------
// inputs Parameters
	CKERROR			ExportInputParameter(CKParameterIn *p);
	CKParameterIn*	CreateInputParameter(CKSTRING name,CKParameterType type);
	CKParameterIn*	CreateInputParameter(CKSTRING name,CKGUID guid);
	CKParameterIn*	InsertInputParameter(int pos,CKSTRING name,CKParameterType type);
	void			InsertInputParameter(int pos,CKParameterIn *in);
	void			AddInputParameter(CKParameterIn *in);
	int				GetInputParameterPosition(CKParameterIn *);
	CKParameterIn*	GetInputParameter(int pos);
	CKParameterIn*	RemoveInputParameter(int pos);		
	CKParameterIn*	ReplaceInputParameter(int pos,CKParameterIn *param);		
	int 			GetInputParameterCount();
	CKERROR 		GetInputParameterValue(int pos,void *buf);
	void*			GetInputParameterReadDataPtr(int pos);
	CKObject* 		GetInputParameterObject(int pos);
	CKBOOL			IsInputParameterEnabled(int pos);
	void			EnableInputParameter(int pos,CKBOOL enable);


//----------------------------------------------------------------
// outputs Parameters
	CKERROR			ExportOutputParameter(CKParameterOut *p);
	CKParameterOut*	CreateOutputParameter(CKSTRING name,CKParameterType type);
	CKParameterOut* CreateOutputParameter(CKSTRING name,CKGUID guid);
	CKParameterOut* InsertOutputParameter(int pos,CKSTRING name,CKParameterType type);
	void			InsertOutputParameter(int pos,CKParameterOut* p);
	CKParameterOut* GetOutputParameter(int pos);
	int				GetOutputParameterPosition(CKParameterOut*);
	CKParameterOut* ReplaceOutputParameter(int pos,CKParameterOut *p);		
	CKParameterOut* RemoveOutputParameter(int pos);		
	void			AddOutputParameter(CKParameterOut *out);
	int 			GetOutputParameterCount();
	CKERROR 		GetOutputParameterValue(int pos,void *buf);
	CKERROR 		SetOutputParameterValue(int pos,const void *buf,int size=0);
	void*			GetOutputParameterWriteDataPtr(int pos);
 CKERROR			SetOutputParameterObject(int pos,CKObject *obj);
	CKObject* 		GetOutputParameterObject(int pos);
	CKBOOL			IsOutputParameterEnabled(int pos);
	void			EnableOutputParameter(int pos,CKBOOL enable);


	void			SetInputParameterDefaultValue(CKParameterIn *pin,CKParameter* plink); 

//----------------------------------------------------------------
// Local Parameters
	CKParameterLocal*	CreateLocalParameter(CKSTRING name,CKParameterType type);
	CKParameterLocal*	CreateLocalParameter(CKSTRING name,CKGUID guid);
	CKParameterLocal*	GetLocalParameter(int pos);
	CKParameterLocal*	RemoveLocalParameter(int pos);		
	void				AddLocalParameter(CKParameterLocal *loc);
	int					GetLocalParameterPosition(CKParameterLocal *);
	int					GetLocalParameterCount();
	CKERROR 			GetLocalParameterValue(int pos,void *buf);
	CKERROR 			SetLocalParameterValue(int pos,const void *buf,int size=0);
	void*				GetLocalParameterWriteDataPtr(int pos);
	void*				GetLocalParameterReadDataPtr(int pos);
	CKObject* 			GetLocalParameterObject(int pos);
 CKERROR				SetLocalParameterObject(int pos,CKObject *obj);
	CKBOOL				IsLocalParameterSetting(int pos);
	CKParameterLocal*	InsertLocalParameter(int pos,CKSTRING name,CKParameterType type);
	void				InsertLocalParameter(int pos,CKParameterLocal* p);

//----------------------------------------------------------------
// Run Time Graph : Activation
void Activate(CKBOOL Active = TRUE,CKBOOL breset = FALSE);

//----------------------------------------------------------------
// Run Time Graph : Sub Behaviors
	CKERROR				AddSubBehavior(CKBehavior *cbk);	
	CKBehavior *		RemoveSubBehavior(CKBehavior *cbk);	
	CKBehavior *		RemoveSubBehavior(int pos);	
	CKBehavior *		GetSubBehavior(int pos);	
	int					GetSubBehaviorCount();

//----------------------------------------------------------------
// Run Time Graph : Links between sub behaviors
	CKERROR				AddSubBehaviorLink(CKBehaviorLink *cbkl);	
	CKBehaviorLink *	RemoveSubBehaviorLink(CKBehaviorLink *cbkl);	
	CKBehaviorLink *	RemoveSubBehaviorLink(int pos);	
	CKBehaviorLink *	GetSubBehaviorLink(int pos);	
	int					GetSubBehaviorLinkCount();	

//----------------------------------------------------------------
// Run Time Graph : Parameter Operation
	CKERROR					AddParameterOperation(CKParameterOperation *op);	
	CKParameterOperation *	GetParameterOperation(int pos);
	CKParameterOperation *	RemoveParameterOperation(int pos);	
	CKParameterOperation *	RemoveParameterOperation(CKParameterOperation *op);
	int 					GetParameterOperationCount();


//----------------------------------------------------------------
// Run Time Graph : Behavior Priority
	int GetPriority();
	void SetPriority(int priority);

//------- Profiling ---------------------
	float GetLastExecutionTime();

//-------------------------------------------------------------------------
// Internal functions 
#ifdef DOCJETDUMMY // DOCJET secret macro
#else

CKERROR	SetOwner(CKBeObject *,CKBOOL callback = TRUE);
CKERROR	SetSubBehaviorOwner(CKBeObject *o,CKBOOL callback = TRUE);

void NotifyEdition();	
void NotifySettingsEdition();	

CKStateChunk* GetInterfaceChunk();
void SetInterfaceChunk(CKStateChunk *state);


			CKBehavior(CKContext *Context,CKSTRING name=NULL);						
	virtual	~CKBehavior();															
	virtual CK_CLASSID GetClassID();												

	virtual void			PreSave(CKFile *file,CKDWORD flags);					
	virtual CKStateChunk*	Save(CKFile *file,CKDWORD flags);						
	virtual CKERROR			Load(CKStateChunk *chunk,CKFile* file);					
	virtual void			PostLoad();												

	virtual void			PreDelete();											

	virtual int				GetMemoryOccupation();									
	virtual CKBOOL			IsObjectUsed(CKObject* obj,CK_CLASSID cid);				

	//--------------------------------------------
	// Dependencies functions	{Secret}											
	virtual CKERROR PrepareDependencies(CKDependenciesContext& context, CKBOOL iCaller = TRUE);
	virtual CKERROR RemapDependencies(CKDependenciesContext& context);				
	virtual CKERROR Copy(CKObject& o,CKDependenciesContext& context);				

	//--------------------------------------------
	// Class Registering {secret}
	static CKSTRING  GetClassName();												
	static int		 GetDependenciesCount(int mode);								
	static CKSTRING  GetDependencies(int i,int mode);								
	static void		 Register();													
	static CKBehavior* CreateInstance(CKContext *Context);							
	static void		 ReleaseInstance(CKContext* iContext,CKBehavior*);							
	static CK_CLASSID m_ClassID;													

	// Dynamic Cast method (returns NULL if the object can't be casted)
	static CKBehavior* Cast(CKObject* iO) 
	{
		return CKIsChildClassOf(iO,CKCID_BEHAVIOR)?(CKBehavior*)iO:NULL;
	}

	void Reset();																						
	void ErrorMessage(CKSTRING Error,CKSTRING Context,CKBOOL ShowOwner=TRUE,CKBOOL ShowScript=TRUE);	
	void ErrorMessage(CKSTRING Error,CKDWORD Context,CKBOOL ShowOwner=TRUE,CKBOOL ShowScript=TRUE);		
	void SetPrototypeGuid(CKGUID ckguid);																
	

protected :
	CK_ID					m_Owner; 
	CK_ID					m_BehParent; 
	XSObjectPointerArray	m_InputArray;		
	XSObjectPointerArray	m_OutputArray;	
	XSObjectPointerArray	m_InParameter;		
	XSObjectPointerArray	m_OutParameter;		
	XSObjectPointerArray	m_LocalParameter;	
	CK_CLASSID				m_CompatibleClassID;
	int						m_Priority;
	CKDWORD					m_Flags;
	CKStateChunk *			m_InterfaceChunk;
	BehaviorGraphData*		m_GraphData;
	BehaviorBlockData*		m_BlockData;
	float					m_LastExecutionTime;
	CK_ID					m_InputTargetParam;

	void SetParent(CKBehavior *parent);
	void SortSubs();
	void ResetExecutionTime();
	void ExecuteStepStart();
	int	 ExecuteStep(float delta,CKDebugContext* Context);
	void WarnInfiniteLoop();
	int	InternalGetShortestDelay(CKBehavior* beh,XObjectPointerArray& behparsed);
	void CheckIOsActivation();
	void CheckBehaviorActivity();
	int ExecuteFunction();
	void FindNextBehaviorsToExecute(CKBehavior* beh);
	void HierarchyPostLoad();												

	static int BehaviorPrioritySort(CKObject *o1,CKObject *o2);
	static int BehaviorPrioritySort(const void *elem1, const void *elem2);

	void ApplyPatchLoad();

#endif // Docjet secret macro
};




#endif
