/* osgCompute - Copyright (C) 2008-2009 SVT Group
 *                                                                     
 * This library is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 3 of
 * the License, or (at your option) any later version.
 *                                                                     
 * 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
 * GNU Lesse General Public License for more details.
 *
 * The full license is in LICENSE file included with this distribution.
*/

#ifndef OSGCOMPUTE_BUFFER
#define OSGCOMPUTE_BUFFER 1

#include <osgCompute/Resource>               
#include <osgCompute/Context>               

namespace osgCompute
{
    class Buffer;

    enum Mapping
    {
        UNMAPPED                       = 0x00000000,
        MAP_HOST                       = 0x00000011,
        MAP_HOST_SOURCE                = 0x00000001,
        MAP_HOST_TARGET                = 0x00000010,
        MAP_DEVICE                     = 0x00110000,
        MAP_DEVICE_SOURCE              = 0x00010000,
        MAP_DEVICE_TARGET              = 0x00100000,
    }; 


    enum ALLOC_HINT
    {
        NO_ALLOC_HINT = 0x0,
        ALLOC_DYNAMIC = 0x1
    };

    /**
    */
    class LIBRARY_EXPORT BufferStream
    {
    public:
        unsigned int                    _mapping;
		osg::ref_ptr<Context>			_context;
        unsigned int                    _allocHint;

        BufferStream();
        virtual ~BufferStream();

    private:
        // not allowed to call copy-constructor or copy-operator
        BufferStream( const BufferStream& ) {}
        BufferStream& operator=( const BufferStream& ) { return *this; }
    };

    /**
    */
    class LIBRARY_EXPORT Buffer : public Resource
    {  
    public:
		Buffer();

		virtual bool init();

        virtual bool setMemory( const Context& context, int value, unsigned int mapping = MAP_DEVICE, unsigned int offset = 0, unsigned int count = UINT_MAX, unsigned int hint = 0 ) const = 0;
        virtual void* map( const Context& context, unsigned int mapping = MAP_DEVICE, unsigned int offset = 0, unsigned int hint = 0 ) const = 0;
		virtual void unmap( const Context& context, unsigned int hint = 0 ) const = 0;
		virtual unsigned int getMapping( const Context& context, unsigned int hint = 0 ) const;

		virtual void setElementSize( unsigned int elementSize );
		virtual unsigned int getElementSize() const;
        virtual unsigned int getByteSize() const;

        virtual void setDimension( unsigned int dimIdx, unsigned int dimSize );
        virtual unsigned int getDimension( unsigned int dimIdx ) const;
        virtual unsigned int getNumDimensions() const;
        virtual unsigned int getNumElements() const;

        virtual void setAllocHint( unsigned int allocHint );
        virtual unsigned int getAllocHint() const;

        virtual void setSubloadCallback( SubloadCallback* sc );
        virtual SubloadCallback* getSubloadCallback();
        virtual const SubloadCallback* getSubloadCallback() const;

		virtual void swap( unsigned int incr = 1 );
		virtual unsigned int getSwapCount() const;

		virtual void init( const Context& context ) const;
		virtual void clear( const Context& context ) const;
        virtual void clear();
	protected:
		virtual ~Buffer();
        void clearLocal();

        virtual BufferStream* newStream( const Context& context ) const;
        virtual BufferStream* lookupStream( const Context& context ) const;

        unsigned int                                    _allocHint;
        std::vector<unsigned int>                       _dimensions;
        unsigned int                                    _numElements;
		unsigned int									_elementSize;
        osg::ref_ptr<SubloadCallback>                   _subloadCallback;

        mutable OpenThreads::Mutex                      _mutex;
        mutable std::vector<BufferStream*>              _streams;

    private:
        // copy constructor and operator should not be called
        Buffer( const Buffer&, const osg::CopyOp& ) {}
        Buffer& operator=( const Buffer& copy ) { return (*this); }
    };
}

#endif //OSGCOMPUTE_BUFFER
