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

#include "RocksDBCacheOptions"
#include <osgEarth/Threading>
#include <osgDB/FileUtils>
#include <osgDB/FileNameUtils>
#include <osg/Referenced>
#include <sys/stat.h>
#ifndef _WIN32
#   include <unistd.h>
#endif

namespace osgEarth { namespace RocksDBCache
{
    /**
     * Tracks usage metrics across a RocksDB cache
     */
    class Tracker : public osg::Referenced
    {
    public:
        Tracker(const RocksDBCacheOptions& options,
                const std::string&         path ) : 
            _options(options),                 
            _path(path),
            _seed(0)
        {
            _maxBytes = (off_t)(options.maxSizeMB().get() * 1048576);
            _size = (::off_t)0;

            if (_options.key().isSet() && !_options.key()->empty())
            {
                _seed = osgEarth::hashString(_options.key().value());
            }
        }
        virtual ~Tracker() { }

    public:
        std::atomic_uint reads;
        std::atomic_uint hits;
        std::atomic_uint writes;

        bool hasSizeLimit() const {
            return _options.maxSizeMB().isSet();
        }

        bool isOverLimit() const { 
            return _size > _maxBytes; 
        }

        bool isTimeToCheckSize() const {
            return ((unsigned)writes % _options.sizeCheckPeriod().value()) == 0;
        }

        bool isTimeToPurge() const {
            unsigned w = (unsigned)writes;
            return w == 1 || (w % _options.sizePurgePeriod().value()) == 0;
        }

        unsigned numToPurge() const {
            return _options.sizePurgePeriod().value();
        }

        const optional<unsigned>& seed() const {
            return _seed;
        }

        ::off_t calcSize()
        {
            ::off_t total = 0;
            osgDB::DirectoryContents dir = osgDB::getDirectoryContents(_path);
            for(osgDB::DirectoryContents::iterator i = dir.begin(); i != dir.end(); ++i)
            {
                std::string path = osgDB::concatPaths(_path, *i);
                struct stat s;
                ::stat( path.c_str(), &s );
                total += s.st_size;
            }
            _size = total;
            return total;
        }

    private:
        const std::string         _path;
        const RocksDBCacheOptions _options;
        ::off_t                   _maxBytes;
        ::off_t                   _size;
        optional<unsigned>        _seed;
    };

} } // namespace osgEarth::RocksDBCache

#endif // OSGEARTH_DRIVER_CACHE_ROCKSDB_TRACKER
