import { __assign, __values } from "tslib";
export var createArticleState = function () {
    var articles = new Map();
    var gfxComIdMap = new Map();
    var lockArticle = function (article) {
        Object.freeze(article);
        Object.freeze(article.configuration);
        Object.freeze(article.children);
        Object.freeze(article.properties);
        Object.freeze(article.info);
        Object.freeze(article.data);
    };
    var getComIdByGfxId = function (gfxId) { return gfxComIdMap.get(gfxId); };
    var getArticleByComId = function (comId) { return articles.get(comId); };
    var getArticleByGfxId = function (gfxId) {
        var comId = getComIdByGfxId(gfxId);
        if (comId === undefined) {
            return undefined;
        }
        return articles.get(comId);
    };
    var getAllArticles = function () { return Array.from(articles.keys()); };
    var addArticle = function (article) {
        if (articles.has(article.comId)) {
            return;
        }
        lockArticle(article);
        articles.set(article.comId, article);
        if (article.parent !== undefined) {
            addToParent(article.comId, article.parent);
        }
        if (article.gfxId !== undefined) {
            addGfxMapping(article.comId, article.gfxId);
        }
        if (article.children !== undefined) {
            updateParents(article.comId, article.children);
        }
    };
    var removeArticle = function (comId) {
        if (!articles.has(comId)) {
            return;
        }
        var article = articles.get(comId);
        if (article.gfxId !== undefined) {
            removeGfxMapping(article.gfxId);
        }
        if (article.parent !== undefined) {
            removeFromParent(comId, article.parent);
        }
        articles.delete(comId);
    };
    var updateArticleProperty = function (comId, key, value) {
        var _a;
        return updateArticleProperties(comId, (_a = {}, _a[key] = value, _a));
    };
    var updateArticleProperties = function (comId, updates) {
        var article = getArticleByComId(comId);
        if (article === undefined) {
            throw new Error("Can not update unknown article " + comId);
        }
        var articleClone = __assign({}, article);
        for (var property in updates) {
            if (property === "gfxId") {
                updateGfxMapping(comId, updates.gfxId, article.gfxId);
            }
            else if (property === "parent") {
                updateParent(comId, updates.parent, article.parent);
            }
            else if (property === "children") {
                //TODO:
                // updateParents(comId, updates.children);
            }
            articleClone[property] = updates[property];
        }
        lockArticle(articleClone);
        articles.set(comId, articleClone);
    };
    var updateParents = function (parentId, children) {
        var e_1, _a;
        if (children === undefined) {
            return;
        }
        try {
            for (var children_1 = __values(children), children_1_1 = children_1.next(); !children_1_1.done; children_1_1 = children_1.next()) {
                var comId = children_1_1.value;
                addToParent(comId, parentId);
            }
        }
        catch (e_1_1) { e_1 = { error: e_1_1 }; }
        finally {
            try {
                if (children_1_1 && !children_1_1.done && (_a = children_1.return)) _a.call(children_1);
            }
            finally { if (e_1) throw e_1.error; }
        }
    };
    var updateParent = function (comId, newParent, oldParent) {
        if (oldParent === newParent) {
            return;
        }
        if (newParent !== undefined) {
            addToParent(comId, newParent);
        }
        if (oldParent !== undefined) {
            removeFromParent(comId, oldParent);
        }
    };
    var updateGfxMapping = function (comId, newGfxId, oldGfxId) {
        if (newGfxId === oldGfxId) {
            return;
        }
        if (newGfxId !== undefined) {
            addGfxMapping(comId, newGfxId);
        }
        if (oldGfxId !== undefined) {
            removeGfxMapping(oldGfxId);
        }
    };
    var addGfxMapping = function (comId, gfxId) {
        return gfxComIdMap.set(gfxId, comId);
    };
    var removeGfxMapping = function (gfxId) { return gfxComIdMap.delete(gfxId); };
    var addToParent = function (comId, parentId) {
        var parent = articles.get(parentId);
        if (parent === undefined) {
            throw new Error("Can not add \"" + comId + "\" to unknown parent \"" + parentId + "\"");
        }
        if (parent.children.indexOf(comId) > -1) {
            return;
        }
        var newChildren = parent.children.slice(0);
        newChildren.push(comId);
        updateArticleProperty(parentId, "children", newChildren);
    };
    var removeFromParent = function (comId, parentId) {
        var parent = articles.get(parentId);
        if (parent === undefined) {
            return;
        }
        var parentIndex = parent.children.indexOf(comId);
        if (parentIndex === -1) {
            return;
        }
        var newChildren = parent.children.slice(0);
        newChildren.splice(parentIndex, 1);
        updateArticleProperty(parentId, "children", newChildren);
    };
    return {
        addArticle: addArticle,
        removeArticle: removeArticle,
        getArticleByComId: getArticleByComId,
        getArticleByGfxId: getArticleByGfxId,
        getComIdByGfxId: getComIdByGfxId,
        getAllComIds: getAllArticles,
        updateArticleProperties: updateArticleProperties,
        updateArticleProperty: updateArticleProperty,
    };
};
