/* -*-c++-*- */
/* osgEarth - Dynamic map generation toolkit for OpenSceneGraph
 * Copyright 2008-2013 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 OSGEARTHUTIL_TMS_PACKAGER_H
#define OSGEARTHUTIL_TMS_PACKAGER_H

#include <osgEarthUtil/Common>
#include <osgEarth/ImageLayer>
#include <osgEarth/ElevationLayer>
#include <osgEarth/Profile>
#include <osgEarth/TaskService>

namespace osgEarth { namespace Util
{
    /**
     * Utility that reads tiles from an ImageLayer or ElevationLayer and stores
     * the resulting data in a disk-based TMS (Tile Map Service) repository.
     *
     * See: http://wiki.osgeo.org/wiki/Tile_Map_Service_Specification
     */
    class OSGEARTHUTIL_EXPORT TMSPackager
    {
    public:
        /**
         * Constructs a new packager.
         * @param profile    Profile of packaged tile data (required)
         */
        TMSPackager( const Profile* outProfile, osgDB::Options* imageWriteOptions);

        /** dtor */
        virtual ~TMSPackager() { }

        /**
         * Whether to dump out progress messages 
         * default = false
         */
        void setVerbose( bool value ) { _verbose = value; }
        bool getVerbose() const { return _verbose; }

        /**
         * Whether to abort if a tile writing error is encountered
         * default = true
         */
        void setAbortOnError( bool value ) { _abortOnError = value; }
        bool getAbortOnError() const { return _abortOnError; }

        /**
         * Maximum level of detail of tiles to package
         */
        void setMaxLevel( unsigned value ) { _maxLevel = value; }
        unsigned getMaxLevel() const { return _maxLevel; }

        /**
         * Whether to overwrite files that already exist in the repo
         * default = false
         */
        void setOverwrite( bool value ) { _overwrite = value; }
        bool getOverwrite() const { return _overwrite; }

        /**
         * Whether to package empty image tiles. An empty tile is a tile
         * that is fully transparent. By default, the packager discards
         * them and does not subdivide past them.
         * default = false
         */
        void setKeepEmptyImageTiles( bool value ) { _keepEmptyImageTiles = value; }
        bool getKeepEmptyImageTiles() const { return _keepEmptyImageTiles; }

        /**
         * Whether to subdivide single color image tiles. An single color tile is a tile
         * that is filled with a single color. By default, the packager does not subdivide past them.
         * default = false
         */
        void setSubdivideSingleColorImageTiles( bool value ) { _subdivideSingleColorImageTiles = value; }
        bool getSubdivideSingleColorImageTiles() const { return _subdivideSingleColorImageTiles; }

        /**
         * Bounding box to package
         */
        void addExtent( const GeoExtent& value );

        /**
         * Result structure for method calls
         */
        struct Result {
            Result(int tasks=0) : ok(true), taskCount(tasks) { }
            Result(const std::string& m) : message(m), ok(false), taskCount(0) { }
            operator bool() const { return ok; }
            bool ok;
            std::string message;
            int taskCount;
        };

        /**
         * Packages an image layer as a TMS repository.
         * @param layer          Image layer to export
         * @param rootFolder     Root output folder of TMS repo
         * @param imageExtension (optional) Force an image type extension (e.g., "jpg")
         */
        Result package(
            ImageLayer*        layer,
            const std::string& rootFolder,
            osgEarth::ProgressCallback* progress=0L,
            const std::string& imageExtension="png" );

        /**
         * Packages an elevation layer as a TMS repository.
         * @param layer          Image layer to 
         * @param rootFolder     Root output folder of TMS repo
         */
        Result package( 
            ElevationLayer*    layer,
            const std::string& rootFolder,
            osgEarth::ProgressCallback* progress=0L );

    protected:

        int packageImageTile(
            ImageLayer*          layer,
            const TileKey&       key,
            const std::string&   rootDir,
            const std::string&   extension,
            osgEarth::TaskRequestVector& tasks,
            Threading::MultiEvent* semaphore,
            osgEarth::ProgressCallback* progress,
            unsigned&            out_maxLevel );

        int packageElevationTile(
            ElevationLayer*      layer,
            const TileKey&       key,
            const std::string&   rootDir,
            const std::string&   extension,
            osgEarth::TaskRequestVector& tasks,
            Threading::MultiEvent* semaphore,
            osgEarth::ProgressCallback* progress,
            unsigned&            out_maxLevel );

        bool shouldPackageKey( 
            const TileKey&     key ) const;

    protected:

        bool                        _verbose;
        bool                        _abortOnError;
        bool                        _overwrite;
        bool                        _keepEmptyImageTiles;
        bool                        _subdivideSingleColorImageTiles;
        unsigned                    _maxLevel;
        std::vector<GeoExtent>      _extents;
        osg::ref_ptr<const Profile> _outProfile;
        osg::ref_ptr<osgDB::Options>    _imageWriteOptions;
    };

} } // namespace osgEarth::Util

#endif // OSGEARTHUTIL_TMS_PACKAGER_H
