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

#include <osgEarth/FeatureSource>
#include <osgEarth/GeoData>

using namespace osgEarth;

namespace osgDB {
    class Options;
}

/**
 * TFS API
 */
namespace osgEarth { namespace TFS
{    
    class OSGEARTH_EXPORT Layer
    {
    public:
        Layer();

        const std::string& getTitle() const { return _title;}
        void setTitle(const std::string& value) { _title = value;}

        const std::string& getAbstract() const { return _abstract;}
        void setAbstract(const std::string& value) { _abstract = value;}

        const GeoExtent& getExtent() const { return _extent;}
        void setExtent(const GeoExtent& value) { _extent = value;}

        unsigned int getMaxLevel() const { return _maxLevel;}
        void setMaxLevel( unsigned int value ) { _maxLevel = value;}

        unsigned int getFirstLevel() const { return _firstLevel;}
        void setFirstLevel(unsigned int value) { _firstLevel = value;}

        const SpatialReference* getSRS() const { return _srs.get();}
        void setSRS( const SpatialReference* srs ) { _srs = srs;}

    private:
        std::string _title = { "layer" };
        std::string _abstract;
        GeoExtent _extent;
        unsigned int _maxLevel = 8;
        unsigned int _firstLevel = 0;
        osg::ref_ptr< const SpatialReference > _srs;
    };

    class OSGEARTH_EXPORT ReaderWriter
    {
    public:
        static bool read(const URI& uri, const osgDB::Options* options, Layer& layer);
        static bool read( std::istream& in, Layer& layer);

        static void write(const Layer& layer, const std::string& location);
        static void write(const Layer& layer, std::ostream& output);
    };

    // Internal serialization data for the TFS feature source
    class OSGEARTH_EXPORT TFSFeatureSourceOptions : public TiledFeatureSource::Options
    {
    public:
        META_LayerOptions(osgEarth, TFSFeatureSourceOptions, TiledFeatureSource::Options);
        OE_OPTION(URI, url);
        OE_OPTION(std::string, format);
        OE_OPTION(bool, invertY);
        OE_OPTION(bool, autoFallback);
        virtual Config getConfig() const;
    private:
        void fromConfig(const Config& conf);
    };

}} // namespace osgEarth::TFS


/**
 * A FeatureSource that reads feature tiles from a TFS layer
 */
namespace osgEarth
{
    /**
     * Feature Layer that accesses features from a TFS endpoint
     */
    class OSGEARTH_EXPORT TFSFeatureSource : public TiledFeatureSource
    {   
    public: // serialization
        using Options = TFS::TFSFeatureSourceOptions;

    public:
        META_Layer(osgEarth, TFSFeatureSource, Options, TiledFeatureSource, TFSFeatures);

        //! Location of the resource
        void setURL(const URI& value);
        const URI& getURL() const;

        //! Format of the geometry data (GeoJSON, GML)
        void setFormat(const std::string& value);
        const std::string& getFormat() const;

        //! Whether to flip the Y coordinate for tile access
        void setInvertY(const bool& value);
        const bool& getInvertY() const;

        //! Whether a query for a TileKey higher than the max_level will
        //! automatically fall back to a query at the max_level.
        //! Default = false (an out-of bounds query returns nothing)
        void setAutoFallbackToMaxLevel(const bool& value);
        const bool& getAutoFallbackToMaxLevel() const;

    public: // Layer

        Status openImplementation() override;

    protected:

        void init() override;

    public: // FeatureLayer

        FeatureCursor* createFeatureCursorImplementation(const Query& query, ProgressCallback* progress) const override;
        
    protected:

        virtual ~TFSFeatureSource() { }

    private:    
        TFS::Layer _layer;
        bool _layerValid;

        bool getFeatures(const std::string& buffer, const TileKey& key, const std::string& mimeType, FeatureList& features) const;
        std::string getExtensionForMimeType(const std::string& mime) const;
        bool isGML(const std::string& mime) const;
        bool isJSON(const std::string& mime) const;
        std::string createURL(const Query& query) const;
    };
} // namespace osgEarth


OSGEARTH_SPECIALIZE_CONFIG(osgEarth::TFSFeatureSource::Options);

#endif // OSGEARTH_FEATURES_TFS_FEATURESOURCE_LAYER
