/* -*-c++-*- */
/* osgEarth - Geospatial SDK for OpenSceneGraph
* Copyright 2019 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.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
* 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_POLICY_H
#define OSGEARTH_CACHE_POLICY_H 1

#include <osgEarth/Common>
#include <osgEarth/Config>
#include <osgEarth/DateTime>
#include <osgDB/Options>

namespace osgEarth
{
    /**
     * Policy for cache usage.
     */
    class OSGEARTH_EXPORT CachePolicy
    {
    public:
        enum Usage
        {
            USAGE_READ_WRITE   = 0,  // read/write to the cache if one exists.
            USAGE_CACHE_ONLY   = 1,  // treat the cache as the ONLY source of data.
            USAGE_READ_ONLY    = 2,  // read from the cache, but don't write new data to it.
            USAGE_NO_CACHE     = 3   // neither read from or write to the cache
        };

        /** default cache policy (READ_WRITE) */
        static CachePolicy DEFAULT;

        /* policy indicating to never use a cache */
        static CachePolicy NO_CACHE;

        /** policy indicating to only use a cache */
        static CachePolicy CACHE_ONLY;

    public:
        /** constructs an invalid CachePolicy. */
        CachePolicy();

        /** copy ctor */
        CachePolicy(const CachePolicy& rhs);

        /** constructs a caching policy. */
        CachePolicy( const Usage& usage );

        /** constructs a CachePolicy from a config options */
        CachePolicy( const Config& conf );

        /** Merges any set properties in another CP into this one, override existing values. */
        void mergeAndOverride(const CachePolicy& rhs);
        void mergeAndOverride(const optional<CachePolicy>& rhs);

        /** Gets the oldest timestamp for which to accept a cache record */
        TimeStamp getMinAcceptTime() const;

        /** Whether the given timestamp is considered to be expired based on this CachePolicy */
        bool isExpired(TimeStamp lastModified) const;

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

        /** Gets the usage policy */
        optional<Usage>& usage() { return _usage; }
        const optional<Usage>& usage() const { return _usage; }

        /** Gets the age limit for a cache record (in seconds) */
        optional<TimeSpan>& maxAge() { return _maxAge; }
        const optional<TimeSpan>& maxAge() const { return _maxAge; }

        /** Gets the age limit for a cache record (as an absolute timestamp) */
        optional<TimeStamp>& minTime() { return _minTime; }
        const optional<TimeStamp>& minTime() const { return _minTime; }

        /** Whether any of the fields are set */
        bool empty() const;

    public: // convenience functions.

        bool isCacheEnabled() const {
            return isCacheReadable() || isCacheWriteable();
        }

        bool isCacheDisabled() const {
            return !isCacheEnabled();
        }

        bool isCacheReadable() const { 
            return *_usage == USAGE_READ_WRITE || *_usage == USAGE_CACHE_ONLY || *_usage == USAGE_READ_ONLY;
        }

        bool isCacheWriteable() const {
            return *_usage == USAGE_READ_WRITE;
        }

        bool isCacheOnly() const {
            return *_usage == USAGE_CACHE_ONLY;
        }

        bool operator == ( const CachePolicy& rhs ) const;

        bool operator != ( const CachePolicy& rhs ) const {
            return ! operator==(rhs);
        }

        CachePolicy& operator = ( const CachePolicy& rhs );

        // returns a readable string describing usage
        std::string usageString() const;

    public: // config
        Config getConfig() const;
        void fromConfig( const Config& conf );

    private:
        optional<Usage>     _usage;
        optional<TimeSpan>  _maxAge;
        optional<TimeStamp> _minTime;
    };
}
OSGEARTH_SPECIALIZE_CONFIG(osgEarth::CachePolicy);

#endif // OSGEARTH_CACHE_POLICY_H
