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

#include <osgEarth/Common>
#include <osgEarth/Map>
#include <osgEarth/URI>

namespace osgEarth
{
    class StyleSheet;
    class FeatureSource;
    class StateSetCache;
}

namespace osgEarth { namespace Util
{
    class ResourceCache;
    class ScriptEngine;
 
    /**
     * Session is a state object that exists throughout the life of one or more related
     * feature compilations.
     *
     * A Session holds shared, re-usable data elements that can be accessed through a 
     * FilterContext.
     *
     * Whereas a FilterContext exists thoughout the life of a single compilation, a Session
     * exists one level above this and governs any number of "related" compilations
     * (e.g., the compilation of many grid cells comprising a single feature layer).
     */
    class OSGEARTH_EXPORT Session : public osg::Object
    {
    public:
        META_Object(osgEarth, Session);

        //! New session
        Session(const Map* map);
        
        //! New session
        Session(const Map* map, StyleSheet* styles);
        
        //! New session
        Session(const Map* map, StyleSheet* styles, FeatureSource* source, const osgDB::Options* dbOptions);

        virtual ~Session();

        //! Whether this session is still valid (the map is still set). Snapshot in time.
        bool hasMap() const { return _map.valid(); }

        /**
         * URI Context for relative path resolution.
         */
        void setURIContext( const URIContext& value ) { _uriContext = value; }
        const URIContext& uriContext() const { return _uriContext; }

        /** Underlying map. Check it for null before using! */
        osg::ref_ptr<const Map> getMap() const;

        const Profile* getMapProfile() const;

        const SpatialReference* getMapSRS() const;

        bool isMapGeocentric() const;

        /** The style sheet governing this session. */
        void setStyles( StyleSheet* value );
        StyleSheet* styles() const { return _styles.get(); }

        /**
         * Set the feature source to draw upon in this Session. 
         * Do no call this after the Session is already in use.
         */
        void setFeatureSource(FeatureSource*);
        
        /** Gets the current feature source */
        FeatureSource* getFeatureSource() const;

        /** The I/O options for operations within this session */
        const osgDB::Options* getDBOptions() const;

        /** Shared resource cache (optional) */
        void setResourceCache(ResourceCache* cache);
        ResourceCache* getResourceCache();

        /** Optional name for this session */
        void setName(const std::string& name) { _name = name; }
        const std::string& getName() const { return _name; }

    public:
        //! The cache for optimizing stateset sharing within a session
        StateSetCache* getStateSetCache();

    public:
      ScriptEngine* getScriptEngine() const;

    private:
        void init();
        void initScriptEngine();

        URIContext                         _uriContext;         
        osg::observer_ptr<const Map>       _map;
        osg::ref_ptr<const Profile>        _mapProfile;
        osg::ref_ptr<StyleSheet>           _styles;
        osg::ref_ptr<const osgDB::Options> _dbOptions;
        osg::ref_ptr<ScriptEngine>         _styleScriptEngine;
        osg::ref_ptr<FeatureSource>        _featureSource;
        osg::ref_ptr<StateSetCache>        _stateSetCache;
        osg::ref_ptr<ResourceCache>        _resourceCache;
        std::string                        _name;

        // hidden - support for META_Object
        Session();
        Session(const Session& rhs, const osg::CopyOp& op = osg::CopyOp::SHALLOW_COPY);
    };
} }
