#ifndef _CacheWriter_h_
#define _CacheWriter_h_
#include "gpuCacheGeometry.h"
#include "gpuCacheMaterial.h"
#include <maya/MMatrix.h>
#include <maya/MFnTransform.h>
#include <maya/MTime.h>
#include <maya/MString.h>
#include <maya/MFileObject.h>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <vector>
class CacheXformSampler;
class CacheMeshSampler;
class CacheWriter
{
public:
    
    static boost::shared_ptr<CacheWriter> create(
const MString& impl,
 
    
    typedef boost::shared_ptr<CacheWriter> CreateFunction(
const MFileObject& file,
 
        char compressLevel, 
const MString& dataFormat);
 
    static void registerWriter(
const MString& impl, CreateFunction func);
 
    virtual ~CacheWriter() {}
    virtual bool valid() const = 0;
    
    
    virtual void writeSubNodeHierarchy(
        const GPUCache::SubNode::Ptr& topNode, 
        double secondsPerSample, double startTimeInSeconds) = 0;
    
    virtual void writeMaterials(
        const GPUCache::MaterialGraphMap::Ptr& materialGraphMap,
        double secondsPerSample, double startTimeInSeconds) = 0;
    
protected:
    CacheWriter() {}
private:
    
    CacheWriter(const CacheWriter&);
    const CacheWriter& operator=(const CacheWriter&);
    static std::map<std::string,void*> fsRegistry;
};
class CacheXformSampler
{
public:
    static boost::shared_ptr<CacheXformSampler> create(
const MObject& xformObject);
 
    ~CacheXformSampler();
    
    void addSample();
    bool isAnimated() const {
        return fXformAnimated || fVisibilityAnimated; }
    boost::shared_ptr<const GPUCache::XformSample> getSample(double timeInSeconds);
private:
    CacheXformSampler(
const MObject& xformObject);
    GPUCACHE_DECLARE_MAKE_SHARED_FRIEND_1;
    
    bool            fIsFirstSample;
    
    
    bool            fXformAnimated;
    
    bool            fVisibilitySample;
    bool            fVisibilityAnimated;
};
class CacheMeshSampler
{
public:
    
    static boost::shared_ptr<CacheMeshSampler> create(bool needUVs);
    ~CacheMeshSampler();
    bool addSample(
MObject meshObject, 
bool visibility);
 
    bool addSampleFromMesh(
MFnMesh& mesh);
 
    bool isAnimated() const 
    {
        return fIsAnimated;
    }
    void enableUVs() 
    {
        fNeedUVs = true;
    }
    void setUseBaseTessellation()
    {
        fUseBaseTessellation = true;
    }
    
    
    
    boost::shared_ptr<const GPUCache::ShapeSample>
        getSample(
double timeInSeconds, 
const MColor& diffuseColor);
    
private:
    CacheMeshSampler(bool needUVs);
    GPUCACHE_DECLARE_MAKE_SHARED_FRIEND_1;
    struct AttributeSet
    {
        size_t fNumWires;
        size_t fNumTriangles;
        size_t fNumVerts;
        boost::shared_ptr<GPUCache::IndexBuffer>    fWireVertIndices;
        std::vector<boost::shared_ptr<GPUCache::IndexBuffer> > fTriangleVertIndices;
        boost::shared_ptr<GPUCache::VertexBuffer>   fPositions;
        boost::shared_ptr<GPUCache::VertexBuffer>   fNormals;
        boost::shared_ptr<GPUCache::VertexBuffer>   fUVs;
        bool                                        fVisibility;
        AttributeSet() 
            : fNumWires(0), fNumTriangles(0), fNumVerts(0), fVisibility(true)
        {}
        AttributeSet(
            MObject meshObject, 
bool visibility, 
bool needUVs);
 
        AttributeSet(
MFnMesh& mesh, 
bool needUVs, 
bool useBaseTessellation);
        
        
        
        bool updateAnimatedChannels(
            bool& animated, const AttributeSet& newer);
    };
    bool fNeedUVs;
    bool fUseBaseTessellation;
    bool fIsAnimated;
    AttributeSet fAttributeSet;
};
#endif