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

#include <osgEarth/Common>
#include <osgEarth/Map>
#include <osgEarth/TileKey>
#include <osgEarth/Progress>
#include <OpenThreads/Mutex>
#include <OpenThreads/Atomic>

namespace osgEarth
{
    class CacheSeed;

    class CacheTileOperation : public osg::Operation
    {
    public:
        CacheTileOperation(const MapFrame& mapFrame, CacheSeed& cacheSeed, const TileKey& key);
        virtual void operator()(osg::Object*);

        // The MapFrame to operate on
        const MapFrame& _mapFrame;

        // The parent CacheSeed
        CacheSeed& _cacheSeed;

        // The TileKey to process
        const TileKey _key;
    };

    /**
    * Utility class for seeding a cache
    */
    class OSGEARTH_EXPORT CacheSeed
    {
    public:
        friend class CacheTileOperation;

        CacheSeed();

		CacheSeed( const CacheSeed& rhs);

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

        /**
        * Sets the minimum level to seed to
        */
        void setMinLevel(const unsigned int& minLevel) {_minLevel = minLevel;}

        /**
        * Gets the minimum level to cache to.
        */
        const unsigned int getMinLevel() const {return _minLevel;}

        /**
        * Sets the maximum level to seed to
        */
        void setMaxLevel(const unsigned int& maxLevel) {_maxLevel = maxLevel;}

        /**
        * Gets the maximum level to cache to.
        */
        const unsigned int getMaxLevel() const {return _maxLevel;}

        /*
         * The number of threads to use when seeding
         */
        unsigned int getNumThreads() const;
        void setNumThreads( unsigned int numThreads );

        std::vector< GeoExtent >& getExtents() { return _extents; }

        /**
        *Adds an extent to cache
        */
        void addExtent( const GeoExtent& value );

        /**
        * Set progress callback for reporting which tiles are seeded
        */
        void setProgressCallback(osgEarth::ProgressCallback* progress) { _progress = progress? progress : new ProgressCallback; }

        /**
        * Performs the seed operation
        */
        void seed( Map* map );

    protected:

        void incrementCompleted() const;

        void reportProgress( const std::string& msg ) const;

        unsigned int _minLevel;
        unsigned int _maxLevel;

        unsigned int _total;
        OpenThreads::Atomic _completed;

        unsigned int _numThreads;

        osg::ref_ptr<ProgressCallback> _progress;

        bool cacheTile( const MapFrame& mapf, const TileKey& key ) const;

        std::vector< GeoExtent > _extents;

        // The work queue to pass seed operations to
        osg::ref_ptr< osg::OperationQueue > _queue;  

        OpenThreads::Mutex _mutex;
    };
}

#endif //OSGEARTH_CACHE_SEED_H
