/* -*-c++-*- */
/* osgEarth - Geospatial SDK for OpenSceneGraph
 * Copyright 2020 Pelican Mapping
 * http://osgearth.org
 *
 * osgEarth 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 2 of the License, or
 * (at your option) any later version.
 *
 * This program 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
 */
#ifndef OSGEARTH_VISIBLE_LAYER_H
#define OSGEARTH_VISIBLE_LAYER_H

#include <osgEarth/Layer>

namespace osgEarth
{
    enum ColorBlending
    {
        BLEND_INTERPOLATE,
        BLEND_MODULATE
    };
}

namespace osgEarth
{
    struct VisibleLayerCallback : public LayerCallback
    {
        virtual void onVisibleChanged(class VisibleLayer* layer) { }
        virtual void onOpacityChanged(class VisibleLayer* layer) { }
        virtual void onVisibleRangeChanged(class VisibleLayer* layer) { }
        typedef void (VisibleLayerCallback::*MethodPtr)(class VisibleLayer* layer);
    };


    //! Base class for a layer supporting visibility and opacity controls.
    class OSGEARTH_EXPORT VisibleLayer : public Layer
    {
    public: // serialization
        class OSGEARTH_EXPORT Options : public Layer::Options {
        public:
            META_LayerOptions(osgEarth, Options, Layer::Options);
            OE_OPTION(bool, visible);
            OE_OPTION(float, opacity);
            OE_OPTION(float, minVisibleRange);
            OE_OPTION(float, maxVisibleRange);
            OE_OPTION(float, attenuationRange);
            OE_OPTION(ColorBlending, blend);
            OE_OPTION(osg::Node::NodeMask, mask);
            OE_OPTION(bool, debugView);
            virtual Config getConfig() const;
        private:
            void fromConfig(const Config& conf);
        };

    public:
        META_Layer(osgEarth, VisibleLayer, Options, Layer, VisibleLayer);

    protected:
        virtual ~VisibleLayer();

    public:
        //! Whether to draw this layer.
        void setVisible(bool value);
        bool getVisible() const;

        //! Opacity with which to draw this layer
        virtual void setOpacity(float value);
        float getOpacity() const;

        //! Minimum camera range at which this image layer is visible (if supported)
        float getMinVisibleRange() const;
        void setMinVisibleRange( float minVisibleRange );

        //! Maximum camera range at which this image layer is visible (if supported)
        float getMaxVisibleRange() const;
        void setMaxVisibleRange( float maxVisibleRange );

        //! Distance (m) over which to ramp min and max range blending
        float getAttenuationRange() const;
        void setAttenuationRange( float value );

        //! Blending mode to apply when rendering this layer
        void setColorBlending(ColorBlending value);
        ColorBlending getColorBlending() const;

        //! The node mask to apply to the layer when rendering.  This works exactly like the node mask would on a node.
        osg::Node::NodeMask getMask() const;
        void setMask(osg::Node::NodeMask mask);

        //! Gets/Sets the default mask to use for VisibleLayers.  Default is 0xffffffff.  Set this very early on your application to make all VisibleLayers have this mask by default.
        static osg::Node::NodeMask getDefaultMask();
        static void setDefaultMask(osg::Node::NodeMask mask);

        //! Enables/disables a debug view for this layer, if available.
        void setEnableDebugView(bool value);
        bool getEnableDebugView() const;

    public: // Layer

        virtual Status openImplementation() override;

    protected: // Layer

        virtual void init() override;

        virtual void prepareForRendering(TerrainEngine*) override;

        void fireCallback(VisibleLayerCallback::MethodPtr);

        bool _visibleTiedToOpen = false;
        bool _canSetVisible = true;

    private:
        osg::ref_ptr<osg::Uniform> _opacityU;
        osg::ref_ptr<osg::Uniform> _rangeU;
        osg::ref_ptr<osg::NodeCallback> _noDrawCallback;
        bool _minMaxRangeShaderAdded;
        void initializeUniforms();
        void initializeMinMaxRangeShader();
        void updateNodeMasks();
    };

    typedef std::vector< osg::ref_ptr<VisibleLayer> > VisibleLayerVector;

} // namespace TileLayer

#endif // OSGEARTH_RENDER_LAYER_H
