/*---------------------------------------------------------------------------------------------
 * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
 * See LICENSE.md in the project root for license terms and full copyright notice.
 *--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
 * @module Backstage
 */
import { ConditionalBooleanValue, ConditionalStringValue, } from "@itwin/appui-abstract";
import { BeEvent } from "@itwin/core-bentley";
/**
 * Controls backstage items.
 * @internal
 */
export class BackstageItemsManager {
    constructor(items) {
        this._items = [];
        /** Event raised when backstage items are changed.
         * @internal
         */
        this.onItemsChanged = new BeEvent();
        // istanbul ignore else
        if (items)
            this.loadItemsInternal(items, true, false);
    }
    loadItemsInternal(items, processConditions, sendItemChanged) {
        if (processConditions && items) {
            const eventIds = BackstageItemsManager.getSyncIdsOfInterest(items);
            if (0 !== eventIds.length) {
                const { itemsUpdated, updatedItems } = this.internalRefreshAffectedItems(items, new Set(eventIds));
                // istanbul ignore else
                if (itemsUpdated)
                    items = updatedItems;
            }
        }
        this._items = items;
        if (sendItemChanged)
            this.onItemsChanged.raiseEvent({ items });
    }
    /** load items but do not fire onItemsChanged
     * @internal
     */
    loadItems(items) {
        this.loadItemsInternal(items, true, false);
    }
    get items() {
        return this._items;
    }
    set items(items) {
        // istanbul ignore else
        if (items !== this._items)
            this.loadItemsInternal(items, true, true);
    }
    /** @internal */
    add(itemOrItems) {
        let itemsToAdd;
        if (!Array.isArray(itemOrItems))
            itemsToAdd = [itemOrItems];
        else {
            itemsToAdd = itemOrItems.filter((itemToAdd, index) => itemOrItems.findIndex((item) => item.id === itemToAdd.id) === index);
        }
        itemsToAdd = itemsToAdd.filter((itemToAdd) => this._items.find((item) => item.id === itemToAdd.id) === undefined);
        if (itemsToAdd.length === 0)
            return;
        const items = [...this._items, ...itemsToAdd];
        this.items = items;
    }
    /** @internal */
    remove(itemIdOrItemIds) {
        const items = this._items.filter((item) => {
            return Array.isArray(itemIdOrItemIds)
                ? !itemIdOrItemIds.find((itemId) => itemId === item.id)
                : item.id !== itemIdOrItemIds;
        });
        this.items = items;
    }
    /** @internal */
    static getSyncIdsOfInterest(items) {
        const eventIds = new Set();
        items.forEach((item) => {
            for (const [, entry] of Object.entries(item)) {
                if (entry instanceof ConditionalBooleanValue) {
                    entry.syncEventIds.forEach((eventId) => eventIds.add(eventId.toLowerCase()));
                } /* istanbul ignore else */
                else if (entry instanceof ConditionalStringValue) {
                    entry.syncEventIds.forEach((eventId) => eventIds.add(eventId.toLowerCase()));
                }
            }
        });
        return [...eventIds.values()];
    }
    internalRefreshAffectedItems(items, eventIds) {
        // istanbul ignore next
        if (0 === eventIds.size)
            return { itemsUpdated: false, updatedItems: [] };
        let updateRequired = false;
        const newItems = [];
        for (const item of items) {
            const updatedItem = { ...item };
            for (const [, entry] of Object.entries(updatedItem)) {
                if (entry instanceof ConditionalBooleanValue) {
                    // istanbul ignore else
                    if (ConditionalBooleanValue.refreshValue(entry, eventIds))
                        updateRequired = true;
                } /* istanbul ignore else */
                else if (entry instanceof ConditionalStringValue) {
                    // istanbul ignore else
                    if (ConditionalStringValue.refreshValue(entry, eventIds))
                        updateRequired = true;
                }
            }
            newItems.push(updatedItem);
        }
        return { itemsUpdated: updateRequired, updatedItems: newItems };
    }
    refreshAffectedItems(eventIds) {
        // istanbul ignore next
        if (0 === eventIds.size)
            return;
        const { itemsUpdated, updatedItems } = this.internalRefreshAffectedItems(this.items, eventIds);
        // istanbul ignore else
        if (itemsUpdated)
            this.loadItemsInternal(updatedItems, false, true);
    }
}
//# sourceMappingURL=BackstageItemsManager.js.map