"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var ig_utilities_1 = require("@intelligentgraphics/ig.utilities");
var CacheHolder = /** @class */ (function () {
    function CacheHolder() {
        this.cache = new Map();
        this.cacheAliases = new Map();
    }
    CacheHolder.createHashedAbsoluteUrl = function (url, basePath, hashes) {
        if (ig_utilities_1.isNullOrUndefined(url)) {
            return url;
        }
        var hash = !ig_utilities_1.isNullOrUndefined(hashes) &&
            (typeof hashes === "object" ? hashes[url] : hashes);
        var absoluteUrl = ig_utilities_1.isNullOrUndefined(basePath) || ig_utilities_1.Http.isAbsoluteUrl(url)
            ? url
            : ig_utilities_1.Http.joinPaths(basePath, url);
        if (hash) {
            return ig_utilities_1.Http.createUrl(absoluteUrl, {
                params: {
                    igxcHash: hash,
                },
            });
        }
        return absoluteUrl;
    };
    /**
     * Retrieves all cache keys
     *
     * @returns {string[]}
     */
    CacheHolder.prototype.getAllEntries = function () {
        return tslib_1.__spread(this.cache.keys());
    };
    /**
     * Retrieves the cached resource from the cache or returns undefined
     *
     * @param {(string)} identifierOrAlias
     * @returns {(Resource | undefined)}
     */
    CacheHolder.prototype.get = function (identifierOrAlias) {
        var cacheIdentifier = this.normalizeIdentifier(identifierOrAlias);
        if (cacheIdentifier === undefined) {
            return undefined;
        }
        var cacheResult = this.cache.get(cacheIdentifier);
        if (cacheResult === undefined || cacheResult.status === "loading") {
            return undefined;
        }
        return cacheResult.value;
    };
    /**
     * Returns true when a resource is available and loaded
     *
     * @param {string} identifierOrAlias
     * @returns {boolean}
     */
    CacheHolder.prototype.has = function (identifierOrAlias) {
        var cacheIdentifier = this.normalizeIdentifier(identifierOrAlias);
        return (this.cache.has(cacheIdentifier) &&
            this.cache.get(cacheIdentifier).status === "loaded");
    };
    /**
     * Returns true when a resource is available or currently loading
     *
     * @param {string} identifierOrAlias
     * @returns {boolean}
     */
    CacheHolder.prototype.hasOrLoads = function (identifierOrAlias) {
        var cacheIdentifier = this.normalizeIdentifier(identifierOrAlias);
        return this.cache.has(cacheIdentifier);
    };
    /**
     * Synchronously overwrites a resources
     *
     * @param {string} identifier
     * @param {Resource} value
     */
    CacheHolder.prototype.put = function (identifier, value) {
        this.cache.set(identifier, {
            status: "loaded",
            value: value,
        });
        this.onResourceAdded(identifier);
    };
    /**
     * Removes a resource from the cache either by alias or identifier
     *
     * @param {string} identifierOrAlias
     * @returns {boolean}
     */
    CacheHolder.prototype.remove = function (identifierOrAlias) {
        var e_1, _a;
        var aliasedIdentifier = this.cacheAliases.get(identifierOrAlias);
        var cacheIdentifier = aliasedIdentifier !== undefined
            ? aliasedIdentifier
            : identifierOrAlias;
        if (cacheIdentifier === undefined) {
            return false;
        }
        try {
            for (var _b = tslib_1.__values(this.cacheAliases), _c = _b.next(); !_c.done; _c = _b.next()) {
                var _d = tslib_1.__read(_c.value, 2), alias = _d[0], cacheId = _d[1];
                if (cacheId === cacheIdentifier) {
                    this.cacheAliases.delete(alias);
                }
            }
        }
        catch (e_1_1) { e_1 = { error: e_1_1 }; }
        finally {
            try {
                if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
            }
            finally { if (e_1) throw e_1.error; }
        }
        if (this.cache.has(cacheIdentifier)) {
            this.onResourceRemoved(cacheIdentifier);
            return this.cache.delete(cacheIdentifier);
        }
        return false;
    };
    CacheHolder.prototype.awaitResource = function (identifierOrAlias) {
        console.log("in awaitResourceOrAlias()", identifierOrAlias);
        var resource = this.cache.get(this.normalizeIdentifier(identifierOrAlias));
        if (resource === undefined) {
            return Promise.reject(new Error("Can not find resource for " + identifierOrAlias));
        }
        if (resource.status === "loaded") {
            return Promise.resolve(resource.value);
        }
        return resource.value;
    };
    /**
     * Ensures a resources is available in the cache
     *
     * @param {LoadData} data
     * @returns {Promise<Resource>}
     */
    CacheHolder.prototype.ensure = function (data) {
        return tslib_1.__awaiter(this, void 0, void 0, function () {
            var cacheIdentifier, resourceValue, cacheEntry, loadPromise;
            var _this = this;
            return tslib_1.__generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        cacheIdentifier = this.createIdentifier(data);
                        if (!this.cache.has(cacheIdentifier)) return [3 /*break*/, 4];
                        resourceValue = void 0;
                        cacheEntry = this.cache.get(cacheIdentifier);
                        if (!ig_utilities_1.isNullOrUndefined(data.alias)) {
                            this.addAlias(data.alias, cacheIdentifier);
                        }
                        if (!(cacheEntry.status === "loading")) return [3 /*break*/, 2];
                        return [4 /*yield*/, cacheEntry.value];
                    case 1:
                        resourceValue = _a.sent();
                        return [3 /*break*/, 3];
                    case 2:
                        resourceValue = cacheEntry.value;
                        _a.label = 3;
                    case 3:
                        if (this.isResourceValid(data, resourceValue)) {
                            return [2 /*return*/, resourceValue];
                        }
                        this.remove(cacheIdentifier);
                        _a.label = 4;
                    case 4:
                        loadPromise = this.load(data);
                        this.cache.set(cacheIdentifier, {
                            status: "loading",
                            value: loadPromise,
                        });
                        return [2 /*return*/, loadPromise
                                .then(function (resource) {
                                _this.cache.set(cacheIdentifier, {
                                    status: "loaded",
                                    value: resource,
                                });
                                _this.onResourceAdded(cacheIdentifier, data);
                                if (!ig_utilities_1.isNullOrUndefined(data.alias)) {
                                    _this.addAlias(data.alias, cacheIdentifier);
                                }
                                return resource;
                            })
                                .catch(function (err) {
                                _this.cache.delete(cacheIdentifier);
                                return Promise.reject(err);
                            })];
                }
            });
        });
    };
    CacheHolder.prototype.isResourceValid = function (data, resource) {
        return true;
    };
    CacheHolder.prototype.onResourceAdded = function (identifier, data) { };
    CacheHolder.prototype.onResourceRemoved = function (identifier) { };
    CacheHolder.prototype.addAlias = function (alias, resourceIdentifier) {
        this.cacheAliases.set(alias, resourceIdentifier);
    };
    CacheHolder.prototype.removeAlias = function (alias) {
        this.cache.delete(alias);
    };
    CacheHolder.prototype.normalizeIdentifier = function (identifier) {
        // make sure that createIdentifier() is not called with null
        var cacheIdentifier = identifier !== undefined &&
            identifier != null &&
            typeof identifier === "object"
            ? this.createIdentifier(identifier)
            : identifier;
        if (this.cacheAliases.has(cacheIdentifier)) {
            return this.cacheAliases.get(cacheIdentifier);
        }
        return cacheIdentifier;
    };
    return CacheHolder;
}());
exports.CacheHolder = CacheHolder;
