/* 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 Resource;

    typedef std::set< const Context* >                                         ContextSet;
    typedef std::set< const Context* >::iterator                               ContextSetItr;
    typedef std::set< const Context* >::const_iterator                         ContextSetCnstItr;

    typedef std::map< Resource*, osg::ref_ptr<osg::Object> >                   ResourceMap;
    typedef std::map< Resource*, osg::ref_ptr<osg::Object> >::iterator         ResourceMapItr;
    typedef std::map< Resource*, osg::ref_ptr<osg::Object> >::const_iterator   ResourceMapCnstItr;

    typedef std::set< Resource* >                                              ResourceSet;
    typedef std::set< Resource* >::iterator                                    ResourceSetItr;
    typedef std::set< Resource* >::const_iterator                              ResourceSetCnstItr;

    typedef std::vector< Resource* >                                           ResourceList;
    typedef std::vector< Resource* >::iterator                                 ResourceListItr;
    typedef std::vector< Resource* >::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;

    typedef std::set< std::string >                                            HandleSet;
    typedef std::set< std::string >::iterator                                  HandleSetItr;
    typedef std::set< std::string >::const_iterator                            HandleSetCnstItr;

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

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

        inline bool isClear() const;
        inline void setId( unsigned int id );
        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;
        inline void setDevice( int device );
        inline int getDevice() const;

    protected:
        friend class Resource;

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

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

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

    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( !isClear() )
            return;

        _id = id;
    }

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

    //------------------------------------------------------------------------------
    inline void Context::setState( osg::State& state )
    {
        if( !isClear() )
            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 void Context::setDevice( int device )
    { 
        _device = device;  
    }

    //------------------------------------------------------------------------------
    inline int Context::getDevice() const 
    { 
        return _device; 
    }

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

#endif //OSGCOMPUTE_CONTEXT

