#ifndef OPENMW_COMPONENTS_SCENEUTIL_LIGHTMANAGER_H
#define OPENMW_COMPONENTS_SCENEUTIL_LIGHTMANAGER_H

#include <osg/Light>

#include <osg/Group>
#include <osg/NodeVisitor>

namespace SceneUtil
{

    // This mask should be included in the Cull and Update visitor's traversal mask if lighting is desired.
    const int Mask_Lit = (1<<16);

    /// LightSource managed by a LightManager.
    class LightSource : public osg::Node
    {
        osg::ref_ptr<osg::Light> mLight;

        // The activation radius
        float mRadius;

        int mId;

    public:

        META_Node(SceneUtil, SceneUtil::LightSource)

        LightSource();

        LightSource(const LightSource& copy, const osg::CopyOp& copyop);

        float getRadius() const
        {
            return mRadius;
        }

        void setRadius(float radius)
        {
            mRadius = radius;
        }

        osg::Light* getLight()
        {
            return mLight;
        }

        void setLight(osg::Light* light)
        {
            mLight = light;
        }

        int getId()
        {
            return mId;
        }
    };

    /// All light sources must be a child of the LightManager node. The LightManager can be anywhere in the scene graph,
    /// but would be typically somewhere near the top.
    class LightManager : public osg::Group
    {
    public:

        META_Node(SceneUtil, SceneUtil::LightManager)

        LightManager();

        LightManager(const LightManager& copy, const osg::CopyOp& copyop);

        // Called automatically by the UpdateCallback
        void update();

        // Called automatically by the LightSource's UpdateCallback
        void addLight(LightSource* lightSource, osg::Matrix worldMat);

        void prepareForCamera(osg::Camera* cam);

        struct LightSourceTransform
        {
            LightSource* mLightSource;
            osg::Matrix mWorldMatrix;
            osg::BoundingSphere mViewBound;
        };

        const std::vector<LightSourceTransform>& getLights() const;

        typedef std::vector<const LightSourceTransform*> LightList;

        osg::ref_ptr<osg::StateSet> getLightListStateSet(const LightList& lightList);

        /// Set the first light index that should be used by this manager, typically the number of directional lights in the scene.
        void setStartLight(int start);

        int getStartLight() const;

    private:
        // Lights collected from the scene graph. Only valid during the cull traversal.
        std::vector<LightSourceTransform> mLights;

        bool mLightsInViewSpace;

        // < Light list hash , StateSet >
        typedef std::map<size_t, osg::ref_ptr<osg::StateSet> > LightStateSetMap;
        LightStateSetMap mStateSetCache;

        int mStartLight;
    };

    class LightListCallback : public osg::NodeCallback
    {
    public:
        LightListCallback()
            : mLightManager(NULL)
        {}
        LightListCallback(const LightListCallback& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY)
            : osg::Object(copy, copyop), osg::NodeCallback(copy, copyop), mLightManager(copy.mLightManager)
        {}

        META_Object(NifOsg, LightListCallback)

        void operator()(osg::Node* node, osg::NodeVisitor* nv);

    private:
        LightManager* mLightManager;
    };

    /// @brief Configures a light's attenuation according to vanilla Morrowind attenuation settings.
    void configureLight(osg::Light* light, float radius, bool isExterior, bool outQuadInLin, bool useQuadratic, float quadraticValue,
                         float quadraticRadiusMult, bool useLinear, float linearRadiusMult, float linearValue);

}

#endif
