/* 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_COMPUTATION
#define OSGCOMPUTE_COMPUTATION 1

#include <map>
#include <osg/Group>
#include "osgCompute/ComputationBin"

namespace osg
{
    class NodeVisitor;
}

namespace osgUtil
{
    class CullVisitor;
}

/**
Helper macro
*/
#define META_Computation( asobject, asnode, ctxlibrary, ctxclass )               \
    virtual osg::Object*                asObject() { return asobject; }                             \
    virtual const osg::Object*          asObject() const { return asobject; }                       \
    virtual osg::Node*                  asNode() { return asnode; }                                 \
    virtual const osg::Node*            asNode() const { return asnode; }                           \
    virtual bool                        isNode() const { return (asnode != NULL); }                 \
    virtual std::string                 contextLibraryName() const { return #ctxlibrary; }          \
    virtual std::string                 contextClassName() const { return #ctxclass; }


namespace osgCompute
{
    /**
    */
    class LIBRARY_EXPORT Computation : public osg::Group
    {
    public: 
        enum ComputeOrder
        {
            PRE_COMPUTE = 0,
            POST_COMPUTE = 1
        };

    public:
        Computation();

        virtual void accept( osg::NodeVisitor& nv );

        virtual osg::Object* asObject() = 0;
        virtual const osg::Object* asObject() const = 0;
        virtual osg::Node* asNode() = 0;
        virtual const osg::Node* asNode() const = 0;
        virtual bool isNode() const = 0;
        virtual std::string contextLibraryName() const = 0;
        virtual std::string contextClassName() const = 0;

        virtual void loadModule( const std::string& modName );
        virtual void addModule( Module& module );
        virtual void removeModule( Module& module );
        virtual void removeModule( const std::string& moduleName );
        virtual bool hasModule( const std::string& moduleName ) const;
        virtual bool hasModule( Module& module ) const;
        virtual bool hasModules() const;
        virtual Module* getModule( const std::string& moduleName );
        virtual const Module* getModule( const std::string& moduleName ) const;
        virtual ModuleList* getModules();
        virtual const ModuleList* getModules() const;
        virtual unsigned int getNumModules() const;

        virtual void addParamHandle( const std::string& handle, osgCompute::Param& param );
        virtual void removeParamHandles( const std::string& handle );
        virtual void removeParamHandle( const osgCompute::Param& param );
        virtual bool hasParamHandle( const std::string& handle ) const;
        virtual HandleToParamMap* getParamHandles();
        virtual const HandleToParamMap* getParamHandles() const;

        inline void setLaunchCallback( LaunchCallback* lc );
        inline LaunchCallback* getLaunchCallback();
        inline const LaunchCallback* getLaunchCallback() const;

        inline void setComputeOrder( ComputeOrder co );
        inline ComputeOrder getComputeOrder();

        inline void enable();
        inline void disable();
        inline bool isEnabled() const;

        virtual void clear();

    protected:
        virtual ~Computation() { clearLocal(); }
        void clearLocal();

        virtual void addBin( osgUtil::CullVisitor& cv );
        virtual void update( osg::NodeVisitor& uv );
        virtual void handleevent( osg::NodeVisitor& ev );
        virtual void checkCallbacks();
        virtual Context* getOrCreateContext( osg::State& state );

        bool                                _enabled;
        LaunchCallback*                     _launchCallback; 
        ModuleList                          _modules;
        HandleToParamMap                    _paramHandles;
        ComputeOrder                        _computeOrder;

        mutable OpenThreads::Mutex          _mutex;

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

    /////////////////////////////////////////////////////////////////////////////////////////////////
    // PUBLIC FUNCTIONS /////////////////////////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////////////////////////////////////////////
    //------------------------------------------------------------------------------
    inline void Computation::setLaunchCallback( LaunchCallback* lc ) 
    { 
        if( lc == _launchCallback )
            return;

        _launchCallback = lc; 
    }

    //------------------------------------------------------------------------------
    inline LaunchCallback* Computation::getLaunchCallback() 
    { 
        return _launchCallback; 
    }

    //------------------------------------------------------------------------------
    inline const LaunchCallback* Computation::getLaunchCallback() const 
    { 
        return _launchCallback; 
    }

    //------------------------------------------------------------------------------
    inline void Computation::setComputeOrder( Computation::ComputeOrder co )
    {
        _computeOrder = co;
    }

    //------------------------------------------------------------------------------
    inline Computation::ComputeOrder Computation::getComputeOrder()
    {
        return _computeOrder;
    }


    //------------------------------------------------------------------------------
    inline void Computation::enable() 
    { 
        _enabled = true; 
    }

    //------------------------------------------------------------------------------
    inline void Computation::disable() 
    { 
        _enabled = false; 
    }

    //------------------------------------------------------------------------------
    inline bool Computation::isEnabled() const
    {
        return _enabled;
    }
}

#endif //OSGCOMPUTE_COMPUTATION
