/*---------------------------------------------------------------------------------------------
 * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
 * See LICENSE.md in the project root for license terms and full copyright notice.
 *--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
 * @module ContentView
 */
import { UiError } from "@itwin/appui-abstract";
import { ConfigurableCreateInfo, ConfigurableUiControlType, } from "../configurableui/ConfigurableUiControl";
import { UiFramework } from "../UiFramework";
import { InternalConfigurableUiManager } from "../configurableui/InternalConfigurableUiManager";
/** Abstract class that can be implemented and specified by frontstage to dynamically construct
 * content group just prior to activating the frontstage.
 * @public
 */
export class ContentGroupProvider {
    /** Allow provider to update any data stored in ContentGroupProps. Typically this may
     * be to remove applicationData entries.
     */
    prepareToSaveProps(contentGroupProps) {
        return contentGroupProps;
    }
    /** Allow provider to update any stored ContentGroupProps be it is to be used to create ContentGroup and layouts.
     * Typically this may be to add applicationData to content entries.
     */
    applyUpdatesToSavedProps(contentGroupProps) {
        return contentGroupProps;
    }
    /** Allow provider to save any content group data before the stage deactivated. */
    async onFrontstageDeactivated() { }
}
/** ContentGroup class. Content Groups define content displayed in content views that are laid out using a [[ContentLayout]].
 * @public
 */
class ContentGroup {
    get id() {
        return this.groupId;
    }
    constructor(contentGroupProps) {
        this._contentControls = new Map();
        this._contentSetMap = new Map();
        this.layout = { ...contentGroupProps.layout };
        this.propsId = contentGroupProps.id;
        // ensure we have a unique groupId for each instance of a content group - this will be used to generate a key in the React controls
        this.groupId = `[${contentGroupProps.id}-${ContentGroup._sId++}]`;
        this.contentPropsList = contentGroupProps.contents;
    }
    /** Gets a [[ContentControl]] from the Content Group based on its [[ContentProps]]. */
    getContentControl(contentProps, _index) {
        // ensure we have a unique control Id for each instance of a content control - this will be used as a key for the React control - see `ContentControl.getKeyedReactNode`
        const id = `${contentProps.id}::${this.groupId}`;
        let contentControl;
        if (!this._contentControls.get(contentProps.id)) {
            let usedClassId = "";
            if (typeof contentProps.classId === "string") {
                if (!this._contentControls.get(contentProps.id) &&
                    UiFramework.controls.isRegistered(contentProps.classId)) {
                    contentControl = UiFramework.controls.create(contentProps.classId, id, contentProps.applicationData, contentProps.id);
                    usedClassId = contentProps.classId;
                }
            }
            else {
                const info = new ConfigurableCreateInfo(contentProps.classId.name, id, contentProps.id);
                contentControl = new contentProps.classId(info, contentProps.applicationData);
                usedClassId = contentProps.classId.name;
            }
            if (contentControl) {
                if (contentControl.getType() !== ConfigurableUiControlType.Content &&
                    contentControl.getType() !== ConfigurableUiControlType.Viewport) {
                    throw new UiError(UiFramework.loggerCategory(this), `getContentControl error: '${usedClassId}' is NOT a ContentControl or ViewportContentControl`);
                }
                contentControl.initialize();
                this._contentControls.set(contentProps.id, contentControl);
            }
        }
        return this._contentControls.get(contentProps.id);
    }
    /** Gets a [[ContentControl]] from the Content Group with a given ID. */
    getContentControlById(id) {
        return this._contentControls.get(id);
    }
    /** Gets the React nodes representing the Content Views in this Content Group. */
    getContentNodes() {
        const contentNodes = new Array();
        this._contentSetMap.clear();
        this.contentPropsList.forEach((contentProps, index) => {
            const control = this.getContentControl(contentProps, index);
            if (control) {
                contentNodes.push(control.reactNode);
                this._contentSetMap.set(control.controlId, control);
            }
        });
        return contentNodes;
    }
    /** Gets the [[ContentControl]] associated with a given React node representing a Content View. */
    getControlFromElement(node) {
        if (this._contentSetMap.size === 0)
            this.getContentNodes();
        if (node && node.key) {
            const key = node.key;
            // key has format `${contentProps.id}::${this.groupId}` which is stored as unique id
            const controlId = key.split("::", 1)[0];
            return this._contentSetMap.get(controlId);
        }
        return undefined;
    }
    /** Refreshes the React nodes representing the Content Views in this Content Group.. */
    refreshContentNodes() {
        this._contentSetMap.clear();
    }
    /** Gets an array of the content controls representing the Content Views. */
    getContentControls() {
        const contentControls = new Array();
        this.contentPropsList.forEach((contentProps, index) => {
            const control = this.getContentControl(contentProps, index);
            if (control) {
                contentControls.push(control);
            }
        });
        return contentControls;
    }
    /** Called when Frontstage is deactivated. */
    onFrontstageDeactivated() {
        this.clearContentControls();
    }
    /** Called when Frontstage is ready. */
    onFrontstageReady() { }
    /** Clears the map of content controls. */
    clearContentControls() {
        this._contentControls.clear();
    }
    /** Creates [[ContentGroupProps]] for JSON purposes
     * @public
     */
    toJSON(contentCallback) {
        const contentGroupProps = {
            id: this.propsId,
            layout: this.layout,
            contents: this.contentPropsList,
        };
        contentGroupProps.contents.forEach((content, index) => {
            if (typeof content.classId !== "string") {
                const classId = InternalConfigurableUiManager.getConstructorClassId(content.classId);
                if (classId !== undefined)
                    content.classId = classId;
                else
                    throw new UiError(UiFramework.loggerCategory(this), `toJSON: ContentControl at index ${index} is NOT registered with a string id`);
                if (contentCallback)
                    contentCallback(content);
            }
        });
        return contentGroupProps;
    }
    /** Gets Viewports from Viewport Content Controls
     * @internal
     */
    getViewports() {
        const contentControls = this.getContentControls();
        const viewports = new Array();
        contentControls.forEach((control) => {
            if (control.isViewport && control.viewport) {
                viewports.push(control.viewport);
            }
            else {
                viewports.push(undefined);
            }
        });
        return viewports;
    }
}
ContentGroup._sId = 0;
export { ContentGroup };
//# sourceMappingURL=ContentGroup.js.map