/* osgEarth
 * Copyright 2025 Pelican Mapping
 * MIT License
 */
#pragma once

#include <osgEarth/Common>
#include <osgEarth/Feature>
#include <osgEarth/Session>

#include <osgEarth/ResourceCache>

#include <osgEarth/GeoData>
#include <osgEarth/ShaderUtils>

#include <osg/Matrix>
#include <list>
#include <vector>

namespace osgEarth
{
    class FeatureProfile;
    class FeatureIndexBuilder;
    class Geometry;
    class Query;
}

namespace osgEarth { namespace Util
{
    /**
     * Context within which a chain of filters is executed.
     */
    class OSGEARTH_EXPORT FilterContext
    {
    public:
        //! Construct (default)
        FilterContext() = default;

        //! Construct with a session
        //! Use this if you session has a feature source.
        FilterContext(
            Session* session,
            const GeoExtent& workingExtent = GeoExtent::INVALID,
            FeatureIndexBuilder* index = nullptr);

        //! Construct with a session and a feature profile
        //! Use this if your session soes NOT have a feature source.
        FilterContext(
            Session*              session,
            const FeatureProfile* profile,
            const GeoExtent&      workingExtent =GeoExtent::INVALID,
            FeatureIndexBuilder*  index         =nullptr);

        //! Construct with a profile and a query
        //! Use this is you don't have a session at all.
        FilterContext(
            const FeatureProfile* profile,
            const Query& query);

        //! Construct (copy)
        FilterContext(const FilterContext& rhs) = default;
        FilterContext& operator = (const FilterContext& rhs) = default;

        //! Construct (move)
        FilterContext(FilterContext&& rhs) = default;
        FilterContext& operator = (FilterContext&& rhs) = default;

        //! Sets the output SRS for feature processing. This is optional.
        //! If you do not set this, the output SRS will be that of the
        //! session's Map.
        void setOutputSRS(const SpatialReference* srs) { _outputSRS = srs; }
        const SpatialReference* outputSRS() const;

        //! Whether this context contains complete georeferencing information.
        bool isGeoreferenced() const;

        //! Access to the Session under which this filter context operates
        Session* session() { return _session.get(); }
        const Session* session() const { return _session.get(); }

        //! The spatial profile of the feature data in this context.
        void setFeatureProfile(const FeatureProfile* value) { _featureProfile = value; }
        const FeatureProfile* featureProfile() const { return _featureProfile.get(); }

        //! The spatial extent of the working cell, if set
        void setWorkingExtent(const GeoExtent& value) { _workingExtent = value; }
        const optional<GeoExtent>& workingExtent() const { return _workingExtent; }

        //! The feature index (optional)
        FeatureIndexBuilder* featureIndex() { return _index; }
        const FeatureIndexBuilder* featureIndex() const { return _index; }

        //! Accesses the shared resource cache where filters can store data.
        void setResourceCache(ResourceCache* value) { _resourceCache = value; }
        ResourceCache* resourceCache() { return _resourceCache.get(); }

        //! Gets the DB Options associated with the context's session
        const osgDB::Options* getDBOptions() const;

        // deprecated
        [[deprecated]] optional<GeoExtent>& extent() { return _workingExtent; }
        [[deprecated]] const optional<GeoExtent>& extent() const { return workingExtent(); }
        [[deprecated]] const FeatureProfile* profile() const { return featureProfile(); }
        [[deprecated]] void setProfile(const FeatureProfile* value) { setFeatureProfile(value); }
        [[deprecated]] const SpatialReference* getOutputSRS() const { return outputSRS(); }
        [[deprecated]] Session* getSession() { return session(); }
        [[deprecated]] const Session* getSession() const { return session(); }

    protected:

        osg::ref_ptr<Session> _session;
        osg::ref_ptr<const FeatureProfile> _featureProfile;
        optional<GeoExtent> _workingExtent;
        osg::ref_ptr<ResourceCache> _resourceCache;
        FeatureIndexBuilder* _index = nullptr;
        osg::ref_ptr<const SpatialReference> _outputSRS;
    };
} }


