#ifndef _cgfxAttrDef_h_
#define _cgfxAttrDef_h_
#include <maya/MObject.h>
#include <maya/MString.h>
#include <maya/MMatrix.h>
#include <maya/MImage.h>
#include <maya/MMessage.h>
#include <maya/MDistance.h>
#include "cgfxRCPtr.h"
#include <Cg/cg.h>
#include <Cg/cgGL.h>
class  cgfxAttrDefList;                
class  cgfxEffect;                     
class  cgfxShaderNode;                 
class  cgfxTextureCacheEntry;
#define kNullCallback 0
class cgfxAttrDef
{
public:
    enum cgfxAttrType
    {
        
        
        kAttrTypeUnknown,
        
        
        
        kAttrTypeBool,
        
        
        
        kAttrTypeInt,
        
        
        
        kAttrTypeFloat,
        
        
        
        kAttrTypeString,
        
        
        
        
        kAttrTypeVector2,
        kAttrTypeVector3,
        kAttrTypeVector4,
        kAttrTypeObjectDir,     
        kAttrTypeFirstDir = kAttrTypeObjectDir,
        kAttrTypeWorldDir,      
        kAttrTypeViewDir,       
        kAttrTypeProjectionDir, 
        kAttrTypeScreenDir,     
        kAttrTypeLastDir = kAttrTypeScreenDir,
        kAttrTypeObjectPos,     
        kAttrTypeFirstPos = kAttrTypeObjectPos,
        kAttrTypeWorldPos,      
        kAttrTypeViewPos,       
        kAttrTypeProjectionPos, 
        kAttrTypeScreenPos,     
        kAttrTypeLastPos = kAttrTypeScreenPos,
        
        
        
        
        kAttrTypeColor3,
        kAttrTypeColor4,
        
        
        
        kAttrTypeMatrix,
        kAttrTypeFirstMatrix = kAttrTypeMatrix,
        kAttrTypeWorldMatrix,
        kAttrTypeViewMatrix,
        kAttrTypeProjectionMatrix,
        kAttrTypeWorldViewMatrix,
        kAttrTypeWorldViewProjectionMatrix,
        kAttrTypeLastMatrix = kAttrTypeWorldViewProjectionMatrix,
        
        
        
        kAttrTypeColor1DTexture,
        kAttrTypeFirstTexture = kAttrTypeColor1DTexture,
        kAttrTypeColor2DTexture,
        kAttrTypeColor3DTexture,
        kAttrTypeColor2DRectTexture,
        kAttrTypeNormalTexture,
        kAttrTypeBumpTexture,
        kAttrTypeCubeTexture,
        kAttrTypeEnvTexture,
        kAttrTypeNormalizationTexture,
        kAttrTypeLastTexture = kAttrTypeNormalizationTexture,
#ifdef _WIN32
        
        kAttrTypeTime,
#endif
        
        kAttrTypeHardwareFogEnabled,
        kAttrTypeHardwareFogMode,
        kAttrTypeHardwareFogStart,
        kAttrTypeHardwareFogEnd,
        kAttrTypeHardwareFogDensity,
        kAttrTypeHardwareFogColor,
        
        
        
        
        kAttrTypeOther,
        
        _kAttrTypeLast
    };
    
    static const char*  typeName( cgfxAttrType eAttrType );
    static const char** compoundAttrSuffixes( cgfxAttrType eAttrType );
    
    
    
    enum cgfxVectorHint
    {
        kVectorHintNone,
        kVectorHintDirLight,
        kVectorHintPointLight,
        kVectorHintSpotLight,
        kVectorHintEye,
        _kVectorHintLast
    };
    
    cgfxAttrType    fType;
    int             fSize;          
    cgfxVectorHint  fHint;
    
    double*         fNumericMin;    
    double*         fNumericMax;
    double*         fNumericSoftMin;
    double*         fNumericSoftMax;
    double*         fNumericDef;    
    CGparameter     fParameterHandle;
    cgfxRCPtr<cgfxTextureCacheEntry> fTexture;
    MCallbackId     fTextureMonitor;
    bool            fInvertMatrix;  
    bool            fTransposeMatrix;
    bool            fTweaked;       
    bool            fInitOnUndo;    
    
private:
    bool            fIsConvertedToInternal;
    
    const static char fSymbol;
    
public:
    
    cgfxAttrDef(CGparameter cgParameter);
    cgfxAttrDef(
        const cgfxAttrType      eAttrType,
    );
    
    ~cgfxAttrDef();
private:
    
    cgfxAttrDef(const cgfxAttrDef&);
    const cgfxAttrDef& operator=(const cgfxAttrDef&);
public:
    
    void            release();
    void            releaseTexture();
    void            releaseCallback();
    
    MString         typeName()
 const { 
return typeName( fType ); }
 
    static cgfxRCPtr<cgfxAttrDefList> attrsFromNode(
MObject& node);
 
    
    static void     updateNode(
        const cgfxRCPtr<const cgfxEffect>& effect,
        cgfxShaderNode*                     pNode, 
        cgfxRCPtr<cgfxAttrDefList>&         attrDefList,
    static void buildAttrDefList(
MObject& node);
 
    static void     initializeAttributes(
        const cgfxRCPtr<cgfxAttrDefList>&   list,
        bool                                bUndoing,
    static void     purgeMObjectCache(const cgfxRCPtr<cgfxAttrDefList>& list);
    static void     validateMObjectCache(
const MObject&   obCgfxShader, 
 
                                         const cgfxRCPtr<cgfxAttrDefList>& list);
    
    static cgfxAttrDef* attrFromNode(
        const cgfxAttrType       eAttrType,
    
    const char*     getExtraAttrSuffix() const;
protected:
    
    
    
    
    
    
    
    
    
    
    void setTextureType(CGparameter param);
    void setSamplerType(CGparameter param);
    void setMatrixType(CGparameter param);
    
    
    
    
    
    
    
    
    
    
    void 
        setVectorType(CGparameter param);
    
    bool            isInitialValueEqual( const cgfxAttrDef& that ) const; 
    
    void            setInitialValue( const cgfxAttrDef& from );
    
    void setAttributeFlags();
public:
    
    
    
    void            getValue( 
MObject& oNode, 
bool& value ) 
const;
 
    void            getValue( 
MObject& oNode, 
int& value ) 
const;
 
    void            getValue( 
MObject& oNode, 
float& value ) 
const;
 
    void            getValue( 
MObject& oNode, 
float& v1, 
float& v2 ) 
const;
 
        float& v1, float& v2, float& v3 ) const;
        float& v1, float& v2, float& v3, float& v4 ) const;
    
    
    
    
    
    
    void            setValue( 
MObject& oNode, 
bool value );
 
    void            setValue( 
MObject& oNode, 
int value );
 
    void            setValue( 
MObject& oNode, 
float value );
 
    void            setValue( 
MObject& oNode, 
float v1, 
float v2 );
 
    void            setValue( 
MObject& oNode, 
float v1, 
float v2, 
float v3 );
 
        float v1, float v2, float v3, float v4 );
    void            setUnitsToInternal(CGparameter& cgParameter);
};
#define VALID(ptr) (ptr == 0 || _CrtIsValidHeapPointer(ptr))
class cgfxAttrDefList
{
protected:
    class element;
    friend class element;
public:
    class iterator;
    friend class iterator;
protected:
    class element
    {
    public:
        element*        prev;
        element*        next;
        cgfxAttrDef*    data;
        element()
            : prev(0)
            , next(0)
            , data(0)
        {  };
        ~element()
        {
#ifdef _WIN32
            _ASSERTE(VALID(prev));
            _ASSERTE(VALID(next));
            _ASSERTE(VALID(data));
#endif
            if (prev)
            {
                prev->next = next;
            }
            if (next)
            {
                next->prev = prev;
            }
            delete data;
        };
    };
    element* head;
    element* tail;
    int refcount;
public:
    class iterator
    {
        friend class cgfxAttrDefList;
    protected:
        element*        item;
    public:
#ifdef _WIN32
        cgfxAttrDef* operator *() { _ASSERTE(VALID(item)); _ASSERTE(VALID(item->data)); return item->data; };
        iterator& operator ++ () { _ASSERTE(VALID(item)); _ASSERTE(VALID(item->next)); item = item->next; return *this; };
#else
        cgfxAttrDef* operator *() { return item->data; };
        iterator& operator ++  () { item = item->next; return *this; };
#endif
        iterator operator ++ (int)
        {
            iterator tmp = *this;
#ifdef _WIN32
            _ASSERTE(VALID(item));
            _ASSERTE(VALID(item->next)); 
#endif
            item = item->next;
            return tmp;
        };
        operator bool() { return (item != 0); };
        iterator(): item(0) {  };
        iterator(cgfxAttrDefList& list): item(list.head)
        {
#ifdef _WIN32
                _ASSERTE(VALID(item));
#endif
        };
        iterator(const cgfxRCPtr<cgfxAttrDefList>& list)
        {
#ifdef _WIN32
            _ASSERTE(VALID(list.operator->()));
            item = list.isNull() ? 0 : list->head;
            _ASSERTE(VALID(item));
#else
            item = list.isNull() ? 0 : list->head;
#endif
        };
        void reset() { item = 0; };
    protected:
        iterator(element* e): item(e) {  };
    };
    cgfxAttrDefList()
        :   head(0)
        ,   tail(0)
        ,   refcount(0)
    {  };
private:
    friend class cgfxRCPtr<cgfxAttrDefList>;
    
    ~cgfxAttrDefList()
    {
        clear();
    };
    void addRef()
    {
        ++refcount;
    };
    void release();
    
    cgfxAttrDefList(const cgfxAttrDefList&);
    const cgfxAttrDefList& operator=(const cgfxAttrDefList&);
public:
    void releaseTextures();
    
    void clear()
    {
#ifdef _WIN32
        _ASSERTE(VALID(head));
#endif
        if (head)
        {
            element *tmp = new element;
            tmp->next = head;
            head->prev = tmp;
            while (tmp->next)
            {
                delete tmp->next;
            }
            delete tmp;
        }
        head = tail = 0;
    };
    bool empty() { return (head == 0); };
    {
        iterator it(*this);
        while (it)
        {
            if ((*it)->fName == name)
            {
                break;
            }
            ++it;
        }
        return it;
    };
    iterator        findInsensitive( 
const MString& name );
    void add(cgfxAttrDef* aDef)
    {
        element * e = new element;
        e->data = aDef;
        if (tail)
        {
            tail->next = e;
            e->prev = tail;
        }
        else
        {
            head = e;
        }
        tail = e;
    }
    iterator begin()
    {
        return iterator(*this);
    };
    void dump(const char* name);
};
#undef VALID
#endif