/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
 * @module UiProvider
 */
import "./DefaultDialogGridContainer.scss";
import classnames from "classnames";
import * as React from "react";
import { PropertyValueFormat, UiLayoutDataProvider, } from "@itwin/appui-abstract";
import { EditorContainer } from "@itwin/components-react";
import { assert, Logger } from "@itwin/core-bentley";
function EditorLabel({ uiDataProvider, item, isLeftmostRecord }) {
    const [isDisabled, setIsDisabled] = React.useState(!!item.isDisabled);
    const displayLabel = React.useMemo(() => {
        return item.property.displayLabel ? item.property.displayLabel : /* istanbul ignore next */ item.property.name;
    }, [item]);
    const propertyId = React.useMemo(() => `dialogItemProperty-${item.property.name}`, [item]);
    // listen for tool sync property events and update the isDisabled state
    React.useEffect(() => {
        const handleSync = (args) => {
            const mySyncItem = args.properties.find((syncItem) => syncItem.propertyName === item.property.name);
            // istanbul ignore next
            if (mySyncItem) {
                setIsDisabled(!!mySyncItem.isDisabled);
            }
        };
        uiDataProvider.onSyncPropertiesChangeEvent.addListener(handleSync);
        return () => {
            uiDataProvider.onSyncPropertiesChangeEvent.removeListener(handleSync);
        };
    }, [uiDataProvider, item]);
    // istanbul ignore next
    const className = classnames("uifw-default-label", isDisabled && "uifw-label-disabled", !!isLeftmostRecord && "uifw-default-narrow-only-display", !isLeftmostRecord && "uifw-default-inline-label");
    return React.createElement("label", { className: className, htmlFor: propertyId },
        displayLabel,
        ":");
}
function PropertyEditor({ uiDataProvider, initialItem, isLock, setFocus }) {
    const getLatestRecordValue = React.useCallback(() => {
        let newRecord = UiLayoutDataProvider.getPropertyRecord(initialItem);
        // istanbul ignore next
        const foundItem = isLock ? uiDataProvider.items.find((item) => { var _a; return ((_a = item.lockProperty) === null || _a === void 0 ? void 0 : _a.property.name) === initialItem.property.name; }) : uiDataProvider.items.find((item) => item.property.name === initialItem.property.name);
        // istanbul ignore else
        if (foundItem) {
            if (isLock) {
                newRecord = newRecord.copyWithNewValue({
                    value: foundItem.lockProperty.value.value,
                    valueFormat: PropertyValueFormat.Primitive,
                });
                newRecord.isDisabled = foundItem.lockProperty.isDisabled;
            }
            else {
                newRecord = newRecord.copyWithNewValue({
                    value: foundItem.value.value,
                    valueFormat: PropertyValueFormat.Primitive,
                });
                newRecord.isDisabled = foundItem.isDisabled;
            }
        }
        return newRecord;
    }, [initialItem, isLock, uiDataProvider.items]);
    const currentRecord = getLatestRecordValue();
    const [propertyRecord, setPropertyRecord] = React.useState(currentRecord);
    // monitor tool for sync UI events
    React.useEffect(() => {
        const handleSync = (args) => {
            const mySyncItem = args.properties.find((syncItem) => syncItem.propertyName === initialItem.property.name);
            // istanbul ignore else
            if (mySyncItem) {
                const newPropertyValue = propertyRecord.copyWithNewValue({
                    value: mySyncItem.value.value,
                    valueFormat: PropertyValueFormat.Primitive,
                    displayValue: mySyncItem.value.displayValue,
                }, mySyncItem.property);
                if (mySyncItem.property) {
                    // istanbul ignore else
                    if (mySyncItem.property.name === mySyncItem.propertyName) {
                        newPropertyValue.isDisabled = mySyncItem.isDisabled;
                        setPropertyRecord(newPropertyValue);
                    }
                    else {
                        Logger.logError("PropertyEditor", `Error trying to replace propertyName=${mySyncItem.propertyName} with property named ${mySyncItem.property.name}`);
                    }
                }
                else {
                    newPropertyValue.isDisabled = mySyncItem.isDisabled;
                    setPropertyRecord(newPropertyValue);
                }
            }
        };
        uiDataProvider.onSyncPropertiesChangeEvent.addListener(handleSync);
        return () => {
            uiDataProvider.onSyncPropertiesChangeEvent.removeListener(handleSync);
        };
    }, [uiDataProvider, propertyRecord, initialItem.property.name]);
    const className = React.useMemo(() => isLock ? "uifw-default-property-lock" : "uifw-default-editor", [isLock]);
    // istanbul ignore next
    const handleCommit = React.useCallback((commit) => {
        // UiLayoutDataProvider supports only primitive property types
        // istanbul ignore next
        assert(commit.newValue.valueFormat === PropertyValueFormat.Primitive && commit.propertyRecord.value.valueFormat === PropertyValueFormat.Primitive);
        const newPropertyValue = propertyRecord.copyWithNewValue(commit.newValue);
        const syncItem = { value: commit.newValue, propertyName: initialItem.property.name, isDisabled: newPropertyValue.isDisabled };
        uiDataProvider.applyUiPropertyChange(syncItem);
        // Now have the uiDataProvider refetch the latest property values from the tool
        uiDataProvider.reloadDialogItems(true);
    }, [initialItem.property.name, propertyRecord, uiDataProvider]);
    // istanbul ignore next
    const handleCancel = () => { };
    return (React.createElement("div", { key: initialItem.property.name, className: className },
        React.createElement(EditorContainer, { key: initialItem.property.name, propertyRecord: propertyRecord, setFocus: setFocus, onCommit: handleCommit, onCancel: handleCancel })));
}
/** Utility methods to generate react ui from DialogRow specs
 * @internal
 */
export class ComponentGenerator {
    constructor(_uiDataProvider) {
        this._uiDataProvider = _uiDataProvider;
    }
    get uiDataProvider() {
        return this._uiDataProvider;
    }
    getEditor(item, isLock = false, setFocus = false) {
        return React.createElement(PropertyEditor, { key: item.property.name, uiDataProvider: this.uiDataProvider, initialItem: item, isLock: isLock, setFocus: setFocus });
    }
    generateRowWithButtonGroupEditors(row, rowIndex) {
        // istanbul ignore else
        if (1 === row.items.length) {
            return (React.createElement("div", { key: row.items[0].property.name, className: "uifw-default-inline-editor-group uifw-default-center-across-width" }, this.getEditor(row.items[0])));
        }
        return (React.createElement("div", { key: rowIndex, className: "uifw-default-inline-editor-group uifw-default-center-across-width" },
            React.createElement("div", { className: "uifw-default-inline-editor-group" }, row.items.map((item) => this.getEditor(item)))));
    }
    generateEntryWithButtonGroupEditors(row, rowIndex) {
        // istanbul ignore else
        if (1 === row.items.length) {
            return ({
                labelNode: "",
                editorNode: React.createElement("div", { key: row.items[0].property.name, className: "uifw-default-inline-editor-group uifw-default-center-across-width" }, this.getEditor(row.items[0])),
            });
        }
        return ({
            labelNode: "",
            editorNode: React.createElement("div", { key: rowIndex, className: "uifw-default-inline-editor-group uifw-default-center-across-width" },
                React.createElement("div", { className: "uifw-default-inline-editor-group" }, row.items.map((item) => this.getEditor(item)))),
        });
    }
    getEditorLabel(item, isLeftmostRecord = false) {
        return React.createElement(EditorLabel, { uiDataProvider: this.uiDataProvider, item: item, isLeftmostRecord: isLeftmostRecord });
    }
    getLeftLockAndLabel(rowItem, multiplePropertiesOnRow) {
        const record = UiLayoutDataProvider.getPropertyRecord(rowItem);
        // istanbul ignore next
        const lockEditor = (UiLayoutDataProvider.hasAssociatedLockProperty(rowItem)) ? this.getEditor(rowItem.lockProperty, true) : null;
        const label = (UiLayoutDataProvider.editorWantsLabel(rowItem)) ? this.getEditorLabel(rowItem) : null;
        const classNames = multiplePropertiesOnRow ? "uifw-default-lock-and-label uifw-default-wide-only-display" : "uifw-default-lock-and-label";
        return (React.createElement("div", { key: `lock-${record.property.name}`, className: classNames },
            lockEditor,
            label));
    }
    getInlineLabelAndEditor(item, isLeftmostRecord) {
        const label = (UiLayoutDataProvider.editorWantsLabel(item)) ? this.getEditorLabel(item, isLeftmostRecord) : null;
        return (React.createElement("div", { key: item.property.name, className: "uifw-default-inline-label-and-editor" },
            label,
            this.getEditor(item)));
    }
    getRowWithMultipleEditors(row) {
        return React.createElement("div", { className: "uifw-default-inline-editor-group" }, row.items.map((item, index) => this.getInlineLabelAndEditor(item, 0 === index)));
    }
    getDivForRow(row) {
        if (1 === row.items.length)
            return this.getEditor(row.items[0]);
        return this.getRowWithMultipleEditors(row);
    }
    getRow(row, rowIndex) {
        if (UiLayoutDataProvider.onlyContainButtonGroupEditors(row)) {
            return this.generateRowWithButtonGroupEditors(row, rowIndex);
        }
        else {
            return (React.createElement(React.Fragment, { key: rowIndex },
                this.getLeftLockAndLabel(row.items[0], row.items.length > 1),
                this.getDivForRow(row)));
        }
    }
    getToolSettingsEntry(row, rowIndex) {
        if (UiLayoutDataProvider.onlyContainButtonGroupEditors(row)) {
            return this.generateEntryWithButtonGroupEditors(row, rowIndex);
        }
        else {
            return ({
                labelNode: this.getLeftLockAndLabel(row.items[0], row.items.length > 1),
                editorNode: this.getDivForRow(row),
            });
        }
    }
    /** ToolSettingsEntries are used by the tool settings bar. */
    getToolSettingsEntries() {
        return this.uiDataProvider.rows.map((row, index) => this.getToolSettingsEntry(row, index));
    }
}
//# sourceMappingURL=ComponentGenerator.js.map