#ifndef __FBPROPERTIES_H__
#define __FBPROPERTIES_H__
/**************************************************************************
 Copyright (c) 1994 - 2006 Autodesk, Inc. and/or its licensors.
 All Rights Reserved.
 
 The coded instructions, statements, computer programs, and/or related 
 material (collectively the "Data") in these files contain unpublished 
 information proprietary to Autodesk, Inc. and/or its licensors, which is 
 protected by Canada and United States of America federal copyright law 
 and by international treaties.
 
 The Data may not be disclosed or distributed to third parties, in whole 
 or in part, without the prior written consent of Autodesk, Inc. 
 ("Autodesk").
 
 THE DATA IS PROVIDED "AS IS" AND WITHOUT WARRANTY.
 ALL WARRANTIES ARE EXPRESSLY EXCLUDED AND DISCLAIMED. AUTODESK MAKES NO 
 WARRANTY OF ANY KIND WITH RESPECT TO THE DATA, EXPRESS, IMPLIED OR 
 ARISING BY CUSTOM OR TRADE USAGE, AND DISCLAIMS ANY IMPLIED WARRANTIES 
 OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR 
 PURPOSE OR USE. WITHOUT LIMITING THE FOREGOING, AUTODESK DOES NOT 
 WARRANT THAT THE OPERATION OF THE DATA WILL BE UNINTERRUPTED OR ERROR 
 FREE.
 
 IN NO EVENT SHALL AUTODESK, ITS AFFILIATES, PARENT COMPANIES, LICENSORS 
 OR SUPPLIERS ("AUTODESK GROUP") BE LIABLE FOR ANY LOSSES, DAMAGES OR 
 EXPENSES OF ANY KIND (INCLUDING WITHOUT LIMITATION PUNITIVE OR MULTIPLE 
 DAMAGES OR OTHER SPECIAL, DIRECT, INDIRECT, EXEMPLARY, INCIDENTAL, LOSS 
 OF PROFITS, REVENUE OR DATA, COST OF COVER OR CONSEQUENTIAL LOSSES OR 
 DAMAGES OF ANY KIND), HOWEVER CAUSED, AND REGARDLESS OF THE THEORY OF 
 LIABILITY, WHETHER DERIVED FROM CONTRACT, TORT (INCLUDING, BUT NOT 
 LIMITED TO, NEGLIGENCE), OR OTHERWISE, ARISING OUT OF OR RELATING TO THE 
 DATA OR ITS USE OR ANY OTHER PERFORMANCE, WHETHER OR NOT AUTODESK HAS 
 BEEN ADVISED OF THE POSSIBILITY OF SUCH LOSS OR DAMAGE.
 
**************************************************************************/

/**	\file fbproperties.h
*	Property classes.
*	Properties are callback variables that insert a layer of abstraction between
*	the internal objects and the software development kit.
*/

#include <kaydaradef.h>

#ifndef FBSDK_DLL
  #define FBSDK_DLL K_DLLIMPORT
#endif

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>

#include <fbsdk/fbplug.h>
#include <fbsdk/fbarray.h>
#include <fbsdk/fbstring.h>
#include <fbsdk/fbtime.h>

K_FORWARD( KEventBase );
K_FORWARD( KProperty );
K_FORWARD( KDataType );
K_FORWARD( IFBObject );
K_FORWARD( IRegister );
K_FORWARD( KStringList );

#ifdef FBSDKUseNamespace
	namespace FBSDKNamespace {
#endif

//! Property types
enum FBPropertyType
{
	kFBPT_unknown,kFBPT_int,kFBPT_bool,kFBPT_float,kFBPT_double,kFBPT_charptr,kFBPT_enum,kFBPT_Time,kFBPT_String,
	kFBPT_object,kFBPT_event,kFBPT_stringlist,
	kFBPT_Vector4D,kFBPT_Vector3D, 
	kFBPT_ColorRGB, kFBPT_ColorRGBA,
	kFBPT_Action,kFBPT_Reference,
	kFBPT_TimeSpan,
	kFBPT_kReference,
	kFBPT_Vector2D,
	kFBPT_last
};

/** Available flags for FBProperty objects.
*   @note   Property flags are not saved into FBX files.
*/
enum FBPropertyFlag
{
	kFBPropertyFlagNotSet = 0,
	kFBPropertyFlagHideProperty = (1 << 0),
	kFBPropertyFlagForceStaticProperty = (1 << 1),
   	kFBPropertyFlagDisableProperty = (1 << 2),
   	kFBPropertyFlagAnimated = (1 << 3),
	kFBPropertyFlagNotSavable = (1 << 4),
	kFBPropertyFlagReadOnly = (1 << 5),
	kFBPropertyFlagNotUserDeletable = (1 << 6)
};

/**	Define a component and give it the ability to be a property.
*	\param	DllTag		Associated DLL.
*	\param	Type		Component to register as a property.
*/
#define FB_DEFINE_COMPONENT( DllTag, Type )                                             \
    class FB##Type; typedef  FB##Type *HFB##Type;                                       \
    typedef class DllTag FBPropertyBase< HFB##Type,kFBPT_object > FBPropertyBase##Type; \
    typedef class DllTag FBPropertyBaseComponent< HFB##Type > FBProperty##Type

/**	Define an enum and give it the ability to be a property.
*	\param	DllTag		Associated DLL.
*	\param	Type		Enum to register as a property.
*/
#define FB_DEFINE_ENUM( DllTag, Type ) \
	typedef class DllTag FBPropertyBaseEnum< enum FB##Type > FBProperty##Type;

/** Define a component list.
*	\param	DllTag		Associated DLL.
*	\param	Type		Component to use as a list item.
*/
#define FB_DEFINE_LIST( DllTag, Type )	\
	typedef class DllTag FBPropertyBaseList< HFB##Type > FBPropertyBaseList##Type;

FB_FORWARD( FBComponent );
__FB_FORWARD( FBProperty );

/** <b>Property:</b> Base property class.
*	In the Open Reality SDK, a property is a holder for function callbacks into the internals
*	of the application.
*/

class FBSDK_DLL FBProperty : public FBPlug
{
    FBClassDeclare( FBProperty, FBPlug );

protected:
	FBString		mName;				// \internal Property unique name.
	KProperty*		mInternal;			// \internal Property data.
	FBPropertyType	mPropertyType;		// \internal Property type.

public:
	bool		mAllocated;			// \internal Allocated.

	//! Constructor.
	FBProperty();

    // ICallback interface.
	IObject_Declare(Implementation);		// Interface to IObject.

    // \internal Return an internal pointer.
    virtual HIObject GetHIObject();

    // \internal Assign component to an internal pointer.
    virtual bool SetHIObject( HIObject pObject, bool pSDKComponent );


	//! \internal Initialize internal pointer.
	FBProperty* InitInternal( void* pOwner, char* pPropName );

	//! \internal Get property.
	KProperty* GetInternal();

	//! \internal Set property
	void SetInternal( KProperty* pInternal );

	/**	Get the property's name.
	*	\return	The property's name.
	*/
	char* GetName();

	/**	Set the property's name.
	*	\param	pName	New name for the property.
	*/
	void SetName(char *pName);

	/**	Get the property's type.
	*	\return	The property's type.
	*/
	FBPropertyType GetPropertyType( );

	/**	Get the property's type name.
	*	\return	The property's type name.
	*/
	char* GetPropertyTypeName();
	
	//@{
	/**	Set the value of the property, passing the type as an argument.
	*	\param	pData	Value to affect property with.
	*/
	virtual void SetData( void*	pData );
	//@}

	//@{
	/**	Get the value of a property.
	*	\retval	pValue	Value to fill with property's current value.
	*/
	virtual void GetData( void*	pData, int pSize ) const;
	//@}

	/**	Get the property as an integer.
	*	\return The integer version of the property.
	*/	
	int			AsInt();

	/**	Set the property from an integer.
	*	\param	pInt Int to set property from.
	*	\return True if it was possible.
	*/	
	bool		SetInt(int pInt);
	
	/**	Get the property as a string.
	*	\return The string version of the property.
	*/	
	virtual char* AsString();

	/**	Set the property from a string.
	*	\param	pString String to set property from.
	*	\return True if it was possible.
	*/
	virtual bool SetString( char* pString );

	//@{
	/**	Verify if property is of this type.
	*	\return	\b true if property is of type.
	*/
	virtual bool IsList();
    bool IsAnimatable();
	bool IsInternal() const;
	bool IsUserProperty();
	bool IsReferenceProperty();
	//@}


    /** Indicate if is an instance of FBPropertyListObject.
    *   \warning A FBPropertyListObject will also return true on a call to 'IsList()'.
    */
    bool IsObjectList();

	/**	Is property read-only?
	*	\return	\b true if property is read-only.
	*/
	virtual bool IsReadOnly();

	/**	Return the string of an enum value.
	*	\param	pIndex	Enum value to get string for.
	*	\return	String value of enum specified by \e pIndex.
	*/
	virtual char *EnumList( int pIndex );

	/** SetPropertyFlags.
    *   Property specific flags are usually controlled within the constructor method
    *   of the owner objects. They can also be modified via tools and scripting.
    *   Property flags will not be saved or restored.
	*	\param	pFlags	The value of all flags that you want to set.
	*	\remark			Note that other unspecified flags will be overwritten to False.
	*/
	void			SetPropertyFlags(FBPropertyFlag pFlags);

	/** ModifyPropertyFlag.
	*	\param	pFlag	The flag to switch to True or False.
	*	\param	pValue	The value to set about this flag.
    *   @warning    Flags are not saved into or read from a FBX file.
	*/
	void			ModifyPropertyFlag(FBPropertyFlag pFlag, bool pValue);

	/** GetPropertyFlags.
	*	\return	Return all flags at once.
	*/
	FBPropertyFlag	GetPropertyFlags();

	/** GetPropertyFlag
	*	\param	pFlag	Flag to test if it is True or False.
	*	\return			If the flag is True, the function returns True and vice-versa.
    *   @warning    Flags are not saved into or read from a FBX file.
	*/
	bool			GetPropertyFlag(FBPropertyFlag pFlag);

	/** SetMinMax
	*	\param	pMin	Minimum value of the property.
	*	\param	pMax	Maximum value of the property.
	*/
	void	SetMinMax( double pMin, double pMax );

	/** SetMin
	*	\param	pMin	Minimum value of the property.
	*/
	void	SetMin( double pMin );

	/** SetMax
	*	\param	pMax	Maximum value of the property.
	*/
	void	SetMax( double pMax );
	
	/** GetMin
	*	\return			Minimum value for the property.
	*/
	double	GetMin();

	/** GetMax
	*	\return			Maximum value for the property.
	*/
	double	GetMax();

};

/**	Get the temporary string buffer for properties
*	\return	Buffer used by properties to write temporary strings.
*/
FBSDK_DLL char *GetPropertyToStringBuffer();

__FB_FORWARD( FBPropertyAnimatable );
FB_FORWARD( FBBox );
FB_FORWARD( FBEvaluateInfo );
FB_FORWARD( FBAnimationNode );

///////////////////////////////////////////////////////////////////////////////
// PropertyEvent
///////////////////////////////////////////////////////////////////////////////
__FB_FORWARD(FBPropertyEvent);

//! \b PropertyEvent: Base event class.
class FBSDK_DLL FBPropertyEvent : public FBProperty
{
  protected:
	HIRegister	mParentRegister;	// \internal Internal callback register.
	int			mType;				// \internal Type of event.
	int			mSubType;			// \internal SubType of event.
  public:
	//! Constructor
    FBPropertyEvent();

	/**	Property initialization function.
	*	\param	pParent		Internal parent register.
	*	\param	pName		Name of FBPropertyEvent
	*	\param	pType		Type of event.
	*	\param	pSubType	SubType of event(default=K_INT_MAX).
	*	\return	Pointer to this FBPropertyEvent
	*/
	FBPropertyEvent *Init( HIRegister pParent,char *pName, int pType, int pSubType=K_INT_MAX );	

	/**	Property initialization function, for global events.
	*	\param	pName				Name of FBPropertyEvent
	*	\param	pGlobalEventName	Name of global event.
	*	\return	Pointer to this FBPropertyEvent
	*/
	FBPropertyEvent *InitGlobal( char* pName, char* pGlobalEventName );	

	//! Destructor.
    virtual ~FBPropertyEvent();

	//@{
	/**	Add/Remove a callback.
	*	\param	pOwner		Callback owner.
	*	\param	pHandler	Callback handler.
	*/
    virtual void Add		( HICallback pOwner, kICallbackHandler pHandler );
  	virtual void Remove		( HICallback pOwner, kICallbackHandler pHandler );
	//@}

	//! Invalidate parent, removing internal register parent.
	virtual void InvalidateParent();

  private:

	HDataFBPropertyEvent mLocalPtr;	//!< Internal data.
};

//! \b PropertyEvent: UI idle event.
class FBSDK_DLL FBPropertyEventUIIdle : public FBPropertyEvent
{
  public:
    virtual void Add	( HICallback pOwner, kICallbackHandler pHandler );
  	virtual void Remove	( HICallback pOwner, kICallbackHandler pHandler );
};

//! \b PropertyEvent: Global ConnectionNotify event.
class FBSDK_DLL FBPropertyEventConnectionNotify : public FBPropertyEvent
{
  public:
    virtual void Add	( HICallback pOwner, kICallbackHandler pHandler );
  	virtual void Remove	( HICallback pOwner, kICallbackHandler pHandler );
};

//! \b PropertyEvent: Global ConnectionDataNotify event.
class FBSDK_DLL FBPropertyEventConnectionDataNotify : public FBPropertyEvent
{
  public:
    virtual void Add	( HICallback pOwner, kICallbackHandler pHandler );
  	virtual void Remove	( HICallback pOwner, kICallbackHandler pHandler );
};

//! \b PropertyEvent: Global ConnectionStateNotify event.
class FBSDK_DLL FBPropertyEventConnectionStateNotify : public FBPropertyEvent
{
  public:
    virtual void Add	( HICallback pOwner, kICallbackHandler pHandler );
  	virtual void Remove	( HICallback pOwner, kICallbackHandler pHandler );
};

/** \internal
*	Base template class for all standard properties
*/
template <class tType, FBPropertyType pPT> class FBPropertyBase : public FBProperty 
{ 
  protected: 
	void  (* Set)(void *, tType);	// \internal Set function pointer.
	tType (* Get)(void *);			// \internal Get function pointer.
	void *mParent;					// \internal Pointer to parent.

  public: 
	//! Constructors.
	inline FBPropertyBase()											{  Set = NULL; Get = NULL; mPropertyType = pPT; }  
	inline FBPropertyBase(const FBPropertyBase<tType,pPT> &pValue)	{ operator=((tType)pValue ); }

	/**	Initialization function.
	*	\param	pParent		Parent object.
	*	\param	pName		Name of base enum.
	*	\param	pGet		Get function (default=NULL).
	*	\param	pSet		Set function (default=NULL).
	*	\return	Pointer to this object.
	*/
	inline FBPropertyBase *Init( void *pParent,char *pName,tType (* pGet)(void *)=NULL,void (* pSet)(void *,tType)=NULL  )
	{  
		mParent = pParent;	
		mName	= pName ;	
		Get		= pGet; 	
		Set		= pSet; 	
		return this;
	} 

	//@{
	/**	Overloaded = operator.
	*	Set the value of the current object using \e Set function.
	*	\param	pValue	Value to set for object.
	*/
	inline void operator=(tType pValue)					{ SetData( &pValue ); }
	//@}

	/**	Overloaded cast to \b tType operator.
	*	Get the value of the current object using \e Get fuction.
	*	\return	\b tType cast of current object.
	*/
    inline operator tType() const						{ tType Value; GetData( &Value,sizeof(Value) ); return Value; } 

	/**	Get the parent of the object.
	*	\return Parent object.
	*/
    inline void * GetParent()							{ return mParent; } 

	/**	Is this class read-only?
	*	If there is an existing set function, this class is read/write, otherwise it is read-only.
	*	\return \b true if it is read-only.
	*/
    inline virtual bool IsReadOnly()					{ return IsInternal() ? (FBProperty::IsReadOnly()) : (Set == NULL); }

	/**	Get value.
	*	\retval	pValue Value to fill with current object value.
	*/
	virtual void GetData(void* pData, int pSize) const
	{
		if (IsInternal())
		{
			FBProperty::GetData( pData, pSize );
		} else
		{
			if(Get) 
			{ 
				*((tType*)pData) = (*Get)(mParent); 
			} else 
			{ 
				assert( Get != NULL); 
				*((tType*)pData) = (tType)0; 
			}
		}
	}
	/**	Set value.
	*	\param	pData	Integer to use to set.
	*/
    virtual void SetData(void* pData)
	{ 
		if (IsInternal())
		{
			FBProperty::SetData( pData );
		} else
		{
			if(Set) 
			{ 
				(*Set)( mParent,*(tType*)pData ); 
			} else 
			{ 
				assert( Set != NULL); 
			} 
		}
	} 
};

/**	\internal
*	Base template class for enum properties.
*/
template <class tType> class FBPropertyBaseEnum : public FBProperty
{
	static const char *mStrings[];		// \internal String list.

  protected: 
	void  (* Set)(void *, tType);	// \internal Set function pointer.
	tType (* Get)(void *);			// \internal Get function pointer.
	void *mParent;					// \internal Pointer to parent.

  public: 
	//! Constructor.
	inline FBPropertyBaseEnum()											{  Set = NULL; Get = NULL; mPropertyType = kFBPT_enum; }  
	inline FBPropertyBaseEnum(const FBPropertyBaseEnum<tType> &pValue)	{ operator=((tType)pValue ); }

	/**	Initialization function.
	*	\param	pParent		Parent object.
	*	\param	pName		Name of base enum.
	*	\param	pGet		Get function (default=NULL).
	*	\param	pSet		Set function (default=NULL).
	*	\return	Pointer to this object.
	*/
	inline FBPropertyBaseEnum *Init( void *pParent,char *pName,tType (* pGet)(void *)=NULL,void (* pSet)(void *,tType)=NULL  )
	{  
		mParent = pParent;	
		mName	= pName ;	
		Get		= pGet; 	
		Set		= pSet; 	
		return this;
	} 

	//@{
	/**	Overloaded = operator.
	*	Set the value of the current object using \e Set function.
	*	\param	pValue	Value to set for object.
	*/
	inline void operator=(tType pValue)					{ SetData( &pValue ); }
	//@}

	/**	Overloaded cast to \b tType operator.
	*	Get the value of the current object using \e Get fuction.
	*	\return	\b tType cast of current object.
	*/
    inline operator tType() const						{ tType Value; GetData( &Value,sizeof(Value) ); return Value; } 

	/**	Get the parent of the object.
	*	\return Parent object.
	*/
    inline void * GetParent()							{ return mParent; } 

	/**	Is this class read-only?
	*	If there is an existing set function, this class is read/write, otherwise it is read-only.
	*	\return \b true if it is read-only.
	*/
    inline virtual bool IsReadOnly()					{ return IsInternal() ? (FBProperty::IsReadOnly()) : (Set == NULL); }

	/**	Get value.
	*	\retval	pValue Value to fill with current object value.
	*/
	virtual void GetData(void* pData, int pSize) const
	{
		if (IsInternal())
		{
			FBProperty::GetData( pData, pSize );
		} else
		{
			if(Get) 
			{ 
				*((tType*)pData) = (*Get)(mParent); 
			} else 
			{ 
				assert( Get != NULL); 
				*((tType*)pData) = (tType)0; 
			}
		}
	}
	/**	Set value.
	*	\param	pData	Integer to use to set.
	*/
    virtual void SetData(void* pData)
	{ 
		if (IsInternal())
		{
			FBProperty::SetData( pData );
		} else
		{
			if(Set) 
			{ 
				(*Set)( mParent,*(tType*)pData ); 
			} else 
			{ 
				assert( Set != NULL); 
			}
		}
	} 

    inline virtual char *EnumList( int pIndex )		
	{ 	
		if( IsInternal() )
		{
			return FBProperty::EnumList( pIndex );
		} else
		{
			return (char *)mStrings[pIndex]; 
		}

	}
};


/**	\internal
*	Base template class for list properties.
*/
class FBSDK_DLL FBPropertyBasicList : public FBProperty
{
protected: 
	void *mParent;			//!< Parent object.
public:
	//! Constructor.
	FBPropertyBasicList();
	/**	Constructor.
	*	\param pParent	Parent for property list.
	*	\param pName	Name of property list.
	*/
	FBPropertyBasicList( void *pParent, char *pName );
	/**	Initialization function.
	*	\param pParent	Parent of property list.
	*	\param pName	Name of property list.
	*/
	FBProperty* Init( void *pParent, char *pName );

	//!	Remove all properties from the list.
	void RemoveAll();

	/**	Get the number of properties in the list.
	*	\return The number of properties in the list.
    *   \warning <b>overload required</b>.
	*/
	virtual int GetCount()=0;

	/**	Remove property at \e pIndex.
	*	\param pIndex Index where property is to be removed.
    *   \warning <b>overload required</b>.
	*/
	virtual void RemoveAt( int pIndex )=0;

	/**	Is this a list?
	*	\return \b true if this is a list.
	*/
	virtual bool IsList();
};

/**	\internal
*	Base template class for list properties.
*/
template <class tType> class FBPropertyBaseList : public FBPropertyBasicList
{
public:
	//! Constructor.
	FBPropertyBaseList( ):FBPropertyBasicList( ) {}
	/**	Constructor.
	*	\param pParent	Parent for property list.
	*	\param pName	Name of property list.
	*/
	FBPropertyBaseList( void *pParent, char *pName ):FBPropertyBasicList( pParent, pName ) {}

public:  
	//***
	//--- These functions require overloads in derived classes. 
	//***
	
	/**	Add a property to the list.
	*	\param pItem Property to add.
	*	\return Index where property was inserted.
    *   \warning <b>overload required</b>.
	*/
	virtual int Add( tType pItem )=0;

	/**	[] operator overload.
	*	\param pIndex Index of property to access.
	*	\return Property at \e pIndex.
    *   \warning <b>overload required</b>.
	*/
	virtual tType operator[]( int pIndex )=0;

public: 
	//***
	//--- These functions can be optionally overloaded in derived classes.
	//***

	/**	Locate a property in the list.
	*	\param pItem Property to find in the list.
	*	\return Index where \e pItem can be found.
	*/
	inline virtual int Find( tType pItem )		
	{ 
		int Index;
		for(Index=0; Index<GetCount(); Index++ ) 
		{
			if( operator[](Index)==pItem ) 
			{
				return Index; 
			}
		}
		return -1;
	}

	/**	Remove \e pItem from the list.
	*	\param pItem Property to remove from the list.
	*	\return Index where property was removed.
	*/
	inline virtual int Remove( tType pItem )		
	{
		int Index = Find( pItem ); 
		if (Index!=-1)
		{
			RemoveAt( Index );
		}
		return Index;
	}

	/**	Get a property at \e pIndex.
	*	\param pIndex Index to access.
	*	\return Property at \e pIndex.
	*/
	inline virtual tType GetAt(int pIndex)	
	{
		return operator[](pIndex); 
	}
};

//! \internal Patch to use the base enum for casting values .
enum kDefaultEnum { kDefaultItemNone };
typedef class FBSDK_DLL FBPropertyBaseEnum< enum kDefaultEnum > FBPropertyEnum;

FB_FORWARD( FBPropertyStringList );

//! <b>Property:</b> StringList
class FBSDK_DLL FBPropertyStringList : public FBProperty
{
  protected:
	HKStringList mItems;			// \internal Items in string list.
  public:
	//! Constructor.
	FBPropertyStringList();

	//! Destructor.
	virtual ~FBPropertyStringList();

	/**	Constructor.
	*	\param	pItems	String list to initialize the property string list with.
	*	\param	pName	Name for string list.
	*/
	FBPropertyStringList( HKStringList pItems, char *pName );
	/**	String list initilialization.
	*	\param	pItems	String list to initialize the property string list with.
	*	\param	pName	Name for string list.
	*	\return	Pointer to this object.
	*/
	FBPropertyStringList *Init( HKStringList pItems, char *pName );

  public:
	/**	Get the reference at \e pIndex.
	*	\param	pIndex	Index to get reference at.
	*	\return	Reference stored at \e pIndex.
	*/
    kReference  GetReferenceAt( int pIndex );
	/**	Set reference at \e pIndex.
	*	\param	pIndex	Index to set reference at.
	*	\param	pRef	Reference to store.
	*/
    void SetReferenceAt( int pIndex,kReference pRef );
	
	/**	Find the index of a reference.
	*	\param	pRef	Reference to find in list.
	*	\return	Index where reference is stored.
	*/
	int	Find( kReference pRef );

	/**	Find the index of a string.
	*	\param	S	String to find in list.
	*	\return	Index of string \e S.
	*/
	int	Find( char *S );

	/**	Get the string stored at \e pIndex.
	*	\param	pIndex	Index to access
	*	\return	String stored at \e pIndex.
	*/
	virtual char *GetAt( int pIndex );

	/** [] operator overload.
	*	Return the string stored at \e pIndex.
	*	\param	pIndex	Index to access.
	*	\return String stored at \e pIndex.
	*/
    char *operator[](int pIndex);

	//! Sort list ascending.
	void Sort( );

	/**	Get the number of items in the list.
	*	\return Number of strings stored in the list.
	*/
	int GetCount();

	/**	Remove a string from the list.
	*	\param	S	String to remove from the list.
	*	\return	Index where item was found.
	*/
	int	Remove( char *S );

  public:  // Needs to be overriden for special behaviors
	/**	Add a string to the list.
	*	\param	S		String to add to list.
	*	\param	pRef	Reference to stored with string (default = 0)
	*	\return	Index where item was stored.
	*/
	virtual int	Add( char *S,kReference pRef = 0 );

	//! Clear the list (remove all the items).
    virtual void Clear();

	/**	Remove an entry at \e pIndex.
	*	\param	pIndex	Index where item is to be removed from.
	*/
    virtual void RemoveAt( int pIndex );
	
	/**	Get the index of a string.
	*	\param	S	String to look for.
	*	\return	Index where string \e S was found.
	*/
    virtual int	IndexOf(char *S);
	
	/**	Insert an entry at \e pIndex.
	*	\param	pIndex	Index where item is to be inserted.
	*	\param	S		String to insert.
	*	\param	pRef	Reference to store with string.
	*/
    virtual void InsertAt( int pIndex, char *S,kReference pRef = 0 );

	/**	Set the string at \e pIndex.
	*	\param	pIndex		Index where string is to be set.
	*	\param	pString		String to set value at \e pIndex with.
	*	\return \b true if success.
	*/
	virtual bool SetAt( int pIndex,char *pString );

	/**	Is this class a list?
	*	\return \b true (this class is a list).
	*/
	virtual bool IsList();

	/**	Get as string.
	*	\return String list.
	*/
	virtual char *AsString();

	/**	Set string for list
	*	\param	pString String to set for list.
	*/
	virtual bool SetString( char *pString );
};

////////////////////////////////////////////////////////////////////////////////////
// FBPropertyManager
////////////////////////////////////////////////////////////////////////////////////
__FB_FORWARD( FBPropertyManager );

/** Property Manager.
*	The property manager exists in all FBComponent objects, and
*	contains an array of all the registered properties. These properties
*	may be SDK properties, internal properties or both.
*/
class FBSDK_DLL FBPropertyManager 
{
public:
	//! Constructor.
	FBPropertyManager();

	//! Destructor.
	~FBPropertyManager();

	/**	Add a property to the property manager.
	*	\param	Property	Handle to property to add.
	*	\return	Index in list where \e Property was added.
	*/
	int Add( HFBProperty Property );

	/**	Overloaded [] operator.
	*	Access the property at \e pIndex.
	*	\param	pIndex	Index of property to access.
	*	\return	Property stored at \e pIndex.
	*/
	HFBProperty operator[](int pIndex);

	/**	Get the number of properties stored in property manager.
	*	\return	Number of properties in manager.
	*/
	int	GetCount();

	/**	Find a property, based on its name.
    *   
	*	\param	pPropertyName       Name of property to look for.
	*	\param	pInternalSearch     Indicate if the search will only be done for properties explicitely defined in the C++ inteface or also look at internal properties. (default = true)
	*	\param	pMultilangLookup    When searching, indicate if the name lookup should also be done on the property name as shown in the GUI. (default = true)
	*	\return	Handle to property found.
	*/
	HFBProperty Find( const char *pPropertyName, bool pInternalSearch=true, bool pMultilangLookup=true );

	/** Remove a property.
	*	\param pProperty	Property to remove.
	*	\return Index where property was found.
	*/
	int Remove( HFBProperty pProperty );

private:
    /** \internal
	*	Set the parent object.
	*	\param pParent	Parent object pointer.
	*	\param pId		Id in parent array (default = 0)
	*/
	void SetParent( void* pParent, int pId=0 );

    void*							mParent[2];
	FBArrayTemplate< HFBProperty >*	mProperties;			// \internal Array of properties.
    HDataFBPropertyManager          mLocalPtr;

    friend class FBComponent;
    friend class FBVisualComponent;
};

/**	\internal
*	Base template class for component properties.
*/
template <class tType> class FBPropertyBaseComponent : public FBPropertyBase< tType, kFBPT_object > 
{
  public:
	int *TypeInfo;	//!<  \internal Type information.
  public:
	//! Constructor.
    inline FBPropertyBaseComponent() {}
	inline FBPropertyBaseComponent(const FBPropertyBaseComponent<tType> &pValue)	{ FBPropertyBase< tType,kFBPT_object >::operator=((tType)pValue ); }

	//@{
	/**	Overloaded = operator
	*	\param	pValue	Value to set for component.
	*/
	inline void operator=(tType pValue)								{ FBPropertyBase< tType,kFBPT_object >::operator=(pValue); } 
	//@}

	/**	Overloaded -> operator
	*	\return	Dereferenced pointer to this object.
	*/
	inline tType operator -> ()									{ return FBPropertyBase< tType,kFBPT_object >::operator tType(); } 

	/**	Overloaded cast to \b tType operator.
	*	\return	\b tType cast of current object.
	*/
    inline operator tType() const									{ return FBPropertyBase< tType,kFBPT_object >::operator tType(); } 
};

/**	Implement a property based on a component
*	\param	DllTag		Associated DLL.
*	\param	Type	Class to implement.
*/
#if defined(KARCH_DEV_INTEL)
	#define FBImplementPropertyComponent( DllTag, Type ) 
#else
	#define FBImplementPropertyComponent( DllTag, Type ) \
		template class DllTag FBSDKNamespaceFunc(FBPropertyBase)< HFB##Type,kFBPT_object >;	\
		template class DllTag FBSDKNamespaceFunc(FBPropertyBaseComponent)< HFB##Type >;
#endif

/**	Implement a property based on an enumeration
*	\param	DllTag		Associated DLL.
*	\param	Type	Class to implement.
*/
#if defined(KARCH_DEV_MIPSPRO) || defined(KARCH_DEV_INTEL)
	#define FBImplementPropertyEnum( DllTag, Type )	// On SGI by having mString defined for each enum already instantiates the template.
#else
	#define FBImplementPropertyEnum( DllTag, Type ) \
		template class DllTag FBSDKNamespaceFunc(FBPropertyBaseEnum)< enum FB##Type >
#endif

/** Implement a property list for a component
*	\param	DllTag		Associated DLL.
*	\param	Type	Class to implement list for.
*/
#if defined(KARCH_DEV_INTEL)
	#define FBImplementPropertyList( DllTag, Type )
#else
	#define FBImplementPropertyList( DllTag, Type ) \
		template class DllTag FBSDKNamespaceFunc(FBPropertyBaseList) < HFB##Type >
#endif


//!	\b Property class: char * (String).
typedef class FBPropertyBase< char *,kFBPT_charptr > FBPropertyString;

//!	<b>Property:</b> bool
typedef class FBPropertyBase< bool,kFBPT_bool > FBPropertyBool;

//!	<b>Property:</b> Action
typedef class FBPropertyBase< bool,kFBPT_Action > FBPropertyAction;

//!	<b>Property:</b> int
typedef class FBPropertyBase< int,kFBPT_int > FBPropertyInt;

//!	<b>Property:</b> double
typedef class FBPropertyBase< double,kFBPT_double > FBPropertyDouble;

//!	<b>Property:</b> float
typedef class FBPropertyBase< float,kFBPT_float > FBPropertyFloat;

//!	<b>Property:</b> FBTime
typedef class FBPropertyBase< FBTime,kFBPT_Time > FBPropertyTime;

//!	<b>Property:</b> FBTimeSpan
typedef class FBPropertyBase< FBTimeSpan,kFBPT_TimeSpan > FBPropertyTimeSpan;

//!	<b>Property:</b> kReference
typedef class FBPropertyBase< kReference,kFBPT_kReference >	FBPropertykReference;

//!	<b>Property:</b> FBProperty *
typedef class FBPropertyBase< HFBProperty,kFBPT_Reference >			FBPropertyReference;

typedef class FBPropertyBase< HFBComponent,kFBPT_object >			_FBPropertyBaseComponent;
typedef class FBPropertyBaseComponent< HFBComponent > FBPropertyComponent;
typedef FBPropertyComponent *HFBPropertyComponent;

typedef class FBPropertyBase< HFBPlug,kFBPT_object >           _FBPropertyBasePlug;
typedef class FBPropertyBaseComponent< HFBPlug >  FBPropertyPlug;
typedef FBPropertyPlug *HFBPropertyPlug;

/**	Initialize a property: default.
*	\param	Param		Owner name.
*	\param	Type		Type of variable.
*	\param	PropName	Variable name.
*	\param	Get			Get function pointer.
*	\param	Set			Set function pointer.
*/
#define FBPropertyInit( Param,Type,PropName,Get,Set ) \
	{ \
		PropertyAdd(PropName.Init( (void *)Param,#PropName,(Type (*)(void *))Get,(void (*)(void *,Type))Set )); \
	}

/**	Initialize a property: list.
*	\param	Param		Owner name.
*	\param	PropName	Variable name.
*/
#define FBPropertyInitList( Param,PropName ) \
	{ \
		PropertyAdd(PropName.Init( Param,#PropName )); \
	}

/**	Initialize a property: string list.
*	\param	Param		Owner name.
*	\param	StringList	String list to initialize with.
*	\param	PropName	Variable name .
*/
#define FBPropertyInitStringList( Param,StringList,PropName ) \
	{ \
		PropertyAdd(PropName.Init( StringList,#PropName )); \
	}

/**	Initialize a property: event.
*	\param	Param		Owner name.
*	\param	Type		Event Type.
*	\param	SubType		Event SubType.
*	\param  PropName	Variable name.
*/
#define FBPropertyInitEvent( Param,Type,SubType,PropName ) \
	{ \
		PropertyAdd(PropName.Init( IQ(Param,IRegister),#PropName,Type,SubType )); \
	}

/**	Initialize a property: global event.
*	\param	GlobalEventName		Name of the global eventEvent Type.
*	\param  PropName			Variable name.
*/
#define FBPropertyInitEventGlobal( GlobalEventName,PropName ) \
	{ \
		PropertyAdd(PropName.InitGlobal( #PropName,GlobalEventName )); \
	}

/**	Initialize a property: private property.
*	This macro is in the case where a property must be used by a class that does not
*	inherit from FBComponent.
*	\param	Param		Owner name.
*	\param	Type		Type of variable.
*	\param	PropName	Variable name.
*	\param	Get			Get function pointer.
*	\param	Set			Set function pointer.
*/
#define FBPrivatePropertyInit( Param,Type,PropName,Get,Set ) \
	{ \
		PropName.Init( (void *)Param,#PropName,(Type (*)(void *))Get,(void (*)(void *,Type))Set ); \
	}

#define FBPropertyInitAnim( Param, PropName, HookName ) \
	{ \
		PropertyAdd(PropName.Init( Param, HookName )); \
	}

#define FBPropertyInitInternal( Param, PropName, HookName ) \
	{\
		PropertyAdd(PropName.Init( PropName.InitInternal( Param, HookName )->GetInternal(),#PropName));\
	}

/** Initialize a FBPropertyListObject, which maps over a KPropertyObjectList.
*   Use this macro when the internal property name matches the one used
*   in the SDK.
*/
#define FBPropertyInitListObject( Param, PropName ) \
	{\
        PropertyAdd(PropName.InitInternal( Param, #PropName ));\
	}

/** Initialize a FBPropertyListObject, which maps over a KPropertyObjectList.
*   Use this macro when the internal property name matches the one used
*   in the SDK.
*/
#define FBPropertyInitListObjectEx( Param, PropName, InternalPropName ) \
	{\
        PropertyAdd(PropName.InitInternal( Param, InternalPropName ));\
	}
															   
typedef class FBSDK_DLL FBPropertyBase< FBColor,kFBPT_ColorRGBA >	FBPropertyColor;
typedef class FBSDK_DLL FBPropertyBase< FBVector2d,kFBPT_Vector2D >	FBPropertyVector2d;
typedef class FBSDK_DLL FBPropertyBase< FBVector3d,kFBPT_Vector3D >	FBPropertyVector3d;
typedef class FBSDK_DLL FBPropertyBase< FBVector4d,kFBPT_Vector4D >	FBPropertyVector4d;


//!	Animatable property base class.
class FBSDK_DLL FBPropertyAnimatable : public FBProperty
{
  private:
	bool	mState;

  public:
	/**	Constructor
	*/
	FBPropertyAnimatable();

	/** Destructor.
	*/
	virtual ~FBPropertyAnimatable();

  public:
	/**	Initialization function (internal).
	*	\param	pOwner	Owner box object.
	*	\param	pName	Name of property searched for.
	*	\return	this, once initialized.
	*/
	FBPropertyAnimatable* Init( void* pOwner, char* pName );

	/**	Initialization function (custom).
	*	\param	pOwner	Owner box object.
	*	\param	pName	Name of property to add.
	*	\param	pType	Type name (string) of property.
	*	\param	pInit	Initialization value.
	*	\return	this, once initialized.
	*/
	FBPropertyAnimatable* Init( HFBBox pOwner, char* pName, char* pType, double* pInit );

	/**	Destruction function, for internal connectors.
	*	Used in the case of custom properties in order to remove the connectors.
	*/
	void Destroy();

	/**	Get the property datatype pointer.
	*	\return Datatype of property as a character string.
	*/
	KDataType* GetDataType();

	/**	Get the property datatype name.
	*	\return Datatype of property as a character string.
	*/
	char* GetDataTypeName();

	/**	Is the property focused (keyable).
	*	\return Current focus (keyable) state for the property.
	*/
	bool IsFocused();

	/** Set the property's focus (keyable) state.
	*	\param	pState	Focus (keyable) state to set for the property.
	*/
	void SetFocus( bool pState );

	/**	Key the connector.
	*/
	void Key();

	/**	Get the data size (number of values) for the connector.
	*	\return	Data size.
	*/
	int GetDataSize() const;

	/**	Is the property animated.
	*	This is true if the property has an FCurve associated to it.
	*	\return	\b true if animated, \b false if not animated.
	*/
	virtual bool IsAnimated();

	/**	Set the animation state of the property.
	*	\param	pState	State of animation for property, true to animate, false to remove curves.
	*/
	void SetAnimated( bool pState );

	/**	Get the animation node for the property.
	*	\return	Animation node for property. NULL is returned if property is not animated.
	*/
	virtual HFBAnimationNode GetAnimationNode();

	/**	Get the owner box.
	*	\return Handle to the owning box (i.e. model).
	*/
	HFBBox GetBox();

	/**	Set the value of the property, passing the type as an argument.
	*	\param	pData	Value to affect property with.
	*/
	virtual void SetData( void* pData );

	/**	Get the value of a property.
	*	\retval	pValue	Value to fill with property's current value.
	*/
	virtual void GetData( void* pData, int pSize ) const;
};

/**	\internal
*	Base template class for animatable properties
*/
template <class tType, FBPropertyType pPT> class FBPropertyBaseAnimatable : public FBPropertyAnimatable
{
  public:
	//! Constructors.
	FBPropertyBaseAnimatable( );
	FBPropertyBaseAnimatable( const FBPropertyBaseAnimatable<tType,pPT> &pValue);

	//@{
	/**	Overloaded = operator
	*	\param	pValue	Value to set for property.
	*/
	void operator=(tType pValue);
	//@}

	/**	Overloaded cast to \b tType operator.
	*	\return	\b tType cast of current object.
	*/
    operator tType() const;

};

typedef class FBSDK_DLL FBPropertyBaseAnimatable< bool,kFBPT_Action >			FBPropertyAnimatableAction;
typedef class FBSDK_DLL FBPropertyBaseAnimatable< bool,kFBPT_bool >				FBPropertyAnimatableBool;
typedef class FBSDK_DLL FBPropertyBaseAnimatable< int,kFBPT_int >				FBPropertyAnimatableInt;
typedef class FBSDK_DLL FBPropertyBaseAnimatable< int,kFBPT_enum >				FBPropertyAnimatableEnum;
typedef class FBSDK_DLL FBPropertyBaseAnimatable< double,kFBPT_double >			FBPropertyAnimatableDouble;
typedef class FBSDK_DLL FBPropertyBaseAnimatable< FBVector2d,kFBPT_Vector2D >	FBPropertyAnimatableVector2d;
typedef class FBSDK_DLL FBPropertyBaseAnimatable< FBVector3d,kFBPT_Vector3D >	FBPropertyAnimatableVector3d;
typedef class FBSDK_DLL FBPropertyBaseAnimatable< FBVector4d,kFBPT_Vector4D >	FBPropertyAnimatableVector4d;
typedef class FBSDK_DLL FBPropertyBaseAnimatable< FBColor,kFBPT_ColorRGBA >		FBPropertyAnimatableColor;

////////////////////////////////////////////////////////////////////////////////////
// Global
////////////////////////////////////////////////////////////////////////////////////
#ifdef FBSDKUseNamespace
	}
#endif

#endif
