"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FormConfiguration = exports.ContainerSectionDiv = exports.PinnedNotifyDiv = void 0;
const tslib_1 = require("tslib");
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = tslib_1.__importDefault(require("react"));
const react_beautiful_dnd_1 = require("react-beautiful-dnd");
const styled_components_1 = tslib_1.__importDefault(require("styled-components"));
const core_1 = require("@material-ui/core");
const DataUtilities_1 = require("@appglue/common/dist/Common/DataUtilities");
const FormDesignConstants_1 = require("./Utilities/FormDesignConstants");
const RegisterUIControl_1 = require("./Utilities/RegisterUIControl");
const PropertyEditorInteger_1 = require("../CommonUI/PropertyEditing/PropertyEditorInteger");
const PropertyEditorBoolean_1 = require("../CommonUI/PropertyEditing/PropertyEditorBoolean");
const PropertyEditorSelect_1 = require("../CommonUI/PropertyEditing/PropertyEditorSelect");
const PropertyEditorColor_1 = require("../CommonUI/PropertyEditing/PropertyEditorColor");
const XStackContainer_1 = require("./Containers/XStackContainer");
const TextSelectionButtonGroups_1 = require("../CommonUI/PropertyEditing/TextSelectionButtonGroups");
const PinIcon_1 = require("../CommonUI/Icon/PinIcon");
const ScrollIcon_1 = require("../CommonUI/Icon/ScrollIcon");
const XContainerDesignWrapper_1 = require("./Utilities/XContainerDesignWrapper");
const FormContext_1 = require("./Utilities/FormContext");
const CommonStyles_1 = require("../CommonUI/CommonStyles");
const registerElements_1 = require("./registerElements");
const MultiExecutable_1 = require("@appglue/common/dist/Common/Execution/MultiExecutable");
const ExecutionData_1 = require("@appglue/common/dist/Common/Data/ExecutionData/ExecutionData");
const ButtonFormControl_1 = require("./Controls/Web/ButtonFormControl");
const LinkFormControl_1 = require("./Controls/Web/LinkFormControl");
const FormRule_1 = require("./Structure/FormRule");
const BooleanDataDefinition_1 = require("@appglue/common/dist/Common/Data/Definitions/BooleanDataDefinition");
const DataDefinition_1 = require("@appglue/common/dist/Common/Data/DataDefinition");
const IDesignValidationProvider_1 = require("@appglue/common/dist/Common/IDesignValidationProvider");
const FormTestResult_1 = require("./Structure/FormTestResult");
const EventLog_1 = require("@appglue/common/dist/Common/Event/EventLog");
const ExecutableReturnPromise_1 = require("@appglue/common/dist/Common/Execution/ExecutableReturnPromise");
const MultiExecutableWithFormHost_1 = require("@appglue/common/dist/Common/Execution/MultiExecutableWithFormHost");
const IFormHost_1 = require("@appglue/common/dist/Common/Execution/IFormHost");
const FormRuntime_1 = require("./FormRuntime");
const AutoBind_1 = require("@appglue/common/dist/Common/AutoBind");
const ExpressionConfiguration_1 = require("@appglue/common/dist/Expressions/ExpressionConfiguration");
const UIStyleConstants_1 = require("@appglue/common/dist/Common/UIStyleConstants");
exports.PinnedNotifyDiv = (0, styled_components_1.default)("div") `
    position: absolute;
    right: calc(100% + ${(props) => (props.moveRightPX ? props.moveRightPX + 34 : 34)}px);
    border-right: solid ${(props) => props.borderWidth || 2}px ${(props) => props.color || "#1873B9"};
    display: flex;
    align-items: center;
    height: 100%;
`;
exports.ContainerSectionDiv = (0, styled_components_1.default)("div") `
  position: ${(props) => (props.pinned ? "relative" : "static")};
`;
class FormConfiguration extends MultiExecutableWithFormHost_1.MultiExecutableWithFormHost {
    _id = DataUtilities_1.DataUtilities.generateUniqueId();
    title;
    designFormWidth = FormDesignConstants_1.FormDesignConstants.DESIGN_WIDTH;
    // setting this to -1 means not set
    runtimeWidth = FormDesignConstants_1.FormDesignConstants.RUNTIME_WIDTH;
    gapBetweenContainers = FormDesignConstants_1.FormDesignConstants.GAP_BETWEEN_CONTAINERS;
    formMargin = FormDesignConstants_1.FormDesignConstants.FORM_MARGIN;
    defaultInnerContainerMargin = FormDesignConstants_1.FormDesignConstants.INNER_CONTAINER_MARGIN;
    defaultInnerColumnMargin = FormDesignConstants_1.FormDesignConstants.INNER_COLUMN_MARGIN;
    defaultInterControlSpacing = FormDesignConstants_1.FormDesignConstants.INTER_CONTROL_SPACING;
    // first container
    doNotScrollLastContainerOnForm = false;
    doNotScrollFirstContainerOnForm = false;
    defaultShowContainerBorder = FormDesignConstants_1.FormDesignConstants.SHOW_CONTAINER_BORDER;
    defaultContainerBorderRadius = FormDesignConstants_1.FormDesignConstants.CONTAINER_BORDER_RADIOUS;
    defaultContainerBorderWidth = FormDesignConstants_1.FormDesignConstants.CONTAINER_BORDER_WIDTH;
    defaultContainerBorderColor = FormDesignConstants_1.FormDesignConstants.CONTAINER_BORDER_COLOR;
    defaultContainerBorderStyle = FormDesignConstants_1.FormDesignConstants.CONTAINER_BORDER_STYLE;
    showLinesBetweenContainers = false;
    defaultLineBetweenContainerWidth = FormDesignConstants_1.FormDesignConstants.CONTAINER_BORDER_WIDTH;
    defaultLineBetweenContainerColor = FormDesignConstants_1.FormDesignConstants.CONTAINER_BORDER_COLOR;
    defaultLineBetweenContainerStyle = FormDesignConstants_1.FormDesignConstants.CONTAINER_BORDER_STYLE;
    formBackgroundColor = FormDesignConstants_1.FormDesignConstants.FORM_BACKGROUND_COLOR;
    defaultContainerBackgroundColor = FormDesignConstants_1.FormDesignConstants.CONTAINER_BACKGROUND_COLOR;
    defaultTextStyle = FormDesignConstants_1.FormDesignConstants.DEFAULT_TEXT_STYLE;
    defaultTextSize = FormDesignConstants_1.FormDesignConstants.DEFAULT_TEXT_SIZE;
    defaultButtonSize = FormDesignConstants_1.FormDesignConstants.DEFAULT_BUTTON_SIZE;
    defaultLinkUnderline = FormDesignConstants_1.FormDesignConstants.DEFAULT_LINK_UNDERLINE;
    defaultLinkType = FormDesignConstants_1.FormDesignConstants.DEFAULT_LINK_TYPE;
    containers = [];
    // this is either designer or runtime form
    _formContext = null;
    constructor(container) {
        super();
        // ensure controls are registered.
        registerElements_1.RegisterFormElements.doRegistration();
        if (!this._formContext) {
            this._formContext = new FormContext_1.FormContext(this);
            this._formContext.mode = FormDesignConstants_1.FormMode.Runtime;
        }
        this.containers = container ?? [];
        if (this.containers) {
            for (let bc of this.containers) {
                if (this._formContext)
                    bc.setFormContext(this._formContext);
            }
        }
    }
    _rules = [];
    get rules() {
        return this._rules;
    }
    set rules(rules) {
        this._rules = rules;
        for (let rule of rules) {
            rule.expression.inputData = () => {
                return this.getFormDatDefinition();
            };
            rule.expression.executionResult = new BooleanDataDefinition_1.BooleanDataDefinition();
        }
    }
    getFormContext() {
        return this._formContext;
    }
    setFormContext(value) {
        if (!value)
            throw new Error("cannot set form context to null (Form Config)");
        this._formContext = value;
        if (value) {
            for (let cont of this.containers) {
                cont.setFormContext(value);
            }
        }
    }
    add(container, index) {
        // set control order
        if (index === undefined || index === null) {
            this.containers.push(container);
        }
        else {
            this.containers.splice(index, 0, container);
        }
        if (this.getFormContext()) {
            container.setFormContext(this.getFormContext());
        }
    }
    remove(control) {
        const index = this.containers.indexOf(control, 0);
        if (index > -1) {
            this.containers.splice(index, 1);
        }
        else {
            for (let cont of this.containers) {
                cont.remove(control);
            }
        }
    }
    setOrder(id, order) {
        let controlToMove;
        for (let c of this.containers) {
            if (c.id === id) {
                controlToMove = c;
            }
        }
        if (controlToMove) {
            this.remove(controlToMove);
            this.add(controlToMove, order);
        }
    }
    getContainers() {
        return this.containers;
    }
    getMode() {
        return this.getFormContext()?.mode ?? FormDesignConstants_1.FormMode.Runtime;
    }
    getWidth() {
        return this.getMode() === FormDesignConstants_1.FormMode.Runtime && !!this.runtimeWidth ? this.runtimeWidth : this.designFormWidth;
    }
    getContentWidth() {
        const formWidth = this.getWidth();
        return formWidth - 2 * this.formMargin;
    }
    isDevice() {
        return ([
            FormDesignConstants_1.FormDesignConstants.FORM_MODE_TABLET_VERTICAL,
            FormDesignConstants_1.FormDesignConstants.FORM_MODE_TABLET_HORIZONTAL,
            FormDesignConstants_1.FormDesignConstants.FORM_MODE_PHONE_VERTICAL,
            FormDesignConstants_1.FormDesignConstants.FORM_MODE_PHONE_HORIZONTAL,
        ].indexOf(this.getFormContext()?.designConfig?.mode || "") >= 0);
    }
    getFormDatDefinition() {
        const ruleDataDef = new DataDefinition_1.DataDefinition();
        const dataDef = this.getInputDefinition();
        const formDataDefFeilds = this.getAllFormData();
        ruleDataDef.fields = [...dataDef.fields, ...formDataDefFeilds];
        const formValue = this.getFormContext()?.getFormData().values;
        if (formValue) {
            ruleDataDef.value = { ...dataDef.value, ...formValue };
        }
        else {
            ruleDataDef.value = dataDef.value;
        }
        return ruleDataDef;
    }
    render() {
        // if there are no containers, ensure we have at least one (stack)
        if (this.containers.length === 0) {
            //	console.log('adding empty xstack')
            this.add(new XStackContainer_1.XStackContainer());
        }
        let mode = this.getMode();
        const formStyles = {
            padding: this.formMargin,
            backgroundColor: this.formBackgroundColor ? this.formBackgroundColor : UIStyleConstants_1.UIStyleConstants.WHITE_COLOR,
            position: "relative",
            minHeight: 2 * this.gapBetweenContainers + 75,
        };
        let firstContainer = null;
        let lastContainer = null;
        let scrollableContrainers = this.containers.map((c) => c);
        if (this.doNotScrollFirstContainerOnForm) {
            firstContainer = this.containers[0];
            scrollableContrainers.splice(0, 1);
        }
        if (this.doNotScrollLastContainerOnForm && this.containers.length > 1) {
            lastContainer = this.containers[this.containers.length - 1];
            scrollableContrainers.splice(-1);
        }
        const pinned = (this.doNotScrollFirstContainerOnForm || this.doNotScrollLastContainerOnForm) &&
            scrollableContrainers.length > 0;
        const gap = this.gapBetweenContainers / 2;
        if (mode === FormDesignConstants_1.FormMode.LayoutDesign) {
            return ((0, jsx_runtime_1.jsx)("div", { className: "App", style: formStyles, children: (0, jsx_runtime_1.jsx)(react_beautiful_dnd_1.Droppable, { droppableId: FormDesignConstants_1.FormDesignConstants.LAYOUT_FORM_KEY_NAME, children: (provided) => {
                        return ((0, jsx_runtime_1.jsx)("div", { ref: provided.innerRef, style: { position: "relative", minHeight: 75 }, ...provided.droppableProps, children: (0, jsx_runtime_1.jsxs)(CommonStyles_1.RowDiv, { colGap: gap, hasOverflow: !(this.doNotScrollLastContainerOnForm ||
                                    this.doNotScrollFirstContainerOnForm), children: [firstContainer && ((0, jsx_runtime_1.jsxs)(exports.ContainerSectionDiv, { pinned: true, children: [(0, jsx_runtime_1.jsx)(exports.PinnedNotifyDiv, { moveRightPX: this.formMargin, children: (0, jsx_runtime_1.jsx)(core_1.IconButton, { color: "primary", children: (0, jsx_runtime_1.jsx)(PinIcon_1.PinIcon, {}) }) }), (0, jsx_runtime_1.jsx)(CommonStyles_1.ContainerDiv, { colGap: gap, children: (0, jsx_runtime_1.jsx)(XContainerDesignWrapper_1.XContainerDesignWrapper, { id: firstContainer.id, index: 0, innerComponent: firstContainer, editContext: this.getFormContext() }) })] })), (0, jsx_runtime_1.jsxs)(exports.ContainerSectionDiv, { pinned: pinned, children: [pinned && ((0, jsx_runtime_1.jsx)(exports.PinnedNotifyDiv, { color: "#F65C66", moveRightPX: this.formMargin, children: (0, jsx_runtime_1.jsx)(core_1.IconButton, { color: "secondary", children: (0, jsx_runtime_1.jsx)(ScrollIcon_1.ScrollIcon, {}) }) })), scrollableContrainers.map((c, i) => {
                                                return ((0, jsx_runtime_1.jsxs)(react_1.default.Fragment, { children: [this.showLinesBetweenContainers &&
                                                            (firstContainer || i !== 0) && ((0, jsx_runtime_1.jsx)(CommonStyles_1.ContainerDivider, { "data-testid": "line-between-containers", lineColorBetweenContainers: this.defaultLineBetweenContainerColor, lineStyleBetweenContrainers: this.defaultLineBetweenContainerStyle, lineWidthBetweenContainers: this.defaultLineBetweenContainerWidth, colGap: gap })), (0, jsx_runtime_1.jsx)(CommonStyles_1.ContainerDiv, { colGap: gap, children: (0, jsx_runtime_1.jsx)(XContainerDesignWrapper_1.XContainerDesignWrapper, { id: c.id, index: i, innerComponent: c, editContext: this.getFormContext() }) })] }, c.id));
                                            })] }), lastContainer && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [this.showLinesBetweenContainers && ((0, jsx_runtime_1.jsx)(CommonStyles_1.ContainerDivider, { "data-testid": "line-between-containers", lineColorBetweenContainers: this.defaultLineBetweenContainerColor, lineStyleBetweenContrainers: this.defaultLineBetweenContainerStyle, lineWidthBetweenContainers: this.defaultLineBetweenContainerWidth, colGap: gap })), (0, jsx_runtime_1.jsxs)(exports.ContainerSectionDiv, { pinned: true, children: [(0, jsx_runtime_1.jsx)(exports.PinnedNotifyDiv, { moveRightPX: this.formMargin, children: (0, jsx_runtime_1.jsx)(core_1.IconButton, { color: "primary", children: (0, jsx_runtime_1.jsx)(PinIcon_1.PinIcon, {}) }) }), (0, jsx_runtime_1.jsx)(CommonStyles_1.ContainerDiv, { colGap: gap, children: (0, jsx_runtime_1.jsx)(XContainerDesignWrapper_1.XContainerDesignWrapper, { id: lastContainer.id, index: this.containers.length - 1, innerComponent: lastContainer, editContext: this.getFormContext() }) })] })] })), provided.placeholder] }) }));
                    } }, "baselayoutform") }, "baseformcontainer"));
        }
        else if ((this.isDevice() || mode === FormDesignConstants_1.FormMode.Runtime) &&
            (this.doNotScrollLastContainerOnForm || this.doNotScrollFirstContainerOnForm) &&
            this.containers.length > 0) {
            formStyles.height = "100%";
            return ((0, jsx_runtime_1.jsx)("div", { className: "App", style: formStyles, children: (0, jsx_runtime_1.jsxs)(CommonStyles_1.RowDiv, { colGap: gap, style: { flexFlow: "column", maxHeight: "100%", overflow: "hidden", display: "flex" }, children: [firstContainer && ((0, jsx_runtime_1.jsx)(CommonStyles_1.ContainerDiv, { colGap: gap, children: (0, jsx_runtime_1.jsx)(XContainerDesignWrapper_1.XContainerDesignWrapper, { id: firstContainer.id, index: 0, innerComponent: firstContainer, editContext: this.getFormContext() }) })), (0, jsx_runtime_1.jsx)("div", { style: {
                                flex: 1,
                                overflowY: "auto",
                                overflowX: "hidden",
                                position: pinned ? "relative" : "static",
                            }, "data-testid": "no-pinned-section", children: scrollableContrainers.map((c, i) => {
                                return ((0, jsx_runtime_1.jsxs)(react_1.default.Fragment, { children: [this.showLinesBetweenContainers && (firstContainer || i !== 0) && ((0, jsx_runtime_1.jsx)(CommonStyles_1.ContainerDivider, { "data-testid": "line-between-containers", lineColorBetweenContainers: this.defaultLineBetweenContainerColor, lineStyleBetweenContrainers: this.defaultLineBetweenContainerStyle, lineWidthBetweenContainers: this.defaultLineBetweenContainerWidth, colGap: gap })), (0, jsx_runtime_1.jsx)(CommonStyles_1.ContainerDiv, { colGap: gap, children: (0, jsx_runtime_1.jsx)(XContainerDesignWrapper_1.XContainerDesignWrapper, { id: c.id, index: firstContainer ? i + 1 : i, innerComponent: c, editContext: this.getFormContext() }) })] }, c.id));
                            }) }), lastContainer && ((0, jsx_runtime_1.jsx)(CommonStyles_1.ContainerDiv, { colGap: gap, children: (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [this.showLinesBetweenContainers && ((0, jsx_runtime_1.jsx)(CommonStyles_1.ContainerDivider, { "data-testid": "line-between-containers", lineColorBetweenContainers: this.defaultLineBetweenContainerColor, lineStyleBetweenContrainers: this.defaultLineBetweenContainerStyle, lineWidthBetweenContainers: this.defaultLineBetweenContainerWidth, colGap: gap })), (0, jsx_runtime_1.jsx)(XContainerDesignWrapper_1.XContainerDesignWrapper, { id: lastContainer.id, index: this.containers.length - 1, innerComponent: lastContainer, editContext: this.getFormContext() })] }) }))] }) }, "form"));
        }
        else {
            return ((0, jsx_runtime_1.jsx)("div", { className: "App", style: formStyles, children: (0, jsx_runtime_1.jsxs)(CommonStyles_1.RowDiv, { colGap: gap, hasOverflow: mode !== FormDesignConstants_1.FormMode.Runtime &&
                        !(this.doNotScrollLastContainerOnForm || this.doNotScrollFirstContainerOnForm), children: [firstContainer && ((0, jsx_runtime_1.jsxs)(exports.ContainerSectionDiv, { pinned: true, "data-testid": "pin-first-container", children: [(0, jsx_runtime_1.jsx)(exports.PinnedNotifyDiv, { moveRightPX: this.formMargin, children: (0, jsx_runtime_1.jsx)(core_1.IconButton, { color: "primary", children: (0, jsx_runtime_1.jsx)(PinIcon_1.PinIcon, {}) }) }), (0, jsx_runtime_1.jsx)(CommonStyles_1.ContainerDiv, { colGap: gap, children: (0, jsx_runtime_1.jsx)(XContainerDesignWrapper_1.XContainerDesignWrapper, { id: firstContainer.id, index: 0, innerComponent: firstContainer, editContext: this.getFormContext() }) })] })), (0, jsx_runtime_1.jsxs)(exports.ContainerSectionDiv, { pinned: pinned, children: [pinned && ((0, jsx_runtime_1.jsx)(exports.PinnedNotifyDiv, { color: "#F65C66", moveRightPX: this.formMargin, "data-testid": "pin-middle-container", children: (0, jsx_runtime_1.jsx)(core_1.IconButton, { color: "secondary", children: (0, jsx_runtime_1.jsx)(ScrollIcon_1.ScrollIcon, {}) }) })), scrollableContrainers.map((c, i) => {
                                    return ((0, jsx_runtime_1.jsxs)(react_1.default.Fragment, { children: [this.showLinesBetweenContainers && (firstContainer || i !== 0) && ((0, jsx_runtime_1.jsx)(CommonStyles_1.ContainerDivider, { "data-testid": "line-between-containers", lineColorBetweenContainers: this.defaultLineBetweenContainerColor, lineStyleBetweenContrainers: this.defaultLineBetweenContainerStyle, lineWidthBetweenContainers: this.defaultLineBetweenContainerWidth, colGap: gap })), (0, jsx_runtime_1.jsx)(CommonStyles_1.ContainerDiv, { colGap: gap, children: (0, jsx_runtime_1.jsx)(XContainerDesignWrapper_1.XContainerDesignWrapper, { id: c.id, index: i, innerComponent: c, editContext: this.getFormContext() }) })] }, c.id));
                                })] }), lastContainer && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [this.showLinesBetweenContainers && ((0, jsx_runtime_1.jsx)(CommonStyles_1.ContainerDivider, { "data-testid": "line-between-containers", lineColorBetweenContainers: this.defaultLineBetweenContainerColor, lineStyleBetweenContrainers: this.defaultLineBetweenContainerStyle, lineWidthBetweenContainers: this.defaultLineBetweenContainerWidth, colGap: gap })), (0, jsx_runtime_1.jsxs)(exports.ContainerSectionDiv, { pinned: true, "data-testid": "pin-last-container", children: [(0, jsx_runtime_1.jsx)(exports.PinnedNotifyDiv, { moveRightPX: this.formMargin, children: (0, jsx_runtime_1.jsx)(core_1.IconButton, { color: "primary", children: (0, jsx_runtime_1.jsx)(PinIcon_1.PinIcon, {}) }) }), (0, jsx_runtime_1.jsx)(CommonStyles_1.ContainerDiv, { colGap: gap, children: (0, jsx_runtime_1.jsx)(XContainerDesignWrapper_1.XContainerDesignWrapper, { id: lastContainer.id, index: this.containers.length - 1, innerComponent: lastContainer, editContext: this.getFormContext() }) })] })] }))] }) }, "form"));
        }
    }
    find(id) {
        if (!this.containers)
            return null;
        for (let cont of this.containers) {
            if (cont.id === id)
                return cont;
            let res = cont.find(id);
            if (res)
                return res;
        }
        return null;
    }
    getAllControls() {
        let controls;
        controls = [];
        for (let container of this.containers) {
            controls.push(...container.getControls());
        }
        return controls;
    }
    getStorageData() {
        let retData = super.getStorageData();
        retData = DataUtilities_1.DataUtilities.addStorageData(this, retData, "_id", "title", "designFormWidth", "runtimeWidth", "gapBetweenContainers", "formMargin", "defaultInnerContainerMargin", "defaultInnerColumnMargin", "defaultInterControlSpacing", "doNotScrollLastContainerOnForm", "doNotScrollFirstContainerOnForm", "defaultShowContainerBorder", "defaultContainerBorderRadius", "defaultContainerBorderWidth", "defaultContainerBorderColor", "defaultContainerBorderStyle", "showLinesBetweenContainers", "defaultLineBetweenContainerWidth", "defaultLineBetweenContainerColor", "defaultLineBetweenContainerStyle", "formBackgroundColor", "defaultContainerBackgroundColor", "defaultTextStyle", "defaultTextSize", "defaultButtonSize", "defaultLinkUnderline", "defaultLinkType");
        let containers = [];
        for (let container of this.containers) {
            containers.push(container.getStorageData());
        }
        Reflect.set(retData, "__containers", containers);
        let rules = [];
        for (let r of this._rules) {
            rules.push(r.getStorageData());
        }
        Reflect.set(retData, "rules", rules);
        return retData;
    }
    setStorageData(data) {
        super.setStorageData(data);
        DataUtilities_1.DataUtilities.setStorageData(this, data, "_id", "title", "designFormWidth", "runtimeWidth", "gapBetweenContainers", "formMargin", "defaultInnerContainerMargin", "defaultInnerColumnMargin", "defaultInterControlSpacing", "doNotScrollLastContainerOnForm", "doNotScrollFirstContainerOnForm", "defaultShowContainerBorder", "defaultContainerBorderRadius", "defaultContainerBorderWidth", "defaultContainerBorderColor", "defaultContainerBorderStyle", "showLinesBetweenContainers", "defaultLineBetweenContainerWidth", "defaultLineBetweenContainerColor", "defaultLineBetweenContainerStyle", "formBackgroundColor", "defaultContainerBackgroundColor", "defaultTextStyle", "defaultTextSize", "defaultButtonSize", "defaultLinkUnderline", "defaultLinkType");
        this.containers = [];
        let containerArray = Reflect.get(data, "__containers");
        let editContext = this.getFormContext();
        if (containerArray && containerArray instanceof Array && containerArray.length !== 0) {
            for (let container of containerArray) {
                let typeName = Reflect.get(container, "__type");
                if (typeName) {
                    let registeredControl = RegisterUIControl_1.UIControlRegistration[typeName];
                    let val = new registeredControl.prototype.constructor();
                    // @ts-ignore
                    let control = val;
                    if (editContext)
                        control.setFormContext(editContext);
                    control.setStorageData(container);
                    this.containers.push(control);
                }
            }
        }
        let ruleData = Reflect.get(data, "rules");
        for (let r of ruleData) {
            let ruleData = new FormRule_1.FormRule(new ExpressionConfiguration_1.ExpressionConfiguration());
            ruleData.setStorageData(r);
            this.rules.push(ruleData);
        }
    }
    refreshDesigner = () => {
        if (this._formContext) {
            this._formContext?.refreshDesigner();
        }
    };
    renderEditUI() {
        return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(PropertyEditorBoolean_1.PropertyEditorBoolean, { editObject: this, label: "Layout Borders", propertyName: "defaultShowContainerBorder", updateCallback: this.refreshDesigner }), (0, jsx_runtime_1.jsxs)(core_1.Collapse, { in: this.defaultShowContainerBorder, children: [(0, jsx_runtime_1.jsx)(PropertyEditorInteger_1.PropertyEditorInteger, { editObject: this, label: "Borders Width", propertyName: "defaultContainerBorderWidth", updateCallback: this.refreshDesigner }), (0, jsx_runtime_1.jsx)(PropertyEditorInteger_1.PropertyEditorInteger, { editObject: this, label: "Borders Radius", propertyName: "defaultContainerBorderRadius", updateCallback: this.refreshDesigner }), (0, jsx_runtime_1.jsx)(PropertyEditorColor_1.PropertyEditorColor, { editObject: this, label: "Borders Color", propertyName: "defaultContainerBorderColor", updateCallback: this.refreshDesigner, parentDefaultValue: FormDesignConstants_1.FormDesignConstants.FORM_BACKGROUND_COLOR }), (0, jsx_runtime_1.jsx)(PropertyEditorSelect_1.PropertyEditorSelect, { editObject: this, label: "Borders Style", propertyName: "defaultContainerBorderStyle", updateCallback: this.refreshDesigner, options: FormDesignConstants_1.FormDesignConstants.BORDER_STYLES })] }), (0, jsx_runtime_1.jsx)(PropertyEditorColor_1.PropertyEditorColor, { editObject: this, label: "Form Color", propertyName: "formBackgroundColor", updateCallback: this.refreshDesigner, parentDefaultValue: FormDesignConstants_1.FormDesignConstants.FORM_BACKGROUND_COLOR }), (0, jsx_runtime_1.jsx)(core_1.Typography, { color: "textSecondary", display: "block", variant: "caption", style: { marginTop: FormDesignConstants_1.FormDesignConstants.FORM_SECTION_MARGIN }, children: "Pinned Sections" }), (0, jsx_runtime_1.jsx)(core_1.Divider, {}), (0, jsx_runtime_1.jsx)(PropertyEditorBoolean_1.PropertyEditorBoolean, { label: "Pin First Container", editObject: this, propertyName: "doNotScrollFirstContainerOnForm", updateCallback: this.refreshDesigner }), (0, jsx_runtime_1.jsx)(PropertyEditorBoolean_1.PropertyEditorBoolean, { label: "Pin Last Container", editObject: this, propertyName: "doNotScrollLastContainerOnForm", updateCallback: this.refreshDesigner }), (0, jsx_runtime_1.jsx)(core_1.Typography, { color: "textSecondary", display: "block", variant: "caption", style: { marginTop: FormDesignConstants_1.FormDesignConstants.FORM_SECTION_MARGIN }, children: "Form Size" }), (0, jsx_runtime_1.jsx)(core_1.Divider, {}), (0, jsx_runtime_1.jsx)(PropertyEditorInteger_1.PropertyEditorInteger, { label: "Design Form Width", editObject: this, propertyName: "designFormWidth", updateCallback: this.refreshDesigner }), (0, jsx_runtime_1.jsx)(PropertyEditorInteger_1.PropertyEditorInteger, { label: "Runtime Width", editObject: this, propertyName: "runtimeWidth", updateCallback: this.refreshDesigner }), (0, jsx_runtime_1.jsx)(core_1.Typography, { color: "textSecondary", display: "block", variant: "caption", style: { marginTop: FormDesignConstants_1.FormDesignConstants.FORM_SECTION_MARGIN }, children: "Spacing" }), (0, jsx_runtime_1.jsx)(core_1.Divider, {}), (0, jsx_runtime_1.jsx)(PropertyEditorInteger_1.PropertyEditorInteger, { label: "Between Layouts", editObject: this, propertyName: "gapBetweenContainers", updateCallback: this.refreshDesigner, parentDefaultValue: FormDesignConstants_1.FormDesignConstants.GAP_BETWEEN_CONTAINERS }), (0, jsx_runtime_1.jsx)(PropertyEditorBoolean_1.PropertyEditorBoolean, { editObject: this, label: "Line Between Containers", propertyName: "showLinesBetweenContainers", updateCallback: this.refreshDesigner }), (0, jsx_runtime_1.jsxs)(core_1.Collapse, { in: this.showLinesBetweenContainers, children: [(0, jsx_runtime_1.jsx)(PropertyEditorInteger_1.PropertyEditorInteger, { editObject: this, label: "Line Width", propertyName: "defaultLineBetweenContainerWidth", updateCallback: this.refreshDesigner }), (0, jsx_runtime_1.jsx)(PropertyEditorColor_1.PropertyEditorColor, { editObject: this, label: "Line Color", propertyName: "defaultLineBetweenContainerColor", updateCallback: this.refreshDesigner }), (0, jsx_runtime_1.jsx)(PropertyEditorSelect_1.PropertyEditorSelect, { editObject: this, label: "Line Style", propertyName: "defaultLineBetweenContainerStyle", updateCallback: this.refreshDesigner, options: FormDesignConstants_1.FormDesignConstants.BORDER_STYLES })] }), (0, jsx_runtime_1.jsx)(PropertyEditorInteger_1.PropertyEditorInteger, { label: "Around Form", editObject: this, propertyName: "formMargin", updateCallback: this.refreshDesigner }), (0, jsx_runtime_1.jsx)(core_1.Typography, { color: "textSecondary", display: "block", variant: "caption", style: { marginTop: FormDesignConstants_1.FormDesignConstants.FORM_SECTION_MARGIN }, children: "Default Text Field Style" }), (0, jsx_runtime_1.jsx)(core_1.Divider, {}), (0, jsx_runtime_1.jsx)(TextSelectionButtonGroups_1.PropertyEditorTextStyleSelection, { updateCallback: this.refreshDesigner, propertyName: "defaultTextStyle", editObject: this }), (0, jsx_runtime_1.jsx)(TextSelectionButtonGroups_1.PropertyEditorTextSizeSelection, { updateCallback: this.refreshDesigner, propertyName: "defaultTextSize", editObject: this }), (0, jsx_runtime_1.jsx)(core_1.Typography, { color: "textSecondary", display: "block", variant: "caption", style: { marginTop: FormDesignConstants_1.FormDesignConstants.FORM_SECTION_MARGIN }, children: "Defaults" }), (0, jsx_runtime_1.jsx)(core_1.Divider, {}), (0, jsx_runtime_1.jsx)(PropertyEditorInteger_1.PropertyEditorInteger, { label: "Container Inner Margin", editObject: this, propertyName: "defaultInnerContainerMargin", updateCallback: this.refreshDesigner }), (0, jsx_runtime_1.jsx)(PropertyEditorInteger_1.PropertyEditorInteger, { label: "Column Inner Margin", editObject: this, propertyName: "defaultInnerColumnMargin", updateCallback: this.refreshDesigner }), (0, jsx_runtime_1.jsx)(PropertyEditorInteger_1.PropertyEditorInteger, { label: "Space Between Controls", editObject: this, propertyName: "defaultInterControlSpacing", updateCallback: this.refreshDesigner }), (0, jsx_runtime_1.jsx)(PropertyEditorColor_1.PropertyEditorColor, { editObject: this, label: "Container Color", propertyName: "defaultContainerBackgroundColor", updateCallback: this.refreshDesigner, parentDefaultValue: FormDesignConstants_1.FormDesignConstants.CONTAINER_BACKGROUND_COLOR })] }));
    }
    // this is all the form data, both input and output
    getAllFormData() {
        const controls = this.getAllControls();
        const formDataDefs = [];
        for (const control of controls) {
            const controlDataDef = control.getAddedData();
            if (controlDataDef) {
                if (Array.isArray(controlDataDef)) {
                    formDataDefs.concat(controlDataDef);
                }
                else {
                    formDataDefs.push(controlDataDef);
                }
            }
        }
        return formDataDefs;
        // todo: needs to be completed
        // - input data
        // - all controls, add the data
        //  - if a value is not a root value, can eliminate it here.  like person.name.
    }
    getOutcomes() {
        let result = [];
        for (let c of this.containers) {
            for (let cnt of c.getControls()) {
                if (cnt instanceof ButtonFormControl_1.ButtonFormControl) {
                    // should look at all buttons, and return.  later we will gather the data we need for each button
                    result.push(new MultiExecutable_1.MultiExecutableOutputDefinition(cnt.getOutcomeName(), []));
                }
                else if (cnt instanceof LinkFormControl_1.LinkFormControl) {
                    if (cnt.type === FormDesignConstants_1.LinkControlType.ACTION) {
                        result.push(new MultiExecutable_1.MultiExecutableOutputDefinition(cnt.getOutcomeName(), []));
                    }
                }
                //todo: add the data to each
            }
        }
        // todo: if no outcomes are defined, need to add general one
        // todo: what if a piece of data is outside the outcome
        return result;
    }
    getRuleValidationIssues(fieldName) {
        const validationIssues = [];
        const runableRules = this.getRunableRules(fieldName);
        const data = new ExecutionData_1.ExecutionData(this.getFormDatDefinition().value);
        for (const rule of runableRules.filter((rule) => rule.ruleType === FormRule_1.FormRuleType.VALIDATION)) {
            const ruleResult = rule.expression.run(data, undefined);
            if (ruleResult) {
                const message = Reflect.get(rule.data, "validationMessage");
                const variable = Reflect.get(rule.data, "controlId");
                if (variable) {
                    validationIssues.push(new IDesignValidationProvider_1.ValidationIssue(message, variable));
                }
            }
        }
        return validationIssues;
    }
    dataChangeByRule(fieldName) {
        const runableRules = this.getRunableRules(fieldName);
        const data = new ExecutionData_1.ExecutionData(this.getFormDatDefinition().value);
        for (const rule of runableRules.filter((rule) => rule.ruleType === FormRule_1.FormRuleType.CHANGE_VALUE)) {
            const ruleResult = rule.expression.run(data, undefined);
            if (ruleResult) {
                const datapath = Reflect.get(rule.data, "dataPath");
                const value = Reflect.get(rule.data, "value");
                const valueResult = value.run(data, undefined);
                this.getFormContext().setFormDataValue(datapath, valueResult);
            }
        }
    }
    hideControlByRule() {
        const runableRules = this.rules;
        const data = new ExecutionData_1.ExecutionData(this.getFormDatDefinition().value);
        let hideControls = [];
        for (const rule of runableRules.filter((rule) => rule.ruleType === FormRule_1.FormRuleType.CONTROL_VISIBILITY)) {
            const ruleResult = rule.expression.run(data, undefined);
            if (ruleResult) {
                const controlId = Reflect.get(rule.data, "controlId");
                if (typeof controlId === "object") {
                    hideControls = [...hideControls, ...controlId];
                }
                else {
                    hideControls.push(controlId);
                }
            }
        }
        this.getFormContext().runtimeHideControls = hideControls;
    }
    disableControlByRule() {
        const runableRules = this.rules;
        const data = new ExecutionData_1.ExecutionData(this.getFormDatDefinition().value);
        let disabledControls = [];
        for (const rule of runableRules.filter((rule) => rule.ruleType === FormRule_1.FormRuleType.CONTROL_ENABLED)) {
            const ruleResult = rule.expression.run(data, undefined);
            if (ruleResult) {
                const controlId = Reflect.get(rule.data, "controlId");
                if (typeof controlId === "object") {
                    disabledControls = [...disabledControls, ...controlId];
                }
                else {
                    disabledControls.push(controlId);
                }
            }
        }
        this.getFormContext().runtimeDisabledControls = disabledControls;
    }
    focusControlByRule() {
        const runableRules = this.rules;
        const data = new ExecutionData_1.ExecutionData(this.getFormDatDefinition().value);
        let focusControls = [];
        for (const rule of runableRules.filter((rule) => rule.ruleType === FormRule_1.FormRuleType.CHANGE_FOCUS)) {
            try {
                const ruleResult = rule.expression.run(data, undefined);
                if (ruleResult) {
                    const controlId = Reflect.get(rule.data, "controlId");
                    if (typeof controlId === "object") {
                        focusControls = [...focusControls, ...controlId];
                    }
                    else {
                        focusControls.push(controlId);
                    }
                }
            }
            catch (e) {
                console.error(e);
            }
        }
        for (const focusControl of focusControls) {
            const control = this.find(focusControl);
            if (control && control.ref.current) {
                control.focusControl();
            }
        }
    }
    getRunableRules(fieldName) {
        const runableRules = [];
        for (const rule of this.rules) {
            const watchingValuesMode = rule.watchingValuesMode;
            let watchingValues = rule.watchingValues;
            if (watchingValuesMode === "value used in rule") {
                watchingValues = rule.expression.getUsedVariables();
            }
            if (rule.enabled &&
                watchingValues.indexOf(fieldName) > -1 &&
                rule.getDesignValidationIssues(this).length === 0) {
                runableRules.push(rule);
            }
        }
        return runableRules;
    }
    toString() {
        return "Form Config";
    }
    // todo: this needs to be a callback type
    run(data, testContext) {
        return this.runWithFormHost(data, IFormHost_1.FormHost.defaultFormHost, testContext);
    }
    runWithFormHost(data, formHost, testContext) {
        let subContext;
        if (testContext) {
            subContext = new FormTestResult_1.FormTestResult(this, data);
            // todo: put this back?
            // if (!formHost) {
            //     FormHost.defaultFormHost = subContext;
            //     formHost = subContext;
            // }
            testContext.addTestResultItem(subContext);
            subContext.addLogItem(new EventLog_1.EventLog(`Form: start evaluating`));
        }
        let formContext = this.getFormContext();
        if (!formContext) {
            formContext = new FormContext_1.FormContext(this);
            this.setFormContext(formContext);
        }
        formContext.data.values = data.values;
        // need to reset lock of form data because we are trying to rerun.
        formContext.data.datalocked = false;
        if (formHost) {
            formHost.showForm(() => (0, jsx_runtime_1.jsx)(FormRuntime_1.FormRuntime, { form: this }));
        }
        return formContext.resultPromise
            .then((outcomeName) => {
            let result = JSON.stringify({
                outcomeName,
                data: data.values,
            });
            if (subContext) {
                subContext.result = result;
                subContext.addLogItem(new EventLog_1.EventLog(`Form: end evaluating with result ${result}`));
            }
            return new ExecutableReturnPromise_1.ExecutablePromiseReturn(result, data);
        })
            .catch((error) => {
            if (subContext) {
                subContext.isError = true;
                subContext.addLogItem(new EventLog_1.EventLog(`Form: end evaluating with error ${error.message}`));
                subContext.result = error.message;
            }
            throw error;
        });
    }
}
tslib_1.__decorate([
    AutoBind_1.AutoBind
], FormConfiguration.prototype, "render", null);
exports.FormConfiguration = FormConfiguration;
//# sourceMappingURL=FormConfiguration.js.map