#ifndef _gpuCacheGeometry_h_
#define _gpuCacheGeometry_h_
#include "gpuCacheSample.h"
#include "gpuCacheTimeInterval.h"
#include <maya/MTime.h>
#include <maya/MString.h>
#include <map>
namespace GPUCache {
class SubNode;
class SubNodeVisitor;
class SubNodeData
{
public:
    
    typedef boost::shared_ptr<const SubNodeData> Ptr;
    
    virtual void accept(SubNodeVisitor& visitor,
                        const SubNode&  subNode) const = 0;
    
    
    
    const TimeInterval& animTimeRange() const
    { return fAnimTimeRange; }
    void setAnimTimeRange(const TimeInterval& animTimeRange)
    { fAnimTimeRange = animTimeRange; }
protected:
    
    SubNodeData() : fAnimTimeRange(TimeInterval::kInvalid) {}
    virtual ~SubNodeData() = 0;
    
    TimeInterval fAnimTimeRange;
};
class ShapeData: public SubNodeData
{
public:
    
    
    typedef boost::shared_ptr<const ShapeData> Ptr;
    
    typedef boost::shared_ptr<ShapeData> MPtr;
    typedef std::map<double, boost::shared_ptr<const ShapeSample> > SampleMap;
    
    static MPtr create() {
        return boost::make_shared<ShapeData>();
    }
    
    virtual ~ShapeData();
    const boost::shared_ptr<const ShapeSample>&
    getSample(double seconds) const;
    
    const boost::shared_ptr<const ShapeSample>&
    getSample(
const MTime& time)
 const    {
    }
    
    const SampleMap& getSamples() const { return fSamples; }
    
    void addSample(const boost::shared_ptr<const ShapeSample>& sample);
    virtual void accept(SubNodeVisitor& visitor,
                        const SubNode&  subNode) const;
    
    void setMaterial(
const MString& material);
 
    
    void setMaterials(const std::vector<MString>& materials);
    const std::vector<MString>& getMaterials() const;
protected:
    template<class T> friend void boost::checked_delete(T * x);
    GPUCACHE_DECLARE_MAKE_SHARED_FRIEND_0;
    
    
    
    ShapeData();
    
    ShapeData(const ShapeData&);
    const ShapeData& operator=(const ShapeData&);
    
    SampleMap            fSamples;
    std::vector<MString> fMaterials;
};
class XformData: public SubNodeData
{
public:
    
    
    typedef boost::shared_ptr<const XformData> Ptr;
    
    typedef boost::shared_ptr<XformData> MPtr;
    typedef std::map<double, boost::shared_ptr<const XformSample> > SampleMap;
    
    static MPtr create() {
        return boost::make_shared<XformData>();
    }
    
    virtual ~XformData();
    const boost::shared_ptr<const XformSample>&
    getSample(double seconds) const;
    
    const boost::shared_ptr<const XformSample>&
    getSample(
const MTime& time)
 const    {
    }
    const SampleMap& getSamples() const { return fSamples; }
    void addSample(const boost::shared_ptr<const XformSample>& sample)
    {
        fSamples[sample->timeInSeconds()] = sample;
    }
    virtual void accept(SubNodeVisitor& visitor,
                        const SubNode&  subNode) const;
    
private:
    
    template<class T> friend void boost::checked_delete(T * x);
    GPUCACHE_DECLARE_MAKE_SHARED_FRIEND_0;
    
    
    
    XformData() {}
    
    
    XformData(const XformData&);
    const XformData& operator=(const XformData&);
    
    
    SampleMap fSamples;
};
class SubNodeVisitor
{
public:
        
    virtual void visit(const XformData&   xform,
                       const SubNode&     subNode) = 0;
    virtual void visit(const ShapeData&   shape,
                       const SubNode&     subNode) = 0;
    virtual ~SubNodeVisitor();
};
class SubNode
{
public:
    
    
    typedef boost::shared_ptr<SubNode>       MPtr;
    
    typedef boost::shared_ptr<const SubNode> Ptr;
    
    typedef boost::weak_ptr<const SubNode>   WPtr;
    enum TransparentType {
        kOpaque,
        kTransparent,
        kOpaqueAndTransparent,
        kUnknown
    };
    
    
    static MPtr create(
const MString& name,
 
                       const SubNodeData::Ptr& nodeData) {
        return boost::make_shared<SubNode>(name, nodeData);
    }
    static void connect(const MPtr& parent, const MPtr& child)
    {
        parent->fChildren.push_back(child);
        child->fParents.push_back(parent);
    }
    static void swapNodeData(const MPtr& left, const MPtr& right)
    {
        assert(left);
        assert(right);
        left->fNodeData.swap(right->fNodeData);
        std::swap(left->fTransparentType, right->fTransparentType);
    }
    
    
    ~SubNode();
    const MString& getName()
 const              { 
return fName; }
 
    const SubNodeData::Ptr& getData() const     { return fNodeData; }
    const std::vector<WPtr>& getParents() const { return fParents; }
    const std::vector<Ptr>& getChildren() const { return fChildren;}
    void setName(
const MString& name)           { fName = name; }
 
    
    TransparentType transparentType() const { return fTransparentType; }
    void setTransparentType(const TransparentType transparentType)
    { fTransparentType = transparentType; }
    
    
    void accept(SubNodeVisitor& visitor) const
    { fNodeData->accept(visitor, *this); }
    
private:
    template<class T> friend void boost::checked_delete(T * x);
    GPUCACHE_DECLARE_MAKE_SHARED_FRIEND_2;
    
    
    
    
    SubNode(
        const SubNodeData::Ptr& nodeData);
    
    
    
    SubNodeData::Ptr   fNodeData;
    std::vector<WPtr>  fParents;
    std::vector<Ptr>   fChildren;
    TransparentType    fTransparentType;
};
}
#endif