/* 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_PARAM
#define OSGCOMPUTE_PARAM 1

#include <vector>
#include <map>
#include <osg/ref_ptr>
#include <osg/Object>
#include <osgCompute/Export>
#include <osgCompute/Context>
#include <osgCompute/Callback>

namespace osgCompute
{
    class Module;

#define META_Resource( libraryname, classname, asModuleType )                   \
    META_Object( libraryname, classname )                                       \
    virtual osg::Object* asObject() { return this; }                            \
    virtual const osg::Object* asObject() const { return this; }                \
    virtual osgCompute::Module* asModule() { return (asModuleType); }           \
    virtual const osgCompute::Module* asModule() const { return (asModuleType); }

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

        virtual osg::Object* asObject() = 0;
        virtual const osg::Object* asObject() const = 0;
        virtual Module* asModule() { return NULL; }
        virtual const Module* asModule() const { return NULL; }

        virtual bool init();

        inline void setUpdateResourceCallback( ResourceCallback* uc );
        inline ResourceCallback* getUpdateResourceCallback();
        inline const ResourceCallback* getUpdateResourceCallback() const;
        inline void setEventResourceCallback( ResourceCallback* ec );
        inline ResourceCallback* getEventResourceCallback();
        inline const ResourceCallback* getEventResourceCallback() const;

        inline void addHandle( const std::string& handle );
        inline void removeHandle( const std::string& handle );
        inline bool isAddressedByHandle( const std::string& handle );

        inline bool isClear() const;
        virtual void clear();

    protected:
        friend class Context;
        virtual ~Resource();

        virtual void clearLocal();

        virtual bool init( const Context& context ) const;
        virtual void clear( const Context& context ) const;
        virtual const Context* getContext( unsigned int ctxId ) const;

        mutable ContextSet                  _contexts;

        osg::ref_ptr<ResourceCallback>      _updateCallback;
        osg::ref_ptr<ResourceCallback>      _eventCallback;
        HandleSet                           _handles;
        bool                                _clear;

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

    /////////////////////////////////////////////////////////////////////////////////////////////////
    // PUBLIC FUNCTIONS /////////////////////////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////////////////////////////////////////////
    //------------------------------------------------------------------------------
    inline void Resource::setUpdateResourceCallback( ResourceCallback* uc ) 
    { 
        _updateCallback = uc; 
    }

    //------------------------------------------------------------------------------
    inline ResourceCallback* Resource::getUpdateResourceCallback() 
    { 
        return _updateCallback.get(); 
    }

    //------------------------------------------------------------------------------
    inline const ResourceCallback* Resource::getUpdateResourceCallback() const 
    { 
        return _updateCallback.get(); 
    }

    //------------------------------------------------------------------------------
    inline void Resource::setEventResourceCallback( ResourceCallback* ec ) 
    { 
        _eventCallback = ec; 
    }

    //------------------------------------------------------------------------------
    inline ResourceCallback* Resource::getEventResourceCallback() 
    { 
        return _eventCallback.get(); 
    }

    //------------------------------------------------------------------------------
    inline const ResourceCallback* Resource::getEventResourceCallback() const 
    { 
        return _eventCallback.get(); 
    }

    //------------------------------------------------------------------------------
    inline void Resource::addHandle( const std::string& handle )
    {
        if( !isAddressedByHandle(handle) )
            _handles.insert( handle ); 
    }

    //------------------------------------------------------------------------------
    inline void Resource::removeHandle( const std::string& handle )
    {
        HandleSetItr itr = _handles.find( handle ); 
        if( itr != _handles.end() )
            _handles.erase( itr );
    }

    //------------------------------------------------------------------------------
    inline bool Resource::isAddressedByHandle( const std::string& handle )
    {
        HandleSetItr itr = _handles.find( handle ); 
        if( itr == _handles.end() )
            return false;

        return true;
    }

    //------------------------------------------------------------------------------
    inline bool Resource::isClear() const 
    { 
        return _clear; 
    }
}

#endif //OSGCOMPUTE_PARAM
