/* osgEarth
 * Copyright 2025 Pelican Mapping
 * MIT License
 */
#ifndef OSGEARTH_COLOR_FILTER_H
#define OSGEARTH_COLOR_FILTER_H 1

#include <osgEarth/Common>
#include <osgEarth/Config>
#include <osg/StateSet>
#include <vector>

namespace osgEarth
{
    /** 
     * An ColorFilter is an inline shader-based image processing function.
     * You can install a chain of ColorFilters on an ImageLayer and the shaders
     * will post-process the layer's color (after texturing but before lighting)
     * using custom shader code.
     *
     * NOTE: ColorFilter will probably be deprecated at some point down the line.
     * Consider using a Layer shader instead.
     */
    class /*header-only*/ ColorFilter : public osg::Referenced
    {
    protected:
        ColorFilter() { }

    public:
        /**
         * The name of the function to call in the custom shader. This function
         * must have the signature:
         *
         *    void function(inout vec4 color)
         *
         * Failure to match this signature will result in a shader compilation error.
         *
         * @param uid Unique ID of the object to which this filter is attached.
         */
        virtual std::string getEntryPointFunctionName() const =0;

        /**
         * Installs any uniforms or other bindings required by this filter on the
         * provided state set.
         */
        virtual void install( osg::StateSet* stateSet ) const =0;

        /**
         * Serializes this object to a Config (optional).
         */
        virtual Config getConfig() const { return Config(); }
    };


    /**
     * A "Chain" of image filters. They are executed in order.
     */
    typedef std::vector< osg::ref_ptr<ColorFilter> > ColorFilterChain;


    //--------------------------------------------------------------------

    class ColorFilterFactory;

    /**
     * Registry for ColorFilter serialization support.
     */
    class OSGEARTH_EXPORT ColorFilterRegistry : public osg::Referenced
    {
    public:
        static ColorFilterRegistry* instance();

    public:
        /**
         * Creates a chain of color filters (based on order of appearance in the Config)
         * @return True if it created at least one object.
         */
        bool readChain(const Config& conf, ColorFilterChain& out_chain);

        /**
         * Serializes a filter chain to the provided Config object
         * @return True if at least one filter was serialized.
         */
        bool writeChain(const ColorFilterChain& chain, Config& out_config);

        /**
         * Adds a ColorFilter type to the registry
         */
        void add( const std::string& key, ColorFilterFactory* factory );


    public:
        ColorFilterRegistry() { }
        virtual ~ColorFilterRegistry() { }

        // must override this to support serialization:
        virtual Config getConfig() const { return Config(); }

    private:
        typedef std::unordered_map<std::string, class ColorFilterFactory*> FactoryMap;
        FactoryMap _factories;
        ColorFilter* createOne(const Config& conf) const;
    };

    // internal: interface class for an object that creates a ColorFilter instance from a Config
    // (used by OSGEARTH_REGISTER_COLORFILTER macro)
    class ColorFilterFactory {
    public:
        virtual ColorFilter* create(const Config& conf) const =0;
        virtual ~ColorFilterFactory() { }
    };

    // internal: proxy class used by the registraion macro
    template<typename T>
    struct ColorFilterRegistrationProxy : public ColorFilterFactory {
        ColorFilterRegistrationProxy(const std::string& key) { ColorFilterRegistry::instance()->add(key, this); }
        ColorFilter* create(const Config& conf) const { return new T(conf); }
    };

    // Macro used to register new annotation types.
#define OSGEARTH_REGISTER_COLORFILTER( KEY, CLASSNAME ) \
    extern "C" void osgearth_colorfilter_##KEY(void) {} \
    static osgEarth::ColorFilterRegistrationProxy< CLASSNAME > s_osgEarthColorFilterRegistrationProxy##KEY( #KEY )
    
#define USE_OSGEARTH_COLORFILTER( KEY ) \
    extern "C" void osgearth_colorfilter_##KEY(void); \
    static osgDB::PluginFunctionProxy proxy_osgearth_colorfilter_##KEY(osgearth_colorfilter_##KEY);

} // namespace osgEarth

#endif // OSGEARTH_IMAGE_FILTER_H
