namespace mudbox
{    
    // Useful typedefs 
    typedef double float64;
    typedef float float32; 
    typedef half_ float16;
    typedef long long int64;
    typedef unsigned int uint32;
    typedef int int32;
    typedef unsigned short uint16;
    typedef short int16;
    typedef unsigned char uint8;
    typedef char int8;
    typedef unsigned int uint;

    // Used to assure one global instance of a plugin
    // This is one global instance of the plugin. This is needed because Mudbox will check all the nodes in the 
    // memory and check their types. If the node type is Importer (like in this case) Mudbox will know
    // that this node can be used to import a specific file type, in this case the PLY format.
    template<typename T>
    class Singleton {
    public:
        static T instance;
    };

    // Provides common functionality for exporters. Primarily it is responsible for 
    // caching the mesh pointers provided by Mudbox
    class BaseExporter : public Exporter
    {
        std::vector<const Mesh*> meshes;

    public:

        BaseExporter() { }
        virtual ~BaseExporter() { }

	    // By calling this function, the mudbox kernel will inform the exporter plugin how many meshes it has to 
	    // put into the file.
	    virtual void SetMeshCount( unsigned int iMeshCount )
        {
            meshes.resize(iMeshCount);
        }
    	
        // This function will be called once for each mesh, to tell the plugin what to export. The plugin don't have to
	    // make a copy of the mesh data, it can store the pointer only, and then extract the required data from the mesh
	    // during the Export() call.
	    virtual void SetMesh( unsigned int iIndex, const Mesh *pMesh )
        {
            if (iIndex > meshes.size())
                MB_ERROR("Internal error, index of mesh out of range for exporter");
            meshes[iIndex] = pMesh;
        }

    protected:
        
        uint GetNumMeshes() {
            return static_cast<uint>(meshes.size());
        }

        const Mesh* GetMesh(uint n) {
            return meshes[n];
        }
    };

    // Utility functions for reading and writing sized values to a stream.
    #pragma region 
    template<typename Stream_T>
    void WriteFloat32(Stream_T& str, float32 f) {
        assert(sizeof(f) == 4);
        str.write((char*)&f, sizeof(f));
    }

    template<typename Stream_T>
    void WriteUInt32(Stream_T& str, uint32 n) {
        assert(sizeof(n) == 4);
        str.write((char*)&n, sizeof(n));
    }

    template<typename Stream_T>
    void WriteUInt16(Stream_T& str, uint16 n) {
        assert(sizeof(n) == 2);
        str.write((char*)&n, sizeof(n));
    }

    template<typename Stream_T>
    void WriteVectorFloat32(Stream_T& str, const Vector& v) {
        WriteFloat32(str, v.x);
        WriteFloat32(str, v.y);
        WriteFloat32(str, v.z);        
    }

    template<typename Stream_T>
    float32 ReadFloat32(Stream_T& str) {
        float32 r;
        assert(sizeof(r) == 4);
        str.read((char*)&r, sizeof(r));
        return r;
    }

    template<typename Stream_T>
    uint32 ReadUInt32(Stream_T& str) {
        uint32 r;
        assert(sizeof(r) == 4);
        str.read((char*)&r, sizeof(r));
        return r;
    }

    template<typename Stream_T>
    uint16 ReadUInt16(Stream_T& str) {
        uint16 r;
        assert(sizeof(r) == 2);
        str.read((char*)&r, sizeof(r));
        return r;
    }

    template<typename Stream_T>
    Vector ReadVectorFloat32(Stream_T& str) {
        Vector v;
        v.x = ReadFloat32(str, v.x);
        v.y = ReadFloat32(str, v.y);
        v.z = ReadFloat32(str, v.z);
        return v;
    }
    #pragma endregion

    // Mesh utility functions
    bool IsMeshOpen(const Mesh* m) {
        switch (m->Type())
        {
        case Mesh::typeTriangular:
            for ( uint i = 0; i < m->FaceCount(); ++i )
                for ( uint j = 0; j < 3; j++ )
                    if ( !m->HasAdjacentTriangle( i, j ) )
                        return true;
            return false;
        case Mesh::typeQuadric:
            for ( uint i = 0; i < m->FaceCount(); ++i )
                for ( uint j = 0; j < 4; j++ )
                    if ( !m->HasAdjacentQuad( i, j ) )
                        return true;
            return false;
        
        default:
            MB_ERROR("Unexpected internal condition");
            return false;
        }
    }
}

