
//**************************************************************************/
// Copyright (c) 2008 Autodesk, Inc.
// All rights reserved.
//
// Use of this software is subject to the terms of the Autodesk license
// agreement provided at the time of installation or download, or which
// otherwise accompanies this software in either electronic or hard copy form.
//
//**************************************************************************/
// DESCRIPTION:
// CREATED: October 2008
//**************************************************************************/

namespace mudbox {

class Template;
class Node;

/// This structure represents and describes a class.
class MBDLL_DECL ClassDesc
{
	const ClassDesc *m_pParent[2], *m_pNext;
	const char *m_sName;
	const char *m_sDisplayName;
	typedef class Node *creator( unsigned int );
	creator *m_pCreator;
	static ClassDesc *s_pFirst;
	Template *m_pTemplate;
	int m_iVersion;
public:
	int m_iStreamVersion;
	
	/// Do not construct this structure directly, use the #DECLARE_CLASS and #IMLEMENT_CLASS macros.
	ClassDesc( const ClassDesc *pParent0, const ClassDesc *pParent1, const char *sName, const char *sDisplayName, creator *pCreator, int iVersion = 0, int iStreamVersion = 0 );
	/// Get the class description for the parent class, or 0 if there is no parent.
	const ClassDesc *Parent( unsigned int iIndex = 0 ) const;
	/// Returns the name of the class.
	const char *Name( void ) const;
	/// Returns the displayname of the class.
	const char *DisplayName( void ) const;
	/// Returns true if this class is derived from pClass.
	bool IsDerivedFrom( const ClassDesc *pClass ) const;
	/// Create instances of the class.
	class Node *CreateInstances( int iCount = 1 ) const;

    /// \name Type enumeration functions 
    ///@{ 
	    /// Returns the first ClassDesc (See also Next()).
	    static const ClassDesc *First( void );
	    /// Returns the next ClassDesc structure. Used when you want to enumerate all the classes (See also First())
	    const ClassDesc *Next( void ) const;
    ///@}

	/// Returns a class by its name, or 0 if the class is not found.
	static const ClassDesc *ByName( const QString &sName );
	/// returns the version of the class.
	int Version( void ) const;

	friend class Node;
	friend class Stream;
};

/// \brief This macro should be used in declaration of classes which are inherited from the Node class (or any descendant of that) to fill RTTI information.
///
/// You have to use this with the IMPLEMENT_CLASS macro. Example:
/// \code
/// class MyClass : public Node
/// {
///     DECLARE_CLASS
///     // other members follow
/// }
/// \endcode
/// in the corresponding cpp file:
/// \code
/// #include "MyClass.h"
/// IMPLEMENT_CLASS( MyClass, Node, "My Class" );
/// \endcode
/// After this you will be able to access the following functionality:
/// 1. Your class will be listed as the implemented classes in mudbox. This means that other plugins, or mudbox itself
///     will be able to create instances of your class. See the Imported class for more details.
/// 2. It will be possible to identify the runtime type of your objects.
#define DECLARE_CLASS \
private: \
	static mudbox::ClassDesc s_cMyClass; \
public: \
	virtual const mudbox::ClassDesc *RuntimeClass( void ) const { return &s_cMyClass; }; \
	static const mudbox::ClassDesc *StaticClass( void ); \
	static mudbox::Node *CreateInstances( unsigned int iCount = 1 );

#define IMPLEMENT_SDK_VCLASS2( name, parent0, parent1, displayname, instanceclass, version, streamversion ) \
	mudbox::ClassDesc name::s_cMyClass( parent0::StaticClass(), parent1::StaticClass(), #name, displayname, name::CreateInstances, version, streamversion ); \
	const mudbox::ClassDesc *name::StaticClass( void ) { return &s_cMyClass; }; \
	mudbox::Node *name::CreateInstances( unsigned int iCount ) \
		{ Node *p; \
			if ( iCount > 1 ) { p = new instanceclass[iCount]; for ( unsigned int i = 0; i < iCount; i++ ) p[i].Initialize(); } \
			else { p = new instanceclass; p->Initialize(); }; \
			return p; };

#define IMPLEMENT_SDK_CLASS( name, parent, displayname, instanceclass ) IMPLEMENT_SDK_VCLASS2( name, parent, parent, displayname, instanceclass, 0, 0 )
#define IMPLEMENT_VCLASS2( name, parent0, parent1, displayname, version ) IMPLEMENT_SDK_VCLASS2( name, parent0, parent1, displayname, name, version, 0 )
#define IMPLEMENT_VCLASS( name, parent, displayname, version ) IMPLEMENT_SDK_VCLASS2( name, parent, parent, displayname, name, version, 0 )
#define IMPLEMENT_CLASS2( name, parent0, parent1, displayname ) IMPLEMENT_SDK_VCLASS2( name, parent0, parent1, displayname, name, 0, 0 )
#define IMPLEMENT_CLASS( name, parent, displayname ) IMPLEMENT_SDK_VCLASS2( name, parent, parent, displayname, name, 0, 0 )
/// \brief This macro is the same as the IMPLEMENT_CLASS macro, but it also accepts an additional parameter, which is the stream version for the class
///
/// When the IMPLEMENT_CLASS macro is used, the local stream version for the class is default to zero. This version number will be automatically
/// written to each stream. When the stream is loaded, you can check which version of your class implementation was writing it, so you know
/// how to read the content of the file. Normally you increase the local version number in your class by 1, when you change something in your
/// Serialize function implementation. For example id your serialize function looks like this:
/// \code
/// IMPLEMENT_SCLASS( MyClass, Node, "MyClass", 4 );
///
/// void MyClass::Serialize( Stream &s )
/// {
///		s == m_bEnabled == m_sName;
/// };
/// \endcode
/// And you want to add a new member variable to the stream, you change the code to the following:
/// \code
/// IMPLEMENT_SCLASS( MyClass, Node, "MyClass", 5 );
///
/// void MyClass::Serialize( Stream &s )
/// {
///		s == m_bEnabled == m_sName;
///    if ( s.IsNewerThan( 4, this )
///			s == m_iLevel;	// this path will be executed when you load/save the most recent file format
///		else
///			m_iLevel = 0;	// and this path will be executed when you load an old file format
/// };
/// \endcode
/// This way, you will be able to load old files without problem, and maintain compatibility.
#define IMPLEMENT_SCLASS( name, parent, displayname, streamversion ) IMPLEMENT_SDK_VCLASS2( name, parent, parent, displayname, name, 0, streamversion )

/// Possible event types when Node::OnNodeEvent is called.
enum NodeEventType
{
	/// Value of an attribute is changed.
	etValueChanged,
	/// The attribute is relinked to another attribute, so source is changed.
	etSourceChanged,
	/// A new attribute is linked to this one, or a link is removed.
	etTargetChanged,
	/// This is valid only for pointer type attributes (See AttributePointer). This is posted when the target node of the pointer is changed (See Node::ContentChanged())
	etPointerContentChanged,
	/// This is valid only for pointer type attributes (See AttributePointer). The target node of the pointer is about to destroyed.
	etPointerTargetDestroyed,
	/// Status of the attribute is changed (See SetConst()).
	etStatusChanged,
	/// UI data in attributes are changed.
	etPointerTargetUIChanged,
	/// Previously requested deferred event.
	etDeferred,
	/// Causes entire dialog to refresh its UI.  Should be used
	/// at the end of a batch job.
	etRefreshDialogUI,
	/// An event triggered.
	etEventTriggered = etValueChanged
};

/// \brief This is an abstract base structure for all attributes. Do not use it directly, use AttributeInstance instead.
///
/// Each node has a list of attributes with different types. The attributes are used like plain data members of the
/// node class, but in case of attributes, mudbox will be able to get a list of all the attributes in a node, and for
/// example it will be possible so simply display a dialog to the used where it is possible to check and alter the value
/// of the variables.
struct MBDLL_DECL Attribute
{	
	/// Type of the attribute
	enum AttributeType
	{
		/// Unknown attribute
		typeUnknown,
		/// Standard integer, 4 bytes.
		typeInt,
		/// Standard float, 4 bytes.
		typeFloat,
		/// Standard bool, 1 bytes.
		typeBool,
		/// String attribute, can store any UNICODE text.
		typeString,
		/// Pointer attribute, see AttributePointer.
		typePointer,
		/// Color attribute, 4xfloat, See Color.
		typeColor,
		/// Vector, 3xfloat, see Vector.
		typeVector,
		/// Standard enum attribute, 4 bytes.
		typeEnum,
		/// Empty attribute, used only to catch events. See AttributeWatch.
		typeWatch
	};

	/// Returns the number of attributes currently linked to this attribute as target.
	unsigned int TargetCount( void ) const;
	/// Returns the target with the given index. If iIndex is greater than the number of targets, returns 0;
	Attribute *Target( unsigned int iIndex ) const;
	/// Returns the source attribute, or 0 if there is no source.
	Attribute *Source( void );
	/// This is a special operator, it does NOT compare the value of the attribute. See Node::OnNodeEvent for details.
	bool operator ==( const Attribute &cAttribute ) const;
	/// This is a special operator, it does NOT compare the value of the attribute. See Node::OnNodeEvent for details.
	bool operator !=( const Attribute &cAttribute ) const;
	/// Returns the type of the attribute.
	virtual AttributeType Type( void ) const;

	/// Returns the unique ID (within this node) of the attribute.
	QString ID( void ) const;
	/// Returns the name of the attribute.
	QString Name( void ) const;
	/// Sets the name of the attribute.
	void SetName( const QString &sName );
	/// Returns the category of the attribute.
	QString Category( void ) const;
	/// Sets the category of the attribute. This value will be used in the user interface to determine which attribute group to be used.
	void SetCategory( const QString &sCategory, bool bSeparator = false );
	/// Returns the separator state of the widget.
	bool Separator( void ) const;
	/// Call this with true to display a separator line below this widget.
	void SetSeparator( bool bSeparator );
	/// Gets the constant status of the attribute. Default value is false. If this is set to true the attribute will not be editable by the user on the interface.
	bool Const( void ) const;
	/// Sets the constant status of the attribute. Default value is false. If this is set to true the attribute will not be editable by the user on the interface.
	void SetConst( bool bConst );
	/// Returns true if the property is visible.
	bool Visible( void ) const;
	/// Sets the visible status of the property.
	void SetVisible( bool bVisible );
	/// Gets the tooltip text to be used on the user interface, this is optional.
	QString ToolTip( void ) const;
	/// Sets the tooltip text to be used on the user interface, this is optional.
	void SetToolTip( const QString &sToolTip );
	/// Returns the size of the attribute value in bytes.
	unsigned int Size( void ) const;
	/// \brief Returns the width of label relative to the full width of the line. 
	/// 
	/// A value 0.4 means that the label will take 40%, while the value part will take 60% of the available space.
	float LabelWidth( void ) const;
	/// Set the width of label.
	void SetLabelWidth( float fLabelWidth );
	/// Returns the attribute index;
	int Index( void ) const;
	/// Sets the attribute index;
	void SetIndex( int iIndex );

	/// Gets the address of the Node which contains this attribute.
	Node *Owner( void ) const;
	/// Serialize the value of the attribute into a stream.
	virtual void Serialize( Stream &s );

	/// Returns the value of the attribute as a string. See also SetFromString.
	virtual QString AsString( void ) const;
	/// Sets the value of the attribute as a string. See also AsString. 
	virtual void SetFromString( const QString &sValue );

    /// \name Attribute connecting functions
    /// These functions are related to creating dependent connections between attributes. 
    /// When a source attribute value changes, the target attribute value will change also. 
    ///@{
	    /// Removes all outgoing connections from the attribute.
	    void ClearTargets( void );
	    /// Removes the incoming connection for this attribute.
	    void ClearSource( void );
	    /// Adds a new outgoing connection for this node to pTarget.
	    virtual void AddTarget( Attribute &cTarget );
	    /// Connect this attribute to another one.
	    void Connect( Attribute &cSource );
	    /// \internal Update the values of all the connected target attributes with the current value. Used internally only, do not call this directly.
	    virtual void UpdateTargets( void );
    ///@}

    /// \name Pointer attribute functions
    /// These functions are intended for use only with AttributePointer.
    ///@{
	    /// This is valid only for pointer attributes (See AttributePointer). Returns the type of the pointer.
	    virtual const ClassDesc* TargetType( void ) const;
	    /// This is valid only for pointer attributes (See AttributePointer). Sets the value of the pointer. This function is used only if you dont know exactly the type of the attribute. Use AttributePointer::SetValue otherwise.
	    virtual void SetPointerValue( Node *pValue, bool bLink = true );
	    /// This is valid only for pointer attributes (See AttributePointer). Gets the value of the pointer. This function is used only if you dont know exactly the type of the attribute. Use AttributePointer::Value otherwise.
	    virtual Node *PointerValue( void ) const;
	    /// Validate a possible value for the pointer, returns true if the value is acceptable.
	    virtual bool ValidatePointerValue( const Node *pValue );
    ///@}

	virtual ~Attribute( void );
	virtual void StartEvent( NodeEventType cType ) const;
	
    /// \brief This function sets the owner of the attribute.  The owner receives all events for this attribute
	///
	/// The owner is the receiver of all events from the attribute.  This function removes any old owner & installs
	/// a new owner.  If NULL or 0 is used as an argument then the old owner is removed and no owner exists for this
	/// attribute.
    void SetOwner( Node *pOwner );

	/// \brief This function creates and returns the address of a QWidget object.
	/// 
	/// The object then can be used in the interface to give the user control over the attribute value. Mudbox calls this
	/// function for every attribute in a node when it displays a properties dialog box for it.
	/// You must override it if you implement a new kind of attribute and want a special interface.
	virtual AttributeWidget *CreateEditorWidget( QWidget *pParent, 
		int iWidth /// Width of the control in pixels.
		);
	
    /// \name Parameter functions
    /// These functions allow you to query or modify the parameters associated with an attribute.
    ///@{
    /// Returns the number of parameters assigned to this attribute.
    virtual unsigned int ParameterCount( void ) const;
    /// Returns the name of a parameter with a given index.
    virtual QString ParameterName( unsigned int iIndex ) const;
    /// Returns the value of parameter with a given index.
    virtual QString ParameterValue( unsigned int iIndex ) const;
    /// Set the value of a parameter.
    virtual void SetParameterValue( const QString &sName, const QString &sValue );
    ///@}

	/// \internal Log all targets (for debug purposes)
	void LogTargets( void );
	
protected:

	Attribute( Node *pOwner, const QString &sID);
	Attribute( Node *pOwner, bool bInstall);

	int m_iSize;
	Attribute *m_pSource, *m_pNext;
	Store<Attribute *> m_aTargets;
	Node *m_pNode;
	QString m_sName;
	bool m_bSeparator;
	QString m_sCategory;
	QString m_sToolTip;
	float m_fLabelWidth;
	bool m_bConst;
	bool m_bVisible;
	int m_iIndex;
	QString m_sID;

	void Uninstall( void );

	friend class Node;
};

/// \brief Used to insert expanded category item
///
/// Will be deprecated someday.  This attribute is simply used to insert a UI element into the
/// auto generated UI.
class MBDLL_DECL AttributeVoid : public Attribute
{
public:
	AttributeVoid(Node *pOwner, const QString &sName ) : Attribute(pOwner, sName) {}
	~AttributeVoid() {}
};

typedef AttributeVoid avoid;

/// \brief This is a generic attribute which can be used instead of the standard built in types. 
///
/// The difference between a standard type and this attribute is that this attribute can be viewed and its value can be changed by the user.
/// Attributes can be linked together also so when the value of an attribute is changed, all target attributes value will be changed also.
/// The owner node also can catch events regarding to the attrbibutes, for example when the user changes the value.
template < typename type >
struct MBDLL_TEMPLATE_DECL AttributeInstance : public Attribute
{
	/// Standard constructor. You have to specify the name of the attribute which will be used in the user interface.
	AttributeInstance( Node *pOwner, const QString &sID) : Attribute( pOwner, sID ) { m_iSize = sizeof(type); };
	/// Using this constructor you can also specify the initial value of the attribute with its name.
	AttributeInstance( Node *pOwner, const QString &sID, const type &cValue ) : Attribute( pOwner, sID ) { m_cValue = cValue; m_iSize = sizeof(type); };

	// Value management
	/// Returns the value of the attribute.
	const type &Value( void ) const { return m_cValue; };
	/// \brief Set the value of the attribute to cValue
	/// \param bInternal if this is false the owner node will receive an event about the value change (See NodeEventType::etValueChanged).
	virtual void SetValue( type cValue, bool bInternal = false )
	{
		m_cValue = cValue;
		UpdateTargets();
		if ( !bInternal )
			StartEvent( etValueChanged );
	};
	void UpdateTargets( void )
	{
		for ( unsigned int i = 0; i < TargetCount(); i++ )
		{
			if ( Target(i)->Size() == Size() )
				((AttributeInstance<type> *)Target(i))->SetValue( m_cValue );
			else
				Target(i)->StartEvent( etValueChanged );
		};
	};
	void Serialize( Stream &s );

	// Connection management
	void AddTarget( Attribute &cTarget )
	{
		Attribute::AddTarget( cTarget );
		if ( cTarget.Size() )
		{
			AttributeInstance<type> *pT = (AttributeInstance<type> *)&cTarget;
			if ( pT->Value() != Value() )
				pT->SetValue( Value() );
		};

		StartEvent( etTargetChanged );
		cTarget.StartEvent( etSourceChanged );
	};

	// Default string operations
	QString AsString( void ) const
	{
		QString sValue;
		const unsigned char *tData = (const unsigned char *)(void *)(&m_cValue);
		for ( unsigned int i = 0; i < sizeof(m_cValue); i++ )
		{
			if ( i ) 
				sValue += " ";
			sValue += QString("%1").arg(int(tData[i]));
		};
		return sValue;
	};
	void SetFromString( const QString &sValue )
	{
		unsigned char *tData = (unsigned char *)(void *)(&m_cValue);
		for ( int i = 0; i < (int)sizeof(m_cValue); i++ )
			tData[i] = sValue.section(' ', i, i).toInt();
	};
	AttributeWidget *CreateEditorWidget( QWidget *pParent, int iWidth ) { return Attribute::CreateEditorWidget( pParent, iWidth ); };
	Attribute::AttributeType Type( void ) const { return Attribute::AttributeType(); };

	// Operators
	// Used for the QString class which does not have a predefined ! operator
	// if the line below is used, than pointers wont be linked into the target node THIS pointer.
	//inline type operator =( type cValue ) { AttributeInstance<type>::SetValue( cValue, true ); return cValue; }; 
#define OPERATORS_NOEXCMARK( type ) \
	/*! Returns the value of the attribute, same as Value(), but its more confortable in some situations */ \
	inline operator const type( void ) const { return AttributeInstance<type>::Value(); }; \
	/*! Returns the value of the attribute, same as Value(), but its shorter. */ \
	inline type const &operator ~( void ) const { return AttributeInstance<type>::Value(); }; \
	/*! Sets the value of the attribute. Almost the same as SetValue() but it wont give a feedback event to the owner node. (See NodeEventType::etValueChanged) */ \
	inline type operator =( type cValue ) { SetValue( cValue, true ); return cValue; }; \
	/*! Sets the value of the attribute. Almost the same as SetValue() but it wont give a feedback event to the owner node. (See NodeEventType::etValueChanged) */ \
	inline type operator =( const AttributeInstance<type> &cValue ) { /*AttributeInstance<type>::*/SetValue( cValue.AttributeInstance<type>::Value(), true ); return cValue; }; \
	/*! Compare the values of two attributes (This is not the same as Attribute::operator ==()) */ \
	inline bool operator ==( type cValue ) const { return AttributeInstance<type>::Value() == cValue; }; \
	/*! Compares the value of two attributes and returns true if they differ. */ \
	inline bool operator !=( type cValue ) const { return AttributeInstance<type>::Value() != cValue; }; \
	/*! \brief Sets the category of the attribute, same as SetCategory.
	
	This operator is used to make category alligment easier. You can use it like this:
	\code m_iValue0 <<= m_iValue1 <<= m_iValue2 <<= "Values"; \endcode
	If you want to assign the same category to multiply attributes the same time.*/ \
	inline const QString &operator <<=( const QString &sCategory ) { AttributeInstance<type>::SetCategory( sCategory ); return sCategory; };
#define OPERATORS( type ) \
	OPERATORS_NOEXCMARK( type ) \
	/*! Returns true if the pointer has a target.*/ \
	inline bool operator !( void ) { return !AttributeInstance<type>::Value(); };

	OPERATORS( type );
 
protected:
	/// Protected constructor, do not use it. You have to specify the name of the attribute which will be used in the user interface.
	AttributeInstance( Node *pOwner, const QString &sName, bool bInstall ) : Attribute( pOwner, bInstall ) { m_sName = sName; m_iSize = sizeof(type); };
	
private:
// HACK:
public:
	type m_cValue;
};

/// This type has to be used instead of the general int type.
typedef AttributeInstance<int> aint;
/// This type has to be used instead of the general float type.
typedef AttributeInstance<float> afloat;
/// This type has to be used instead of the general bool type.
typedef AttributeInstance<bool> abool;
/// This type has to be used instead of the String type.
typedef AttributeInstance<QString> astring; 

template <> inline
bool astring::operator !(void) { return !(m_cValue.isEmpty()); }

template <> inline
QString aint::AsString( void ) const { return QString("%1").arg(m_cValue); };
template <> inline
QString afloat::AsString( void ) const { return QString("%1").arg(m_cValue); };
template <> inline
QString abool::AsString( void ) const { return m_cValue ? "true" : "false"; };
template <> inline
QString astring::AsString( void ) const { return m_cValue; };

template <> inline
void aint::SetFromString( const QString &sValue ) { m_cValue = sValue.toInt(); };
template <> inline
void afloat::SetFromString( const QString &sValue ) { m_cValue = sValue.toFloat(); };
template <> inline
void abool::SetFromString( const QString &sValue ) { if ( sValue == "true" ) m_cValue = true; if ( sValue == "false" ) m_cValue = false; };
template <> inline
void astring::SetFromString( const QString &sValue ) { m_cValue = sValue; };

template <> inline
Attribute::AttributeType aint::Type( void ) const { return typeInt; };
template <> inline
Attribute::AttributeType abool::Type( void ) const { return typeBool; }; 
template <> inline
Attribute::AttributeType afloat::Type( void ) const { return typeFloat; };
template <> inline
Attribute::AttributeType astring::Type( void ) const { return typeString; };

MBDLL_DECL AttributeWidget *CreateNewPtrWidget( QWidget *pParent, int iWidth, Attribute *pAttribute, const ClassDesc *pType );
MBDLL_DECL AttributeWidget *CreateNewBoolWidget( QWidget *pParent, int iWidth, abool *pAttribute );
MBDLL_DECL AttributeWidget *CreateNewIntWidget( QWidget *pParent, int iWidth, aint *pAttribute );

template <> inline
AttributeWidget *abool::CreateEditorWidget( QWidget *pParent, int iWidth ) { return CreateNewBoolWidget( pParent, iWidth, this ); };
template <> inline
AttributeWidget *aint::CreateEditorWidget( QWidget *pParent, int iWidth ) { return CreateNewIntWidget( pParent, iWidth, this ); };

/// This operator compares the two attributes and NOT their values. Returns true only if the two attribute instances are the same (See Node::OnNodeEvent).
template < typename type > inline
bool operator ==( const Attribute &cA, const AttributeInstance<type> &cB )
{
	return &cA == &cB;
};
    
template < typename type > inline
Stream &operator ==( Stream &s, AttributeInstance<type> &c )
{
	c.Serialize( s );
	return s;
};

class EventGate;

/// \brief This class can be used instead of standard pointers, when the pointer target class is derived from the Node class.
///
/// This object has the following advantages over a plain pointer:
/// \li The pointer value will be zero by default, you don't have to initialize it.
/// \li If the target of the pointer is destroyed, the pointer value becomes zero automatically.
/// \li The owner of the pointer (the class which declares the pointer object as a member variable) will be able to catch events about the target of the pointer, like when its content is changed, or it's destructed.
/// \li The pointer value will be serializable. If the pointer has a valid target, the target will be included in the mud file also. See AttributePointer::Serialize() for more details.
template < typename type >
class AttributePointer : public AttributeInstance<type *>
{
	const ClassDesc *TargetType( void ) const { return type::StaticClass(); };
	Node *PointerValue( void ) const { return AttributeInstance<type *>::Value(); };
	void UpdateTargets( void )
	{
		for ( unsigned int i = 0; i < AttributeInstance<type *>::TargetCount(); i++ )
			AttributeInstance<type *>::Target(i)->SetPointerValue( PointerValue(), false );
	};
	AttributeWidget *CreateEditorWidget( QWidget *pParent, int iWidth ) { return CreateNewPtrWidget( pParent, iWidth, this, type::StaticClass() ); };
	typedef bool validator( const type *pTarget );
	validator *m_pValidator;
	bool ValidatePointerValue( const Node *pValue )
	{
		if ( m_pValidator == 0 || m_pValidator( dynamic_cast< const type *>( pValue ) ) )
			return true;

		return false;
	};

public:
	AttributePointer( Node *pOwner=NULL, const QString &sID = "") : AttributeInstance<type *>( pOwner, sID ) { SetValue( 0, true ); m_pValidator = 0; m_sNullString = "NULL"; m_bAllowNull = true; };
	AttributePointer( Node *pOwner, const QString &sID,  bool bInstall ) : AttributeInstance<type *>( pOwner, sID, bInstall ) { SetValue( 0, true ); m_pValidator = 0; m_sNullString = "NULL"; m_bAllowNull = true; };
	QString AsString( void ) const { if ( PointerValue() ) return PointerValue()->Name(); else return m_sNullString; };
	void SetFromString( const QString & /*sValue*/ ) { SetPointerValue( 0 ); };
	/// Register a function as the validator for this pointer. This function will be called each time a new value has to be assigned to the pointer. If this function returns false the value wont be assigned to the pointer.
	inline void SetValidator( validator *pValidator ) { m_pValidator = pValidator; };
	void SetPointerValue( Node *pNode, bool bLink = true ) 
	{
		// always accept 0 pointer, the target may be destroyed
		if ( pNode && m_pValidator && !m_pValidator( dynamic_cast<type *>( pNode ) ) )
			return;
		if ( bLink )
			SetValue( dynamic_cast<type *>( pNode ) );
		else
			AttributeInstance<type *>::SetValue( dynamic_cast<type *>( pNode ) );
	};
	void SetValue( type *cValue, bool bX = false )
	{
		if ( cValue == AttributePointer<type>::Value() )
			return;
		AttributeInstance<type *>::SetValue( cValue, bX );
		if ( cValue )
			cValue->m_pThis.AddTarget( *this );
	};
	void AddTarget( Attribute &cTarget )
	{
		Attribute::AddTarget( cTarget );
		if ( cTarget.Size() )
		{
			if ( cTarget.PointerValue() == PointerValue() )
				cTarget.SetPointerValue( PointerValue() );
		};
	};
	/// Deletes the object what is referred in this pointer
	void DeleteTarget( void )
	{
		delete AttributePointer<type>::Value();
	};
	/// \brief Serializes the pointer value to a stream.
	///
	/// The following two lines are doing the same:
	/// \code
	/// s == m_pMyPointer;
	/// m_pMyPointer.Serialize( s );
	/// \endcode
	/// The stream has an internal list of the nodes it contains. This list is empty when the stream is opened, and keeps 
	/// growing as more and more nodes are serialized. If the stream is writing data to a file and a pointers Serialize 
	/// function is called, the stream checks the list if the target of the pointer is there or not. If its there, it will only
	/// write the index of the node into the stream. Otherwise it will serialize the target node and append it to the end
	/// of the list. You don't have to know about this mechanism, but be carefull because if you serialize pointers in your
	/// nodes then it might lead to a huge stream file containing lots of nodes. For example if you have a pointer to a 
	/// mesh object, and you serialize that pointer, then the whole scene graph will be serialized to the file, since the 
	/// mesh node will also serialize some pointers and so on.
	void Serialize( Stream &s );
	void StartEvent( NodeEventType cType ) const
	{
		AttributeInstance<type *>::StartEvent( cType );
		if ( cType == etPointerContentChanged || cType == etPointerTargetDestroyed || cType == etPointerTargetUIChanged || cType == etRefreshDialogUI )
			for ( unsigned int i = 0; i < AttributeInstance<type *>::TargetCount(); i++ )
				AttributeInstance<type *>::Target( i )->StartEvent( cType );
	};
	Attribute::AttributeType Type( void ) const { return AttributeInstance<type *>::typePointer; };
#define PTROPERATORS( type ) \
	OPERATORS( type* ); \
	/*! This operator is provided if you can to assign 0 value to a pointer.*/ \
	inline type *operator =( int iValue ) { MB_ASSERT( iValue == 0 ); return operator =( (type *)(uint64)iValue ); }; \
	/*! This operator is provided if you want to compare the value of the pointer to 0.*/ \
	inline bool operator ==( int iValue ) { MB_ASSERT( iValue == 0 ); return operator ==( (type *)(uint64)iValue ); }; \
	/*! This operator is provided if you want to compare the value of the pointer to 0.*/ \
	inline bool operator !=( int iValue ) { MB_ASSERT( iValue == 0 ); return operator !=( (type *)(uint64)iValue ); }; \
	/*! This operator is provided if you want to access a member of the target structure/class.*/ \
	inline type *operator ->( void ) { return AttributeInstance<type *>::Value(); }; \
	/*! This operator is provided if you want to access a member of the target structure/class.*/ \
	inline const type *operator ->( void ) const { return AttributeInstance<type *>::Value(); }; \
	/*! This operator convert the value to bool, true if the pointer value is not 0.*/ \
	inline operator bool( void ) const { return AttributeInstance<type *>::Value() != 0; };
	PTROPERATORS( type );

	QString m_sNullString;
	bool m_bAllowNull;

	friend class Node;
	friend class AttributeThisPointer;
	friend struct Attribute;
};

//template < typename type>
//typedef AttributePointer<type> aptr<type>;
#define aptr AttributePointer
template < typename type >
inline Stream &operator ==( Stream &cStream, AttributePointer<type> &cPointer ) { cPointer.AttributePointer<type>::Serialize( cStream ); return cStream; };

/// \internal This class represents a special pointer in the Node class, it always points to the owner. Used internally.
class MBDLL_DECL AttributeThisPointer : public aptr<Node>
{
	AttributeThisPointer( Node *pOwner );
	const ClassDesc *TargetType( void ) const;
	PTROPERATORS( Node );

	friend class Node;
};

/// \brief This is the base class for most classes in the Mudbox SDK. 
class MBDLL_DECL Node
{
	Attribute *m_pAttributes;

	static Node *s_pFirstNode;
	int m_iID;
	Node *m_pNext, *m_pPrev;

	static int s_iNextID;
	friend struct Attribute;
	friend class Stream;

public:
	/// Standard constructor. You can specify the name of the node which will be used in the user interface. See Name().
	Node( const QString &sName = "" );
	virtual ~Node( void );
	virtual void Initialize( void );

    /// \name Event functions 
    /// These functions are used for working with node events, such as notifications 
    /// to changes to an attribute.
    ///@{
	    /*! \brief This function is called if an event occurs with any of the attributes of the node.

	    All derived classes should override this function to be able to handle attribute events.
	    \param cAttribute The attribute which caused the event. The attribute has a special == operator to make it easier to implement this function. You can write the following:
        \code
        void MyClass::OnNodeEvent( const Attribute &cAttribute, NodeEventType cType )
        {
            if ( cAttribute == myAttribute0 )
            {
	            ...
            }
            else if ( cAttribute == myAttribute1 )
            {
	            ...
            }
        }
	    \endcode
	    This comparison will check the address of the two attributes and NOT their values.
	    \param cType Type of the event occured.
	    */
	    virtual void OnNodeEvent( const Attribute &cAttribute, NodeEventType cType );
	    /// This function is called when a generic event occurs. See EventGate class.
	    virtual void OnEvent( const EventGate &cEvent );
	    /// Request for a deferred event, which will occur only in the main loop.
	    void RequestDeferredEvent( Attribute &cAttribute );
    ///@}

	/// Use an external XML file to initialize the attributes.
	void LoadTemplate( const QString &sFileName = "", bool bStartEvent = false );
	/// Save current attributes as an XML template.
	void SaveTemplate( const QString &sFileName = "", bool bSaveOnlyVisible = false);
	/// Returns the current version of the node. This number increases when the content of the node changed (when ContentChanged() called).
	unsigned int Version( void ) const;
	/// Sets the current version number for the node.
	void SetVersion( unsigned int iVersion );
	
    /// \name Node enumeration and retrieval function
    /// The following functions are used for enumerating over nodes.
    ///@{
	    /// This function will return the first node in the memory. Used to enumerate all the current nodes. See also Next().
	    static Node *First( void );
	    /// Returns the next node in the chain. Used to enumerate the current nodes. See also First().
	    Node *Next( void ) const;
	    /// Returns an ID for the node. The ID is unique in the whole application life.
	    int ID( void ) const;
	    /// Returns the node with the specified ID, or zero if such a node does not exists.
	    static Node *ByID( int iID );
	    /// Search for a node with the name sName. Will return 0 if the node was not found.
	    static Node *ByName( const QString &sClass, const QString &sName );
    ///@}

	/// Returns the name of the node. Can be overwritten in derived classes.
	virtual QString Name( const ClassDesc *pClass = 0 ) const;
	/// Sets the name of the node. Has no effect if Name() is overwritten in a derived class.
	void SetName( const QString &sName );

	/// Relink all the attributes of the source node to this one.
	void Annex( Node *pSource, const QString &sCategory = "" );

    /// \name Attribute methods
    /// These functions are for working with attributes.
    ///@{
	    /// Returns the number of attributes owned by the node.
	    unsigned int AttributeCount( void ) const;
	    /// Returns a specified attribute (or 0 if iIndex is greater than the number of attributes).
	    Attribute *AttributeByIndex( int iIndex ) const;
	    /// Returns a specified attribute by its name. Returns 0 if the attribute not found.
	    Attribute *AttributeByName( const QString &sName ) const;
	    /// Returns a specified attribute by its ID. Returns 0 if the attribute not found.
	    Attribute *AttributeByID( const QString &sID ) const;
	    /// Write all attributes into the log file.
	    void LogAttributes( void ) const;
	    /// Create a window which displays the attributes of the node. Can be overriden to provide a custom interface.
	    virtual QWidget *CreatePropertiesWindow( QWidget *pParent );
    ///@}

	/// \brief Serializes the node. 
    ///
    /// Override this function in your plug-in to save and load attributes and custom data with the Mudbox file.
	virtual void Serialize( Stream &s );

	AttributeThisPointer m_pThis;

	friend class EventGate;

	/// Returns true if this node is derived from the pClass class.
	bool IsKindOf( const ClassDesc *pClass ) const;
	
    /// This function must be called if the content of the node is changed. 
    /// All other nodes which has an AttributePointer pointing to this node will receive a 
    /// event notficiation of type etPointerContentChanged (See NodeEventType).
	void ContentChanged( void ) const;
	
    DECLARE_CLASS;

private:
	QString m_sName;
	mutable unsigned int m_iVersion;
};

/// Creates an event widget. 
AttributeWidget *CreateNewEventWidget( QWidget *pParent, int iWidth, EventGate *pAttribute );

/// \brief This class represents an event receiver/triggerer point.
/// 
/// This is a special attribute, by linking these gates together you can receive events. If a class wants to emit one type of event and want to receive 5 events then it needs 6 EventGate attributes.
/// The receiver eventgates must be linked to emitter evengates (See Connect()). It is also possible to link a receiver to another receiver, then the event will travel along the chain and all receiver will receive the event.
/// \code
/// class MyClass : public Node
/// {
///     aevent m_eLowMemory;
///
///     MyClass( void )
///     {
///         m_eLowMemory.Connect( Kernel()->m_eLowMemory );
///     };
///     void OnEvent( const EventGate &cEvent )
///     {
///          if ( cEvent == m_eLowMemory )
///          {
///              // free some buffers
///          };
///     };
/// };
/// \endcode
/// In the example above, the class MyClass has an EventGate member variable. The class connects this variable
/// to the m_eLowMemory variable in Kernel, so when the m_eLowMemory event in kernel is triggered, the m_eLowMemory
/// event object will be triggered also. The class can catch the even with the OnEvent() function as seen above.
class MBDLL_DECL EventGate : public AttributeInstance<int>
{
	void StartEvent( NodeEventType cType ) const;
	AttributeWidget *CreateEditorWidget( QWidget *pParent, int iWidth );

public:
	/// Standard constructor.
	EventGate( Node *pOwner, const QString &sID = "" );
	/// Fire the event. Connected evengates will receive the event (See Node::OnEvent()).
	void Trigger( void );
	/// Connect this eventgate to another one to receive events from that.
	void Connect( EventGate &cEvent );
	/// Compare two eventgates.
	bool operator ==( const EventGate &cEvent ) const;
};
typedef EventGate aevent;

// special attributes
/// This attribute represents a float value which has a minimum and a maximum value. These values will be used in the user interface only, but the user will be able to assign values out of the range to the attribute.
class MBDLL_DECL AttributeFloatRange : public afloat
{
private:
	mutable float m_fMin, m_fMax;
	float m_fFactor;

	QString AsString( void ) const;
	void SetFromString( const QString &sValue );

	unsigned int ParameterCount( void ) const;
	QString ParameterName( unsigned int iIndex ) const;
	QString ParameterValue( unsigned int iIndex ) const;
	void SetParameterValue( const QString &sName, const QString &sValue );
public:
	/// Creates the attribute with the given name and limits.
	AttributeFloatRange( Node *pOwner, const QString &sID, float fMinimum = 0, float fMaximum = 1, float fFactor = 1 );
	OPERATORS( float );
	void StartEvent( NodeEventType cType ) const;
	AttributeWidget *CreateEditorWidget( QWidget *pParent, int iWidth );
	float Min( void ) const;
	float Max( void ) const;
	void SetMin( float fValue );
	void SetMax( float fValue );
};

typedef AttributeFloatRange afloatr;
MBDLL_DECL Stream &operator ==( Stream &s, afloatr &a );

/// An attribute that can hold a number and uses the specified number of digits when displaying on the UI.
class MBDLL_DECL AttributeNumber : public AttributeInstance<int>
{
	int m_iDigitCount;
	int m_iControlWidth;
	AttributeWidget *CreateEditorWidget( QWidget *pParent, int iWidth );
public:
	AttributeNumber( Node *pOwner, const QString &sID, int m_iControlwidth = 40, int m_iDigitCount = 0 );
	OPERATORS( int );
};

typedef AttributeNumber anumber;

/// This attribute is very similar to the aint type but on the user interface it will be displayed as a combobox, and the user will be able to choose its value from a list.
class MBDLL_DECL AttributeEnumeration : public aint
{
private:
	Store<QString> m_aValues;

	unsigned int ParameterCount( void ) const;
	QString ParameterName( unsigned int iIndex ) const;
	QString ParameterValue( unsigned int iIndex ) const;
	void SetParameterValue( const QString &sName, const QString &sValue );
public:
	AttributeEnumeration( Node *pOwner, const QString &sID );
	OPERATORS( int );
	AttributeWidget *CreateEditorWidget( QWidget *pParent, int iWidth );
	/// Add a new value to the attribute. The values will be assigned by calling order to this function, so the first given string will mean value 0, second will mean 1 and so on.
	unsigned int AddItem( const QString &sValue );
	void SetItem( unsigned int iIndex, const QString &sValue );
	/*! \brief This operator is provided to make it easier to fill the possible values for the attribute.
	
	You can write:
	\code
		m_eImageType << "gif" << "bmp" << "jpg" << "tif";
	\endcode
	Which is the same as
	\code
		n_eImageType.AddValue( "gif" );
		n_eImageType.AddValue( "bmp" );
		n_eImageType.AddValue( "jpg" );
		n_eImageType.AddValue( "tif" );
	\endcode
	*/
	AttributeEnumeration &operator <<( const char *sValue );
	/// Returns the number of items in the enumeration.
	unsigned int ItemCount( void ) const;
	void Clear( void );
	QString Item( unsigned int iIndex ) const;
};
typedef AttributeEnumeration aenum;
MBDLL_DECL Stream &operator ==( Stream &s, aenum &a );

/// Similar to AttributeInstance<String> but it provides a button on the interface where the user can browse for a filename.
class MBDLL_DECL AttributeFilename : public astring
{
public:
	AttributeFilename( Node *pOwner, const QString &sID, bool bMustExists = true );
	OPERATORS_NOEXCMARK( QString );
	AttributeWidget *CreateEditorWidget( QWidget *pParent, int iWidth );

	unsigned int ParameterCount( void ) const;
	QString ParameterName( unsigned int iIndex ) const;
	QString ParameterValue( unsigned int iIndex ) const;
	void SetParameterValue( const QString &sName, const QString &sValue );

	bool m_bMustExists;
	QString m_sFilter;
	QString m_sPath;
};
typedef AttributeFilename afilename;

/// Represents a special file name attribute that accepts texture files as value. Provides a create new and a browse interface.
class MBDLL_DECL AttributeTextureFilename : public AttributeFilename
{
public:
	AttributeTextureFilename( Node *pOwner, const QString &sID,  bool bMustExists = true );
	OPERATORS_NOEXCMARK( QString );
	AttributeWidget *CreateEditorWidget( QWidget *pParent, int iWidth );
};
typedef AttributeTextureFilename atexturefilename;
MBDLL_DECL Stream &operator ==( Stream &s, afilename &a );

/// \brief A fake attribute used to watch an attribute in your class which is not a member. 
/// Its better if you create a copy of the attribute in your class with the same type and link it to the target, 
/// but if you do not know the exact type of the other attribute you can use this class.
class MBDLL_DECL AttributeWatch : public Attribute
{
	Attribute::AttributeType Type( void ) const;
public:
	AttributeWatch( Node *pOwner, const QString &sID = "");
};

/// This attribute is a collection of bools.
class MBDLL_DECL AttributeBoolCollection : public AttributeInstance<int>
{
private:
	AttributeWidget *CreateEditorWidget( QWidget *pParent, int iWidth );
	QString m_aNames[32];
	unsigned int m_iBoolCount;

	unsigned int ParameterCount( void ) const;
	QString ParameterName( unsigned int iIndex ) const;
	QString ParameterValue( unsigned int iIndex ) const;
	void SetParameterValue( const QString &sName, const QString &sValue );
public:
	AttributeBoolCollection( Node *pOwner, const QString &sID );
	void Clear( void );
	void SetValue( unsigned int iIndex, bool bValue, bool bX = true );
	bool Value( unsigned int iIndex ) const;
	int AddBool( const QString &sName, bool bValue = false );
	unsigned int BoolCount( void ) const;
	void SetBoolName( unsigned int iIndex, const QString &sName );
	QString BoolName( unsigned int iIndex ) const;
};
typedef AttributeBoolCollection aboolc;

}; // end of namespace mudbox

