/* 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_CONTEXT
#define OSGCOMPUTE_CONTEXT 1

#include <limits.h>
#include <vector>
#include <set>
#include <osg/Object>
#include <osg/State>
#include "osgCompute/Export"

namespace osgCompute
{
    class Context;
    class ContextResource;

    typedef std::set< unsigned int >                                           ContextSet;
    typedef std::set< unsigned int >::iterator                                 ContextSetItr;
    typedef std::set< unsigned int >::const_iterator                           ContextSetCnstItr;

    typedef std::vector< ContextResource* >                                    ResourceList;
    typedef std::vector< ContextResource* >::iterator                          ResourceListItr;
    typedef std::vector< ContextResource* >::const_iterator                    ResourceListCnstItr;

    typedef std::map<unsigned int, osg::ref_ptr<Context> >                     ContextMap;
    typedef std::map<unsigned int, osg::ref_ptr<Context> >::iterator           ContextMapItr;
    typedef std::map<unsigned int, osg::ref_ptr<Context> >::const_iterator     ContextMapCnstItr;


    /**
    */
    class LIBRARY_EXPORT ContextResource : public osg::Object
    {
    public:
        ContextResource();

        virtual void clear();

    protected:
        friend class Context;
        virtual ~ContextResource();
        
        virtual void clearLocal();

        virtual bool init( const Context& context ) const;
        virtual void clear( const Context& context ) const;

        mutable ContextSet _contexts;

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


    /**
    */
    class LIBRARY_EXPORT Context : public osg::Object
    {
    public:
        static void registerContext( Context& contextProto );
        static Context* instance( unsigned int id, bool erase = false );
        static Context* instance( osg::State& state, bool erase = false );
        static Context* createInstance( unsigned int id, std::string libraryName, std::string className );
        static Context* createInstance( osg::State& state, std::string libraryName, std::string className );

        virtual bool init();
        virtual void clear();
        virtual void apply();

        inline bool isDirty() const;
        inline unsigned int getId() const;
        inline void setState( osg::State& state );
        inline osg::State* getState();
        inline const osg::State* getState() const;
        inline void removeState();
        inline bool isStateValid() const;

    protected:
        friend class ContextResource;

        Context();
        virtual ~Context();
        inline void clearLocal();
        virtual void clearResources() const;

        inline void setId( unsigned int id );

        virtual bool isRegistered( ContextResource& resource ) const;
        virtual void registerResource( ContextResource& resource ) const;
        virtual void unregisterResource( ContextResource& resource ) const;

        unsigned int                        _id;
        osg::ref_ptr<osg::State>            _state;
        bool                                _dirty;
        mutable OpenThreads::Mutex          _mutex;
        mutable ResourceList                _resources;

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

    /////////////////////////////////////////////////////////////////////////////////////////////////
    // PUBLIC FUNCTIONS /////////////////////////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////////////////////////////////////////////
    //------------------------------------------------------------------------------
    inline void Context::setId( unsigned int id )
    {
        if( !isDirty() )
            return;

        _id = id;
    }

    //------------------------------------------------------------------------------
    inline unsigned int Context::getId() const
    {
        return _id;
    }

    //------------------------------------------------------------------------------
    inline void Context::setState( osg::State& state )
    {
        if( !isDirty() )
            return;

        _state = &state;
    }

    //------------------------------------------------------------------------------
    inline osg::State* Context::getState()
    {
        return _state.get();
    }

    //------------------------------------------------------------------------------
    inline const osg::State* Context::getState() const
    {
        return _state.get();
    }

    //------------------------------------------------------------------------------
    inline void Context::removeState()
    {
        _state = NULL;
    }

    //------------------------------------------------------------------------------
    inline bool Context::isStateValid() const
    {
        return _state.valid();
    }

    //------------------------------------------------------------------------------
    inline bool Context::isDirty() const
    {
        return _dirty;
    }
}

#endif //OSGCOMPUTE_CONTEXT

