/* global L -- eslint */
/**
* DataCache constructor.
* Manages a cache for map data tiles. The cache has a maximum age and size limit,
* and these limits can vary for mobile and desktop environments.
* @class DataCache
*/
window.DataCache = function () {
this.REQUEST_CACHE_FRESH_AGE = 3 * 60; // if younger than this, use data in the cache rather than fetching from the server
this.REQUEST_CACHE_MAX_AGE = 5 * 60; // maximum cache age. entries are deleted from the cache after this time
// NOTE: characters are 16 bits (ECMAScript standard), so divide byte size by two for correct limit
if (L.Browser.mobile) {
// on mobile devices, smaller cache size
this.REQUEST_CACHE_MAX_ITEMS = 300; // if more than this many entries, expire early
this.REQUEST_CACHE_MAX_CHARS = 5000000 / 2; // or more than this total size
} else {
// but on desktop, allow more
this.REQUEST_CACHE_MAX_ITEMS = 1000; // if more than this many entries, expire early
this.REQUEST_CACHE_MAX_CHARS = 20000000 / 2; // or more than this total size
}
this._cache = {};
this._cacheCharSize = 0;
this._interval = undefined;
};
/**
* Stores data in the cache.
* If an entry for the given key already exists, it's removed before the new data is stored.
* The data is stored along with its timestamp and expiration time.
*
* @function
* @memberof DataCache
* @param {string} qk - The key under which to store the data.
* @param {object} data - The data to be stored in the cache.
*/
window.DataCache.prototype.store = function (qk, data) {
this.remove(qk);
var time = new Date().getTime();
var expire = time + this.REQUEST_CACHE_FRESH_AGE * 1000;
var dataStr = JSON.stringify(data);
this._cacheCharSize += dataStr.length;
this._cache[qk] = { time: time, expire: expire, dataStr: dataStr };
};
/**
* Removes a specific entry from the cache based on its key.
*
* @function
* @memberof DataCache
* @param {string} qk - The key of the data to remove from the cache.
*/
window.DataCache.prototype.remove = function (qk) {
if (qk in this._cache) {
this._cacheCharSize -= this._cache[qk].dataStr.length;
delete this._cache[qk];
}
};
/**
* Retrieves the data for a given key from the cache.
*
* @function
* @memberof DataCache
* @param {string} qk - The key of the data to retrieve.
* @returns {object|undefined} The cached data if it exists, otherwise undefined.
*/
window.DataCache.prototype.get = function (qk) {
if (qk in this._cache) return JSON.parse(this._cache[qk].dataStr);
else return undefined;
};
/**
* Retrieves the timestamp for the given key from the cache.
*
* @function
* @memberof DataCache
* @param {string} qk - The key of the data to check.
* @returns {number} The timestamp of the data if it exists, otherwise 0.
*/
window.DataCache.prototype.getTime = function (qk) {
if (qk in this._cache) return this._cache[qk].time;
else return 0;
};
/**
* Checks if the data for the given key is fresh.
*
* @function
* @memberof DataCache
* @param {string} qk - The key of the data to check.
* @returns {boolean|undefined} True if the data is fresh, false if it's stale, undefined if data doesn't exist.
*/
window.DataCache.prototype.isFresh = function (qk) {
if (qk in this._cache) {
var d = new Date();
var t = d.getTime();
if (this._cache[qk].expire >= t) return true;
else return false;
}
return undefined;
};
/**
* Starts the interval to periodically run the cache expiration.
*
* @function
* @memberof DataCache
* @param {number} period - The period in seconds between each expiration run.
*/
window.DataCache.prototype.startExpireInterval = function (period) {
if (this._interval === undefined) {
var savedContext = this;
this._interval = setInterval(function () {
savedContext.runExpire();
}, period * 1000);
}
};
/**
* Stops the interval that checks for cache expiration.
* This function clears the interval set for running the cache expiration check,
* effectively stopping automatic cache cleanup.
*
* @function
* @memberof DataCache.prototype
*/
window.DataCache.prototype.stopExpireInterval = function () {
if (this._interval !== undefined) {
clearInterval(this._interval);
this._interval = undefined;
}
};
/**
* Runs the cache expiration process.
* This function checks and removes expired cache entries based on the maximum age, item count,
* and character size limits.
*
* @function
* @memberof DataCache.prototype
*/
window.DataCache.prototype.runExpire = function () {
var d = new Date();
var t = d.getTime() - this.REQUEST_CACHE_MAX_AGE * 1000;
var cacheSize = Object.keys(this._cache).length;
for (var qk in this._cache) {
if (cacheSize > this.REQUEST_CACHE_MAX_ITEMS || this._cacheCharSize > this.REQUEST_CACHE_MAX_CHARS || this._cache[qk].time < t) {
this._cacheCharSize -= this._cache[qk].dataStr.length;
delete this._cache[qk];
cacheSize--;
}
}
};