/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * OpenSceneGraph Public License for more details.
*/

#ifndef OSG_ARRAY
#define OSG_ARRAY 1

#include <osg/MixinVector>

#include <osg/Vec2b>
#include <osg/Vec3b>
#include <osg/Vec4b>
#include <osg/Vec2s>
#include <osg/Vec3s>
#include <osg/Vec4s>
#include <osg/Vec2i>
#include <osg/Vec3i>
#include <osg/Vec4i>
#include <osg/Vec2ub>
#include <osg/Vec3ub>
#include <osg/Vec4ub>
#include <osg/Vec2us>
#include <osg/Vec3us>
#include <osg/Vec4us>
#include <osg/Vec2ui>
#include <osg/Vec3ui>
#include <osg/Vec4ui>
#include <osg/Vec2>
#include <osg/Vec3>
#include <osg/Vec4>
#include <osg/Vec2d>
#include <osg/Vec3d>
#include <osg/Vec4d>
#include <osg/Matrix>
#include <osg/Matrixd>
#include <osg/Quat>

#include <osg/BufferObject>

#include <osg/Object>
#include <osg/GL>

namespace osg {

class ArrayVisitor;
class ConstArrayVisitor;

class ValueVisitor;
class ConstValueVisitor;

class OSG_EXPORT Array : public BufferData
{

    public:

        /// The type of data stored in this array.
        enum Type
        {
            ArrayType = 0,

            ByteArrayType     = 1,
            ShortArrayType    = 2,
            IntArrayType      = 3,

            UByteArrayType    = 4,
            UShortArrayType   = 5,
            UIntArrayType     = 6,

            FloatArrayType    = 7,
            DoubleArrayType   = 8,

            Vec2bArrayType    = 9,
            Vec3bArrayType    = 10,
            Vec4bArrayType    = 11,

            Vec2sArrayType    = 12,
            Vec3sArrayType    = 13,
            Vec4sArrayType    = 14,

            Vec2iArrayType    = 15,
            Vec3iArrayType    = 16,
            Vec4iArrayType    = 17,

            Vec2ubArrayType   = 18,
            Vec3ubArrayType   = 19,
            Vec4ubArrayType   = 20,

            Vec2usArrayType   = 21,
            Vec3usArrayType   = 22,
            Vec4usArrayType   = 23,

            Vec2uiArrayType   = 24,
            Vec3uiArrayType   = 25,
            Vec4uiArrayType   = 26,

            Vec2ArrayType     = 27,
            Vec3ArrayType     = 28,
            Vec4ArrayType     = 29,

            Vec2dArrayType    = 30,
            Vec3dArrayType    = 31,
            Vec4dArrayType    = 32,

            MatrixArrayType   = 33,
            MatrixdArrayType  = 34,

            QuatArrayType     = 35,

            UInt64ArrayType   = 36,
            Int64ArrayType    = 37,

            LastArrayType     = 37
                // If new array types are added, update this and
                // update Array::className() in src/osg/Array.cpp.
                // Array::Type values are from ArrayType to
                // LastArrayType, inclusive.
        };

        /// The scope of applicability of the values in this array
        enum Binding
        {
            BIND_UNDEFINED=-1,
            BIND_OFF=0,
            BIND_OVERALL=1,
            BIND_PER_PRIMITIVE_SET=2,
            BIND_PER_VERTEX=4
        };

        Array(Type arrayType=ArrayType,GLint dataSize=0,GLenum dataType=0, Binding binding=BIND_UNDEFINED):
            _arrayType(arrayType),
            _dataSize(dataSize),
            _dataType(dataType),
            _binding(binding),
            _normalize(false),
            _preserveDataType(false) {}

       Array(const Array& array,const CopyOp& copyop=CopyOp::SHALLOW_COPY):
            BufferData(array,copyop),
            _arrayType(array._arrayType),
            _dataSize(array._dataSize),
            _dataType(array._dataType),
            _binding(array._binding),
            _normalize(array._normalize),
            _preserveDataType(array._preserveDataType) {}

        virtual bool isSameKindAs(const Object* obj) const { return dynamic_cast<const Array*>(obj)!=NULL; }
        virtual const char* libraryName() const { return "osg"; }

        /// Get the class name of this array.  Defined in src/osg/Array.cpp
        /// for all concrete array types listed below --- doesn't use traits.
        virtual const char* className() const;

        virtual void accept(ArrayVisitor&) = 0;
        virtual void accept(ConstArrayVisitor&) const = 0;

        virtual void accept(unsigned int index,ValueVisitor&) = 0;
        virtual void accept(unsigned int index,ConstValueVisitor&) const = 0;

        /** Return -1 if lhs element is less than rhs element, 0 if equal,
          * 1 if lhs element is greater than rhs element. */
        virtual int compare(unsigned int lhs,unsigned int rhs) const = 0;

        Type getType() const { return _arrayType; }
        GLint getDataSize() const { return _dataSize; }
        GLenum getDataType() const { return _dataType; }

        virtual osg::Array* asArray() { return this; }
        virtual const osg::Array* asArray() const { return this; }

        virtual unsigned int getElementSize() const = 0;
        virtual const GLvoid* getDataPointer() const = 0;
        virtual const GLvoid* getDataPointer(unsigned int index) const = 0;
        virtual unsigned int getTotalDataSize() const = 0;
        virtual unsigned int getNumElements() const = 0;
        virtual void reserveArray(unsigned int num) = 0;
        virtual void resizeArray(unsigned int num) = 0;


        /** Specify how this array should be passed to OpenGL.*/
        void setBinding(Binding binding) { _binding = binding; }

        /** Get how this array should be passed to OpenGL.*/
        Binding getBinding() const { return _binding; }


        /** Specify whether the array data should be normalized by OpenGL.*/
        void setNormalize(bool normalize) { _normalize = normalize; }

        /** Get whether the array data should be normalized by OpenGL.*/
        bool getNormalize() const { return _normalize; }


        /** Set hint to ask that the array data is passed via integer or double, or normal setVertexAttribPointer function.*/
        void setPreserveDataType(bool preserve) { _preserveDataType = preserve; }

        /** Get hint to ask that the array data is passed via integer or double, or normal setVertexAttribPointer function.*/
        bool getPreserveDataType() const { return _preserveDataType; }


        /** Frees unused space on this vector - i.e. the difference between size() and max_size() of the underlying vector.*/
        virtual void trim() {}

        /** Set the VertexBufferObject.*/
        inline void setVertexBufferObject(osg::VertexBufferObject* vbo) { setBufferObject(vbo); }

        /** Get the VertexBufferObject. If no VBO is assigned returns NULL*/
        inline osg::VertexBufferObject* getVertexBufferObject() { return dynamic_cast<osg::VertexBufferObject*>(_bufferObject.get()); }

        /** Get the const VertexBufferObject. If no VBO is assigned returns NULL*/
        inline const osg::VertexBufferObject* getVertexBufferObject() const { return dynamic_cast<const osg::VertexBufferObject*>(_bufferObject.get());  }

    protected:

        virtual ~Array() {}

        Type    _arrayType;
        GLint   _dataSize;
        GLenum  _dataType;
        Binding _binding;
        bool    _normalize;
        bool    _preserveDataType;
};

/** convenience function for getting the binding of array via a ptr that may be null.*/
inline osg::Array::Binding getBinding(const osg::Array* array) { return array ? array->getBinding() : osg::Array::BIND_OFF; }

/** convenience function for getting the binding of array via a ptr that may be null.*/
inline bool getNormalize(const osg::Array* array) { return array ? array->getNormalize() : false; }


/// A concrete array holding elements of type T.
template<typename T, Array::Type ARRAYTYPE, int DataSize, int DataType>
class TemplateArray : public Array, public MixinVector<T>
{
    public:

        TemplateArray(Binding binding=BIND_UNDEFINED) : Array(ARRAYTYPE,DataSize,DataType, binding) {}

        TemplateArray(const TemplateArray& ta,const CopyOp& copyop=CopyOp::SHALLOW_COPY):
            Array(ta,copyop),
            MixinVector<T>(ta) {}

        TemplateArray(unsigned int no) :
            Array(ARRAYTYPE,DataSize,DataType),
            MixinVector<T>(no) {}

        TemplateArray(unsigned int no,const T* ptr) :
            Array(ARRAYTYPE,DataSize,DataType),
            MixinVector<T>(ptr,ptr+no) {}

        TemplateArray(Binding binding, unsigned int no) :
            Array(ARRAYTYPE,DataSize,DataType, binding),
            MixinVector<T>(no) {}

        TemplateArray(Binding binding, unsigned int no,const T* ptr) :
            Array(ARRAYTYPE,DataSize,DataType, binding),
            MixinVector<T>(ptr,ptr+no) {}

        template <class InputIterator>
        TemplateArray(InputIterator first,InputIterator last) :
            Array(ARRAYTYPE,DataSize,DataType),
            MixinVector<T>(first,last) {}

        TemplateArray& operator = (const TemplateArray& array)
        {
            if (this==&array) return *this;
            this->assign(array.begin(),array.end());
            return *this;
        }

        virtual Object* cloneType() const { return new TemplateArray(); }
        virtual Object* clone(const CopyOp& copyop) const { return new TemplateArray(*this,copyop); }

        inline virtual void accept(ArrayVisitor& av);
        inline virtual void accept(ConstArrayVisitor& av) const;

        inline virtual void accept(unsigned int index,ValueVisitor& vv);
        inline virtual void accept(unsigned int index,ConstValueVisitor& vv) const;

        virtual int compare(unsigned int lhs,unsigned int rhs) const
        {
            const T& elem_lhs = (*this)[lhs];
            const T& elem_rhs = (*this)[rhs];
            if (elem_lhs<elem_rhs) return -1;
            if (elem_rhs<elem_lhs) return 1;
            return 0;
        }

        /** Frees unused space on this vector - i.e. the difference between size() and max_size() of the underlying vector.*/
        virtual void trim()
        {
            MixinVector<T>( *this ).swap( *this );
        }

        virtual unsigned int    getElementSize() const { return sizeof(ElementDataType); }
        virtual const GLvoid*   getDataPointer() const { if (!this->empty()) return &this->front(); else return 0; }
        virtual const GLvoid*   getDataPointer(unsigned int index) const { if (!this->empty()) return &((*this)[index]); else return 0; }
        virtual unsigned int    getTotalDataSize() const { return static_cast<unsigned int>(this->size()*sizeof(ElementDataType)); }
        virtual unsigned int    getNumElements() const { return static_cast<unsigned int>(this->size()); }
        virtual void reserveArray(unsigned int num) { this->reserve(num); }
        virtual void resizeArray(unsigned int num) { this->resize(num); }

        typedef T ElementDataType; // expose T

    protected:

        virtual ~TemplateArray() {}
};

class OSG_EXPORT IndexArray : public Array
{

    public:

        IndexArray(Type arrayType=ArrayType,GLint dataSize=0,GLenum dataType=0):
            Array(arrayType,dataSize,dataType) {}

        IndexArray(const Array& array,const CopyOp& copyop=CopyOp::SHALLOW_COPY):
            Array(array,copyop) {}

        virtual bool isSameKindAs(const Object* obj) const { return dynamic_cast<const IndexArray*>(obj)!=NULL; }

        virtual unsigned int index(unsigned int pos) const = 0;

    protected:

        virtual ~IndexArray() {}
};

template<typename T, Array::Type ARRAYTYPE, int DataSize, int DataType>
class TemplateIndexArray : public IndexArray, public MixinVector<T>
{
    public:

        TemplateIndexArray() : IndexArray(ARRAYTYPE,DataSize,DataType) {}

        TemplateIndexArray(const TemplateIndexArray& ta,const CopyOp& copyop=CopyOp::SHALLOW_COPY):
            IndexArray(ta,copyop),
            MixinVector<T>(ta) {}

        TemplateIndexArray(unsigned int no) :
            IndexArray(ARRAYTYPE,DataSize,DataType),
            MixinVector<T>(no) {}

        TemplateIndexArray(unsigned int no,T* ptr) :
            IndexArray(ARRAYTYPE,DataSize,DataType),
            MixinVector<T>(ptr,ptr+no) {}

        template <class InputIterator>
        TemplateIndexArray(InputIterator first,InputIterator last) :
            IndexArray(ARRAYTYPE,DataSize,DataType),
            MixinVector<T>(first,last) {}

        TemplateIndexArray& operator = (const TemplateIndexArray& array)
        {
            if (this==&array) return *this;
            this->assign(array.begin(),array.end());
            return *this;
        }

        virtual Object* cloneType() const { return new TemplateIndexArray(); }
        virtual Object* clone(const CopyOp& copyop) const { return new TemplateIndexArray(*this,copyop); }

        inline virtual void accept(ArrayVisitor& av);
        inline virtual void accept(ConstArrayVisitor& av) const;

        inline virtual void accept(unsigned int index,ValueVisitor& vv);
        inline virtual void accept(unsigned int index,ConstValueVisitor& vv) const;

        virtual int compare(unsigned int lhs,unsigned int rhs) const
        {
            const T& elem_lhs = (*this)[lhs];
            const T& elem_rhs = (*this)[rhs];
            if (elem_lhs<elem_rhs) return -1;
            if (elem_rhs<elem_lhs) return 1;
            return 0;
        }

        /** Frees unused space on this vector - i.e. the difference between size() and max_size() of the underlying vector.*/
        virtual void trim()
        {
            MixinVector<T>( *this ).swap( *this );
        }

        virtual unsigned int getElementSize() const { return sizeof(ElementDataType); }
        virtual const GLvoid*   getDataPointer() const { if (!this->empty()) return &this->front(); else return 0; }
        virtual const GLvoid*   getDataPointer(unsigned int index) const { if (!this->empty()) return &((*this)[index]); else return 0; }
        virtual unsigned int    getTotalDataSize() const { return static_cast<unsigned int>(this->size()*sizeof(T)); }
        virtual unsigned int    getNumElements() const { return static_cast<unsigned int>(this->size()); }
        virtual void reserveArray(unsigned int num) { this->reserve(num); }
        virtual void resizeArray(unsigned int num) { this->resize(num); }

        virtual unsigned int    index(unsigned int pos) const { return (*this)[pos]; }

        typedef T ElementDataType; // expose T

    protected:

        virtual ~TemplateIndexArray() {}
};

// The predefined array types

typedef TemplateIndexArray<GLbyte,Array::ByteArrayType,1,GL_BYTE>               ByteArray;
typedef TemplateIndexArray<GLshort,Array::ShortArrayType,1,GL_SHORT>            ShortArray;
typedef TemplateIndexArray<GLint,Array::IntArrayType,1,GL_INT>                  IntArray;

typedef TemplateIndexArray<GLubyte,Array::UByteArrayType,1,GL_UNSIGNED_BYTE>    UByteArray;
typedef TemplateIndexArray<GLushort,Array::UShortArrayType,1,GL_UNSIGNED_SHORT> UShortArray;
typedef TemplateIndexArray<GLuint,Array::UIntArrayType,1,GL_UNSIGNED_INT>       UIntArray;

typedef TemplateArray<GLfloat,Array::FloatArrayType,1,GL_FLOAT>                 FloatArray;
typedef TemplateArray<GLdouble,Array::DoubleArrayType,1,GL_DOUBLE>              DoubleArray;

typedef TemplateArray<Vec2b,Array::Vec2bArrayType,2,GL_BYTE>                    Vec2bArray;
typedef TemplateArray<Vec3b,Array::Vec3bArrayType,3,GL_BYTE>                    Vec3bArray;
typedef TemplateArray<Vec4b,Array::Vec4bArrayType,4,GL_BYTE>                    Vec4bArray;

typedef TemplateArray<Vec2s,Array::Vec2sArrayType,2,GL_SHORT>                   Vec2sArray;
typedef TemplateArray<Vec3s,Array::Vec3sArrayType,3,GL_SHORT>                   Vec3sArray;
typedef TemplateArray<Vec4s,Array::Vec4sArrayType,4,GL_SHORT>                   Vec4sArray;

typedef TemplateArray<Vec2i,Array::Vec2iArrayType,2,GL_INT>                     Vec2iArray;
typedef TemplateArray<Vec3i,Array::Vec3iArrayType,3,GL_INT>                     Vec3iArray;
typedef TemplateArray<Vec4i,Array::Vec4iArrayType,4,GL_INT>                     Vec4iArray;

typedef TemplateArray<Vec2ub,Array::Vec2ubArrayType,2,GL_UNSIGNED_BYTE>         Vec2ubArray;
typedef TemplateArray<Vec3ub,Array::Vec3ubArrayType,3,GL_UNSIGNED_BYTE>         Vec3ubArray;
typedef TemplateArray<Vec4ub,Array::Vec4ubArrayType,4,GL_UNSIGNED_BYTE>         Vec4ubArray;

typedef TemplateArray<Vec2us,Array::Vec2usArrayType,2,GL_UNSIGNED_SHORT>        Vec2usArray;
typedef TemplateArray<Vec3us,Array::Vec3usArrayType,3,GL_UNSIGNED_SHORT>        Vec3usArray;
typedef TemplateArray<Vec4us,Array::Vec4usArrayType,4,GL_UNSIGNED_SHORT>        Vec4usArray;

typedef TemplateArray<Vec2ui,Array::Vec2uiArrayType,2,GL_UNSIGNED_INT>          Vec2uiArray;
typedef TemplateArray<Vec3ui,Array::Vec3uiArrayType,3,GL_UNSIGNED_INT>          Vec3uiArray;
typedef TemplateArray<Vec4ui,Array::Vec4uiArrayType,4,GL_UNSIGNED_INT>          Vec4uiArray;

typedef TemplateArray<Vec2,Array::Vec2ArrayType,2,GL_FLOAT>                     Vec2Array;
typedef TemplateArray<Vec3,Array::Vec3ArrayType,3,GL_FLOAT>                     Vec3Array;
typedef TemplateArray<Vec4,Array::Vec4ArrayType,4,GL_FLOAT>                     Vec4Array;

typedef TemplateArray<Vec2d,Array::Vec2dArrayType,2,GL_DOUBLE>                  Vec2dArray;
typedef TemplateArray<Vec3d,Array::Vec3dArrayType,3,GL_DOUBLE>                  Vec3dArray;
typedef TemplateArray<Vec4d,Array::Vec4dArrayType,4,GL_DOUBLE>                  Vec4dArray;

typedef TemplateArray<Matrixf,Array::MatrixArrayType,16,GL_FLOAT>               MatrixfArray;
typedef TemplateArray<Matrixd,Array::MatrixdArrayType,16,GL_DOUBLE>             MatrixdArray;

typedef TemplateArray<Quat,Array::QuatArrayType,4,GL_DOUBLE>                    QuatArray;

typedef TemplateIndexArray<GLuint64,Array::UInt64ArrayType,1,GL_UNSIGNED_INT64_ARB> UInt64Array;
typedef TemplateIndexArray<GLint64,Array::Int64ArrayType,1,GL_INT64_ARB>            Int64Array;

class ArrayVisitor
{
    public:
        ArrayVisitor() {}
        virtual ~ArrayVisitor() {}

        virtual void apply(Array&) {}

        virtual void apply(ByteArray&) {}
        virtual void apply(ShortArray&) {}
        virtual void apply(IntArray&) {}

        virtual void apply(UByteArray&) {}
        virtual void apply(UShortArray&) {}
        virtual void apply(UIntArray&) {}

        virtual void apply(FloatArray&) {}
        virtual void apply(DoubleArray&) {}


        virtual void apply(Vec2bArray&) {}
        virtual void apply(Vec3bArray&) {}
        virtual void apply(Vec4bArray&) {}

        virtual void apply(Vec2sArray&) {}
        virtual void apply(Vec3sArray&) {}
        virtual void apply(Vec4sArray&) {}

        virtual void apply(Vec2iArray&) {}
        virtual void apply(Vec3iArray&) {}
        virtual void apply(Vec4iArray&) {}

        virtual void apply(Vec2ubArray&) {}
        virtual void apply(Vec3ubArray&) {}
        virtual void apply(Vec4ubArray&) {}

        virtual void apply(Vec2usArray&) {}
        virtual void apply(Vec3usArray&) {}
        virtual void apply(Vec4usArray&) {}

        virtual void apply(Vec2uiArray&) {}
        virtual void apply(Vec3uiArray&) {}
        virtual void apply(Vec4uiArray&) {}

        virtual void apply(Vec2Array&) {}
        virtual void apply(Vec3Array&) {}
        virtual void apply(Vec4Array&) {}

        virtual void apply(Vec2dArray&) {}
        virtual void apply(Vec3dArray&) {}
        virtual void apply(Vec4dArray&) {}

        virtual void apply(MatrixfArray&) {}
        virtual void apply(MatrixdArray&) {}

        virtual void apply(UInt64Array&) {}
        virtual void apply(Int64Array&)  {}
};

class ConstArrayVisitor
{
    public:
        ConstArrayVisitor() {}
        virtual ~ConstArrayVisitor() {}

        virtual void apply(const Array&) {}

        virtual void apply(const ByteArray&) {}
        virtual void apply(const ShortArray&) {}
        virtual void apply(const IntArray&) {}

        virtual void apply(const UByteArray&) {}
        virtual void apply(const UShortArray&) {}
        virtual void apply(const UIntArray&) {}

        virtual void apply(const FloatArray&) {}
        virtual void apply(const DoubleArray&) {}


        virtual void apply(const Vec2bArray&) {}
        virtual void apply(const Vec3bArray&) {}
        virtual void apply(const Vec4bArray&) {}

        virtual void apply(const Vec2sArray&) {}
        virtual void apply(const Vec3sArray&) {}
        virtual void apply(const Vec4sArray&) {}

        virtual void apply(const Vec2iArray&) {}
        virtual void apply(const Vec3iArray&) {}
        virtual void apply(const Vec4iArray&) {}

        virtual void apply(const Vec2ubArray&) {}
        virtual void apply(const Vec3ubArray&) {}
        virtual void apply(const Vec4ubArray&) {}

        virtual void apply(const Vec2usArray&) {}
        virtual void apply(const Vec3usArray&) {}
        virtual void apply(const Vec4usArray&) {}

        virtual void apply(const Vec2uiArray&) {}
        virtual void apply(const Vec3uiArray&) {}
        virtual void apply(const Vec4uiArray&) {}

        virtual void apply(const Vec2Array&) {}
        virtual void apply(const Vec3Array&) {}
        virtual void apply(const Vec4Array&) {}

        virtual void apply(const Vec2dArray&) {}
        virtual void apply(const Vec3dArray&) {}
        virtual void apply(const Vec4dArray&) {}

        virtual void apply(const MatrixfArray&) {}
        virtual void apply(const MatrixdArray&) {}

        virtual void apply(const UInt64Array&) {}
        virtual void apply(const Int64Array&)  {}
};


class ValueVisitor
{
    public:
        ValueVisitor() {}
        virtual ~ValueVisitor() {}

        virtual void apply(GLbyte&) {}
        virtual void apply(GLshort&) {}
        virtual void apply(GLint&) {}

        virtual void apply(GLushort&) {}
        virtual void apply(GLubyte&) {}
        virtual void apply(GLuint&) {}

        virtual void apply(GLfloat&) {}
        virtual void apply(GLdouble&) {}


        virtual void apply(Vec2b&) {}
        virtual void apply(Vec3b&) {}
        virtual void apply(Vec4b&) {}

        virtual void apply(Vec2s&) {}
        virtual void apply(Vec3s&) {}
        virtual void apply(Vec4s&) {}

        virtual void apply(Vec2i&) {}
        virtual void apply(Vec3i&) {}
        virtual void apply(Vec4i&) {}

        virtual void apply(Vec2ub&) {}
        virtual void apply(Vec3ub&) {}
        virtual void apply(Vec4ub&) {}

        virtual void apply(Vec2us&) {}
        virtual void apply(Vec3us&) {}
        virtual void apply(Vec4us&) {}

        virtual void apply(Vec2ui&) {}
        virtual void apply(Vec3ui&) {}
        virtual void apply(Vec4ui&) {}

        virtual void apply(Vec2&) {}
        virtual void apply(Vec3&) {}
        virtual void apply(Vec4&) {}

        virtual void apply(Vec2d&) {}
        virtual void apply(Vec3d&) {}
        virtual void apply(Vec4d&) {}

        virtual void apply(Matrixf&) {}
        virtual void apply(Matrixd&) {}

        virtual void apply(Quat&) {}

        virtual void apply(GLuint64&){}
        virtual void apply(GLint64&){}
};

class ConstValueVisitor
{
    public:
        ConstValueVisitor() {}
        virtual ~ConstValueVisitor() {}

        virtual void apply(const GLbyte&) {}
        virtual void apply(const GLshort&) {}
        virtual void apply(const GLint&) {}

        virtual void apply(const GLushort&) {}
        virtual void apply(const GLubyte&) {}
        virtual void apply(const GLuint&) {}

        virtual void apply(const GLfloat&) {}
        virtual void apply(const GLdouble&) {}


        virtual void apply(const Vec2b&) {}
        virtual void apply(const Vec3b&) {}
        virtual void apply(const Vec4b&) {}

        virtual void apply(const Vec2s&) {}
        virtual void apply(const Vec3s&) {}
        virtual void apply(const Vec4s&) {}

        virtual void apply(const Vec2i&) {}
        virtual void apply(const Vec3i&) {}
        virtual void apply(const Vec4i&) {}

        virtual void apply(const Vec2ub&) {}
        virtual void apply(const Vec3ub&) {}
        virtual void apply(const Vec4ub&) {}

        virtual void apply(const Vec2us&) {}
        virtual void apply(const Vec3us&) {}
        virtual void apply(const Vec4us&) {}

        virtual void apply(const Vec2ui&) {}
        virtual void apply(const Vec3ui&) {}
        virtual void apply(const Vec4ui&) {}

        virtual void apply(const Vec2&) {}
        virtual void apply(const Vec3&) {}
        virtual void apply(const Vec4&) {}

        virtual void apply(const Vec2d&) {}
        virtual void apply(const Vec3d&) {}
        virtual void apply(const Vec4d&) {}

        virtual void apply(const Matrixf&) {}
        virtual void apply(const Matrixd&) {}

        virtual void apply(const Quat&) {}

        virtual void apply(const GLuint64&){}
        virtual void apply(const GLint64&){}
};

template<typename T, Array::Type ARRAYTYPE, int DataSize, int DataType>
inline void TemplateArray<T,ARRAYTYPE,DataSize,DataType>::accept(ArrayVisitor& av) { av.apply(*this); }

template<typename T, Array::Type ARRAYTYPE, int DataSize, int DataType>
inline void TemplateArray<T,ARRAYTYPE,DataSize,DataType>::accept(ConstArrayVisitor& av) const { av.apply(*this); }

template<typename T, Array::Type ARRAYTYPE, int DataSize, int DataType>
inline void TemplateArray<T,ARRAYTYPE,DataSize,DataType>::accept(unsigned int index,ValueVisitor& vv) { vv.apply( (*this)[index] ); }

template<typename T, Array::Type ARRAYTYPE, int DataSize, int DataType>
inline void TemplateArray<T,ARRAYTYPE,DataSize,DataType>::accept(unsigned int index,ConstValueVisitor& vv) const {  vv.apply( (*this)[index] );}

template<typename T, Array::Type ARRAYTYPE, int DataSize, int DataType>
inline void TemplateIndexArray<T,ARRAYTYPE,DataSize,DataType>::accept(ArrayVisitor& av) { av.apply(*this); }

template<typename T, Array::Type ARRAYTYPE, int DataSize, int DataType>
inline void TemplateIndexArray<T,ARRAYTYPE,DataSize,DataType>::accept(ConstArrayVisitor& av) const { av.apply(*this); }

template<typename T, Array::Type ARRAYTYPE, int DataSize, int DataType>
inline void TemplateIndexArray<T,ARRAYTYPE,DataSize,DataType>::accept(unsigned int index,ValueVisitor& vv) { vv.apply( (*this)[index] ); }

template<typename T, Array::Type ARRAYTYPE, int DataSize, int DataType>
inline void TemplateIndexArray<T,ARRAYTYPE,DataSize,DataType>::accept(unsigned int index,ConstValueVisitor& vv) const {  vv.apply( (*this)[index] );}

}

#endif