/* -*-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_LAND_COVER_LAYER
#define OSGEARTH_LAND_COVER_LAYER 1

#include <osgEarth/ImageLayer>
#include <osgEarth/LandCover>
#include <osgEarth/LayerReference>

namespace osgEarth
{    
    /**
     * Layer that provides land cover raster data, in which each texel 
     * contains a land cover code as defined in the LandCoverDictionary.
     * This appears in a Map as a shared, non-visible Layer.
     */
    class OSGEARTH_EXPORT LandCoverLayer : public ImageLayer
    {
    public: // serialization
        class OSGEARTH_EXPORT Options : public ImageLayer::Options {
        public:
            META_LayerOptions(osgEarth, Options, ImageLayer::Options);
            OE_OPTION_LAYER(ImageLayer, source);
            LandCoverValueMappingVector& mappings() { return _mappings; }
            const LandCoverValueMappingVector& mappings() const { return _mappings; }
            virtual Config getConfig() const;
        private:
            void fromConfig(const Config& conf);
            LandCoverValueMappingVector _mappings;
        };

    public:
        META_Layer(osgEarth, LandCoverLayer, Options, ImageLayer, LandCover);

        //! Sets the image layer from which to read coverage data
        void setSource(ImageLayer* layer);
        ImageLayer* getSource() const;

        //! Access to the land cover mappings
        LandCoverValueMappingVector& getLandCoverValueMappings();
        const LandCoverValueMappingVector& getLandCoverValueMappings() const;

        //! Convenience function to add a mapping
        void map(int value, const std::string& classname);

    public: // Layer

        virtual Status openImplementation();

        virtual void addedToMap(const class Map*);

        virtual void removedFromMap(const class Map*);

        virtual GeoImage createImageImplementation(const TileKey& key, ProgressCallback*) const;

        virtual Config getConfig() const;

    protected: // Layer

        virtual void init();

    protected: // TileLayer

        osg::ref_ptr<LandCoverDictionary> _lcDictionary;
        typedef std::vector<int> CodeMap;
        CodeMap _codemap;
        LandCoverValueMappingVector _mappings;

        GeoImage createFractalEnhancedImage(const TileKey& key, ProgressCallback* progress) const;

        void buildCodeMap(CodeMap&);

        struct MetaImageComponent {
            MetaImageComponent() : pixel(0L), failed(false) { }
            bool failed;
            osg::ref_ptr<const osg::Image> image;
            osg::Matrix scaleBias;
            ImageUtils::PixelReader pixel;
        };
        typedef MetaImageComponent MetaImage[3][3];

        bool readMetaImage(MetaImage&, const TileKey&, int s, int t, osg::Vec4f& output, ProgressCallback*) const;

        int _waterCode, _beachCode;
    };


    /**
    * Vector of landcover layers, with added methods.
    */
    class OSGEARTH_EXPORT LandCoverLayerVector : public osg::MixinVector< osg::ref_ptr<LandCoverLayer> >
    {
    public:
        /**
        * Populates an existing height field (hf must already exist) with height
        * values from the elevation layers.
        */
        bool populateLandCoverImage(
            osg::ref_ptr<osg::Image>& image,
            const TileKey& key,
            ProgressCallback* progress ) const;

    public:
        LandCoverLayerVector();
        LandCoverLayerVector(const LandCoverLayerVector& rhs);
    };

} // namespace osgEarth

OSGEARTH_SPECIALIZE_CONFIG(osgEarth::LandCoverLayer::Options);

#endif // OSGEARTH_LAND_COVER_LAYER
