////////////////////////////////////////////////////////////////////////////
//
//  Crytek Engine Source File.
//  Copyright (C), Crytek Studios, 2001-2005.
// -------------------------------------------------------------------------
//  File name:   G4FlowBaseNode.h
//  Version:     v1.00
//  Created:     21/11/2005		Nick Hesketh
//  Compilers:   Visual Studio.NET 2003
//  Description: Base class and support routines for GameDLL flow nodes.
// -------------------------------------------------------------------------
//
//  CG4AutoRegFlowNode
//		Helper class for auto adding flow node classes to a registration list.
//		This list is registered with the flow system via G4GameStartup.cpp
//		(m_pMod->CompleteInit) and G4Game::CompleteInit
//		Adapted from CAutoRegFlowNode in Flowsystem.h in the CryAction DLL
//		(This way the static list of classes is resident in this dll.)
//
//	CFlowBaseNode
//		A concrete base class for flow nodes. Also provides utility funcs.
//		A direct copy of CFlowBaseNode from the CryAction DLL
//		Needs moving into CryCommon in some fashion.
//
// -------------------------------------------------------------------------
//  History: A slightly modified version of Timur's FlowBaseNode.h
//
////////////////////////////////////////////////////////////////////////////

#ifndef __G4FlowBaseNode_h__
#define __G4FlowBaseNode_h__
#pragma once

#include <IFlowSystem.h>
//#include "..\FlowSystem.h"
//#include "..\FlowSerialize.h"

//////////////////////////////////////////////////////////////////////////
// Auto registration for flow nodes.
//////////////////////////////////////////////////////////////////////////
class CG4AutoRegFlowNodeBase : public IFlowNodeFactory
{
public:
	CG4AutoRegFlowNodeBase( const char *sClassName )
	{
		m_sClassName = sClassName;
		m_pNext = 0;
		if (!m_pLast)
		{
			m_pFirst = this;
		}
		else
			m_pLast->m_pNext = this;
		m_pLast = this;
	}
	void AddRef() {}
	void Release() {}

	//////////////////////////////////////////////////////////////////////////
	const char *m_sClassName;
	CG4AutoRegFlowNodeBase* m_pNext;
	static CG4AutoRegFlowNodeBase *m_pFirst;
	static CG4AutoRegFlowNodeBase *m_pLast;
	//////////////////////////////////////////////////////////////////////////
};

//////////////////////////////////////////////////////////////////////////
template <class T>
class CG4AutoRegFlowNode : public CG4AutoRegFlowNodeBase
{
public:
	CG4AutoRegFlowNode( const char *sClassName ) : CG4AutoRegFlowNodeBase( sClassName ) {}
	IFlowNodePtr Create( IFlowNode::SActivationInfo * pActInfo ) { return new T(pActInfo); }
};

//////////////////////////////////////////////////////////////////////////
// Use this define to register a new flow node class.
// Ex. REGISTER_FLOW_NODE( "Delay",CFlowDelayNode )
//////////////////////////////////////////////////////////////////////////
#define REGISTER_FLOW_NODE( FlowNodeClassName,FlowNodeClass ) \
	CG4AutoRegFlowNode<FlowNodeClass> g_AutoReg##FlowNodeClass ( FlowNodeClassName );



class CFlowBaseNode : public IFlowNode
{
public:
	CFlowBaseNode() { m_refs = 0; };
	virtual ~CFlowBaseNode() {}

	//////////////////////////////////////////////////////////////////////////
	// IFlowNode
	virtual void AddRef() { ++m_refs; };
	virtual void Release() { if (0 >= --m_refs)	delete this; };

	virtual IFlowNodePtr Clone( SActivationInfo *pActInfo ) { return this; }
	virtual bool SerializeXML( SActivationInfo *, const XmlNodeRef&, bool ) { return true; }
	virtual void Serialize(SActivationInfo *, TSerialize ser) {}
	virtual void ProcessEvent( EFlowEvent event, SActivationInfo *pActInfo ) {};
	//////////////////////////////////////////////////////////////////////////

	//////////////////////////////////////////////////////////////////////////
	// Common functions to use in derived classes.
	//////////////////////////////////////////////////////////////////////////
	bool IsPortActive( SActivationInfo *pActInfo,int nPort ) const
	{
		return pActInfo->pInputPorts[nPort].IsUserFlagSet();
	}
	bool IsBoolPortActive( SActivationInfo *pActInfo,int nPort ) const
	{
		if (IsPortActive(pActInfo,nPort) && GetPortBool(pActInfo,nPort))
			return true;
		else
			return false;
	}
	EFlowDataTypes GetPortType( SActivationInfo *pActInfo,int nPort ) const
	{
		return (EFlowDataTypes)pActInfo->pInputPorts[nPort].GetType();
	}

	const TFlowInputData& GetPortAny( SActivationInfo *pActInfo,int nPort ) const
	{
		return pActInfo->pInputPorts[nPort];
	}

	bool GetPortBool( SActivationInfo *pActInfo,int nPort ) const
	{
		bool* p_x = (pActInfo->pInputPorts[nPort].GetPtr<bool>());
		if (p_x != 0) return *p_x;
		SFlowNodeConfig config;
		const_cast<CFlowBaseNode*> (this)->GetConfiguration(config);
		GameWarning("CFlowBaseNode::GetPortBool: Node=%p Port=%d '%s' Tag=%d -> Not a bool tag!", this, nPort,
			config.pInputPorts[nPort].name,
			pActInfo->pInputPorts[nPort].GetTag());
		return false;
	}
	int GetPortInt( SActivationInfo *pActInfo,int nPort ) const
	{
		int x = *(pActInfo->pInputPorts[nPort].GetPtr<int>());
		return x;
	}
	EntityId GetPortEntityId( SActivationInfo *pActInfo,int nPort )
	{
		EntityId x = *(pActInfo->pInputPorts[nPort].GetPtr<EntityId>());
		return x;
	}
	float GetPortFloat( SActivationInfo *pActInfo,int nPort ) const
	{
		float x = *(pActInfo->pInputPorts[nPort].GetPtr<float>());
		return x;
	}
	Vec3 GetPortVec3( SActivationInfo *pActInfo,int nPort ) const
	{
		Vec3 x = *(pActInfo->pInputPorts[nPort].GetPtr<Vec3>());
		return x;
	}
	EntityId GetPortEntityId( SActivationInfo *pActInfo,int nPort ) const
	{
		EntityId x = *(pActInfo->pInputPorts[nPort].GetPtr<EntityId>());
		return x;
	}
	const string& GetPortString( SActivationInfo *pActInfo,int nPort ) const
	{
		const string* p_x = (pActInfo->pInputPorts[nPort].GetPtr<string>());
		if (p_x != 0) return *p_x;
		const static string empty ("");
		SFlowNodeConfig config;
		const_cast<CFlowBaseNode*> (this)->GetConfiguration(config);
		GameWarning("CFlowBaseNode::GetPortString: Node=%p Port=%d '%s' Tag=%d -> Not a string tag!", this, nPort,
			config.pInputPorts[nPort].name,
			pActInfo->pInputPorts[nPort].GetTag());
		return empty;
	}

	//////////////////////////////////////////////////////////////////////////
	EFlowDataTypes GetPortType( SActivationInfo *pActInfo,int nPort )
	{
		return (EFlowDataTypes)pActInfo->pInputPorts[nPort].GetType();
	}

	//////////////////////////////////////////////////////////////////////////
	// Sends data to output port.
	//////////////////////////////////////////////////////////////////////////
	template <class T>
	void ActivateOutput( SActivationInfo *pActInfo,int nPort, const T &value )
	{
		SFlowAddress addr( pActInfo->myID, nPort, true );
		pActInfo->pGraph->ActivatePort( addr, value );
	}
	//////////////////////////////////////////////////////////////////////////
	bool IsOutputConnected( SActivationInfo *pActInfo,int nPort ) const
	{
		SFlowAddress addr( pActInfo->myID, nPort, true );
		return pActInfo->pGraph->IsOutputConnected( addr );
	}
	//////////////////////////////////////////////////////////////////////////

private:
	int m_refs;
};

#endif // __G4FlowBaseNode_h__
