import { IGXA } from "@intelligentgraphics/igd.core";
import Logger from "../Logger";
import { CatalogManager } from "../CatalogManager";
/**
 * IGXACatalogManager is an implementation of the ICatalogManager interface that
 * uses the IGD.IGXA catalog format as data source.
 */
export class IGXACatalogManager extends CatalogManager {
    constructor(settings) {
        super();
        this.lastID = 0;
        this._settings = settings;
        this.patchData(settings.data);
        this.cache.parseIGXA(settings.data);
        this._image = this._settings.data.Image;
        this._title = this._settings.data.Title;
    }
    static Create(settings) {
        const tCatalogManager = new IGXACatalogManager(settings);
        return Promise.resolve(tCatalogManager);
    }
    /** Returns the class name for identifying instances at runtime */
    getClassName() {
        return "IGXACatalogManager";
    }
    /**
     * Retrieves the addables of an item.
     *
     * @param {string} baseArticleId number of the base article for which addables should be searched.
     * @returns {Promise<IGXA.IArticleItem[]>}
     * @memberof IGXACatalogManager
     */
    getAddables(baseArticleId) {
        const tBaseItem = this.findArticleItem(baseArticleId);
        const tItems = [];
        if (tBaseItem && tBaseItem.Addables) {
            tBaseItem.Addables.forEach(add => {
                const tAddItem = this.findArticleItem(add);
                if (tAddItem) {
                    tItems.push(tAddItem);
                }
            });
        }
        return Promise.resolve(tItems);
    }
    // IGXA-specific methods
    hasFolder(folderId) {
        return (this.findFolderItem(this.Settings.data.Items, folderId) !==
            undefined);
    }
    removeFolder(folderId) {
        function processLevel(items) {
            let tIdx = -1;
            if (items.some((item, idx) => {
                if (item.Type === IGXA.EItemType.Folder) {
                    const tFI = item;
                    if (tFI.ID === folderId) {
                        tIdx = idx;
                        return true;
                    }
                    else {
                        return processLevel(tFI.SubItems || []);
                    }
                }
                return false;
            })) {
                if (tIdx > -1) {
                    items.splice(tIdx, 1);
                }
                return true;
            }
            else {
                return false;
            }
        }
        return processLevel(this.Settings.data.Items);
    }
    removeArticle(articleId, parentFolderId) {
        let tParentSet;
        if (parentFolderId) {
            const tFI = this.findFolderItem(this.Settings.data.Items, parentFolderId);
            if (tFI) {
                tParentSet = tFI.SubItems || [];
            }
        }
        else {
            tParentSet = this.Settings.data.Items;
        }
        if (tParentSet === undefined) {
            Logger.warn("IGXACatalogManager.removeArticle()", "Could not find specified parent folder.");
            return;
        }
        const itemIndex = tParentSet.findIndex(item => (item.Type === IGXA.EItemType.ArticleCom ||
            item.Type === IGXA.EItemType.ArticleGfx) &&
            item.ID === articleId);
        if (itemIndex > -1) {
            tParentSet.splice(itemIndex, 1);
        }
    }
    addFolder(newFolderItem, parentFolderId) {
        if (newFolderItem.ID) {
            if (this.findFolderItem(this.Settings.data.Items, newFolderItem.ID) !== undefined) {
                // folder with this id already exists
                return true;
            }
        }
        else {
            newFolderItem.ID = (++this.lastID).toString();
        }
        let tParentSet;
        if (parentFolderId) {
            const tFI = this.findFolderItem(this.Settings.data.Items, parentFolderId);
            if (tFI) {
                tParentSet = tFI.SubItems || [];
            }
        }
        else {
            tParentSet = this.Settings.data.Items;
        }
        if (tParentSet) {
            tParentSet.push(newFolderItem);
        }
        else {
            Logger.error("IGXACatalogManager.addFolder()", "Could not find specified parent folder.");
            return false;
        }
        return true;
    }
    addArticle(newArticleItem, parentFolderId) {
        let tParentSet;
        if (parentFolderId) {
            const tFI = this.findFolderItem(this.Settings.data.Items, parentFolderId);
            if (tFI) {
                tParentSet = tFI.SubItems || [];
            }
        }
        else {
            tParentSet = this.Settings.data.Items;
        }
        if (tParentSet) {
            tParentSet.push(newArticleItem);
        }
        else {
            Logger.error("IGXACatalogManager.addArticle()", "Could not find specified parent folder.");
            return false;
        }
        return true;
    }
    addItems(items, parentFolderId) {
        let tParentSet;
        if (parentFolderId) {
            const tFI = this.findFolderItem(this.Settings.data.Items, parentFolderId);
            if (tFI) {
                tParentSet = tFI.SubItems || [];
            }
        }
        else {
            tParentSet = this.Settings.data.Items;
        }
        if (tParentSet) {
            items.forEach(item => {
                tParentSet.push(item);
            });
        }
        else {
            Logger.error("IGXACatalogManager.addArticle()", "Could not find specified parent folder.");
            return false;
        }
        return true;
    }
    /** Retrieves the folder item. Synchroneous version of getFolder().
     * @param folderId Internal ID of the folder.
     * @returns The folder item
     */
    getIGXAFolder(folderId) {
        return this.cache.getItemById(folderId);
    }
    /** Retrieves the first article item with given id.
     * @param articleId article id.
     * @returns The article item
     */
    getIGXAArticle(articleId) {
        return this.cache.getItemById(articleId);
    }
    getIGXASet(setId) {
        return this.cache.getItemById(setId);
    }
    /** Retrieves the parent folder item.
     * @param folderId Internal ID of the folder.
     * @returns The parent folder item as Promise
     */
    getIGXAParentFolder(folderId) {
        function checkLevel(parentId, items) {
            let tR;
            items.some(item => {
                if (item.Type === IGXA.EItemType.Folder ||
                    item.Type === IGXA.EItemType.MultiArticle) {
                    const tFI = item;
                    if (tFI.ID === folderId) {
                        tR = parentId;
                        return true;
                    }
                    else {
                        tR = checkLevel(tFI.ID, tFI.SubItems || []);
                        return tR !== undefined;
                    }
                }
                return false;
            });
            return tR;
        }
        const tR = checkLevel(undefined, this.Settings.data.Items);
        if (tR === undefined) {
            return undefined;
        }
        else {
            return this.findFolderItem(this.Settings.data.Items, tR);
        }
    }
    get IGXA() {
        return this.Settings.data;
    }
    // PRIVATE HELPERS:
    getCatalogTextLocalized(text) {
        let tR;
        switch (typeof text) {
            case "string":
                tR = text;
                break;
            case "object":
                if (text.hasOwnProperty("length")) {
                    tR = text;
                }
                else if (text.hasOwnProperty(this.Settings.catalogLocale)) {
                    tR = this.getCatalogTextLocalized(text[this.Settings.catalogLocale]);
                }
                else {
                    tR = "";
                }
                break;
            default:
                tR = "";
        }
        return tR;
    }
    findFolderItem(root, id) {
        let tR;
        root.some(item => {
            if (item.Type === IGXA.EItemType.Folder ||
                item.Type === IGXA.EItemType.MultiArticle) {
                const tFI = item;
                if (tFI.ID === id) {
                    tR = tFI;
                    return true;
                }
                else {
                    tR = this.findFolderItem(tFI.SubItems || [], id);
                    return tR !== undefined;
                }
            }
            return false;
        });
        return tR;
    }
    patchData(data) {
        const idPatchFields = [
            "FolderID",
            "ArticleID",
            "ImpressionID",
        ];
        const recurse = (items) => {
            if (!items) {
                return;
            }
            for (const entry of items) {
                const field = idPatchFields.find(key => entry[key] !== undefined);
                // patch old ids (FolderID, ArticleID) to ID
                if (field) {
                    entry.ID = entry[field];
                    delete entry[field];
                }
                // fix type property
                if (typeof entry.Type === "string") {
                    entry.Type = IGXA.EItemType[entry.Type];
                }
                // fix visibility
                if (entry.Type === IGXA.EItemType.ArticleCom ||
                    entry.Type === IGXA.EItemType.ArticleGfx) {
                    if (entry.Visibility === undefined) {
                        entry.Visibility = IGXA.EItemVisibility.Always;
                    }
                    else if (typeof entry.Visibility === "string") {
                        entry.Visibility =
                            IGXA.EItemVisibility[entry.Visibility];
                    }
                }
                if (!entry["Source"] &&
                    (entry.Type === IGXA.EItemType.ArticleCom ||
                        entry.Type === IGXA.EItemType.ArticleGfx ||
                        entry.Type === IGXA.EItemType.Impression ||
                        entry.Type === IGXA.EItemType.Set)) {
                    entry.Source = this.Settings.sourceId;
                }
                // add ids if they're missing
                if (entry.Type === IGXA.EItemType.Folder ||
                    entry.Type === IGXA.EItemType.MultiArticle) {
                    if (!entry.ID) {
                        entry.ID = (++this.lastID).toString();
                    }
                }
                if ("SubItems" in entry) {
                    recurse(entry.SubItems);
                }
            }
        };
        recurse(data.Items);
    }
    findArticleItem(baseArticleId) {
        let tR;
        function processFolder(items) {
            return items.some(item => {
                if (item.Type === IGXA.EItemType.Folder ||
                    item.Type === IGXA.EItemType.MultiArticle) {
                    return processFolder(item.SubItems || []);
                }
                else {
                    if (item.ID === baseArticleId) {
                        tR = item;
                        return true;
                    }
                }
                return false;
            });
        }
        processFolder(this.Settings.data.Items);
        return tR;
    }
    get Settings() {
        return this._settings;
    }
}
