"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FlowBuilder = void 0;
const tslib_1 = require("tslib");
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = tslib_1.__importDefault(require("react"));
const FlowConfiguration_1 = require("@appglue/common/dist/Flow/FlowConfiguration");
const styled_components_1 = tslib_1.__importDefault(require("styled-components"));
const RegisterFlowEditor_1 = require("./Utilities/RegisterFlowEditor");
const react_beautiful_dnd_1 = require("react-beautiful-dnd");
const AutoBind_1 = require("@appglue/common/dist/Common/AutoBind");
const CommonStyles_1 = require("../CommonUI/CommonStyles");
const StateManager_1 = require("@appglue/common/dist/Common/StateManager");
const ObserveState_1 = require("../CommonUI/StateManagement/ObserveState");
const FlowConstants_1 = require("@appglue/common/dist/Flow/Utilities/FlowConstants");
const FlowEditContext_1 = require("./FlowEditContext");
const ObserveMultiStateProperties_1 = require("../CommonUI/StateManagement/ObserveMultiStateProperties");
const CandidateSequence_1 = require("@appglue/common/dist/Flow/Structure/CandidateSequence");
const Topbar_1 = require("../CommonUI/BuilderUI/Topbar");
const Sidebar_1 = require("../CommonUI/BuilderUI/Sidebar");
const ViewIcon_1 = require("../CommonUI/Icon/ViewIcon");
const ToolBox_1 = require("./Builder/Components/ToolBox");
const RegisterFlowEditors_1 = require("./Utilities/RegisterFlowEditors");
const XFlowEditor_Designer_1 = require("./Builder/Components/XFlowEditor.Designer");
const FlowBuilderPage_1 = require("./Builder/FlowBuilderPage");
const FlowStepSequence_1 = require("@appglue/common/dist/Flow/Structure/FlowStepSequence");
const FlowIcon_1 = require("../CommonUI/Icon/FlowIcon");
const TestDataIcon_1 = require("../CommonUI/Icon/TestDataIcon");
const XBuilderEditPage_1 = require("../CommonUI/BuilderUI/XBuilderEditPage");
const CodingIcon_1 = require("../CommonUI/Icon/CodingIcon");
const RegisterFlowStepDatas_1 = require("@appglue/common/dist/Flow/Utilities/RegisterFlowStepDatas");
const AppGlueError_1 = require("@appglue/common/dist/AppGlueError");
const DataBuilder_1 = require("../DataBuilder/DataBuilder");
const DescriptionGrayIcon_1 = require("../CommonUI/Icon/DescriptionGrayIcon");
const CommonStyles_2 = require("./Builder/CommonStyles");
const ErrorBranchIcon_1 = require("../CommonUI/Icon/ErrorBranchIcon");
const ExpandAllIcon_1 = require("../CommonUI/Icon/ExpandAllIcon");
const CollapseAllIcon_1 = require("../CommonUI/Icon/CollapseAllIcon");
const DataInputIcon_1 = require("../CommonUI/Icon/DataInputIcon");
const DataOutputIcon_1 = require("../CommonUI/Icon/DataOutputIcon");
const XExecutableTester_1 = require("../CommonUI/Testing/XExecutableTester");
const FlowEditorDiv = styled_components_1.default.div `
    width: 100%;
    height: 100vh;
    display: flex;
    flex-direction: column;

    *::-webkit-scrollbar-track {
        -webkit-box-shadow: inset 0 0 2px rgba(147, 169, 191, 0.28);
        background-color: transparent;
    }

    *::-webkit-scrollbar {
        width: 8px;
        background-color: transparent;
    }

    *::-webkit-scrollbar-thumb {
        background-color: rgba(64, 80, 166, 0.8);
    }
`;
class FlowBuilder extends react_1.default.Component {
    editContext;
    mousePosition = {
        x: 0,
        y: 0,
    };
    constructor(props) {
        super(props);
        RegisterFlowEditors_1.RegisterFlowEditors.doRegistration();
        if (props.flowEditContext) {
            if (this.props.flowEditContext?.flow._id !== props.flow._id)
                throw new AppGlueError_1.AppGlueError("flow id in context and flow do not match");
            this.editContext = props.flowEditContext;
        }
        else {
            this.editContext = new FlowEditContext_1.FlowEditContext(props.flow, this);
        }
        // ensure flow steps are registered
        RegisterFlowEditors_1.RegisterFlowEditors.doRegistration();
        RegisterFlowStepDatas_1.RegisterFlowStepDatas.doRegistration();
        if (props.flowName) {
            this.editContext.flowName = props.flowName;
        }
        if (props.viewAPIUrl) {
            this.editContext.viewAPIUrl = props.viewAPIUrl;
        }
        if (props.onFlowSave) {
            this.editContext.onFlowSave = props.onFlowSave;
        }
        if (props.onFlowCancel) {
            this.editContext.onFlowCancel = props.onFlowCancel;
        }
        if (props.flowStartDataDefinition) {
            props.flow.inputData = props.flowStartDataDefinition;
        }
        if (props.flow.sequences.length > 0) {
            for (let seq of [...props.flow.sequences, props.flow.errorSequence, props.flow.endSequence]) {
                seq.flow = props.flow;
            }
        }
        window.addEventListener("mousemove", this.onMouseMove);
    }
    get flow() {
        return this.props.flow;
    }
    onMouseMove = (event) => {
        this.mousePosition = {
            x: event.clientX,
            y: event.clientY,
        };
    };
    componentWillUnmount() {
        window.removeEventListener("mousemove", this.onMouseMove);
    }
    getDefaultTabs() {
        let sideBarTabs = [];
        sideBarTabs.push({
            value: FlowBuilderPage_1.FlowBuilderPage.Flow,
            renderUI: () => ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(ObserveState_1.ObserveState, { listenTo: this.editContext, properties: [FlowStepSequence_1.FlowStepSequence.DRAG_OVER], control: () => (0, jsx_runtime_1.jsx)(ToolBox_1.ToolBox, { editContext: this.editContext, flow: this.flow }) }), (0, jsx_runtime_1.jsx)(ObserveMultiStateProperties_1.ObserveMultiStateProperties, { listeners: [
                            {
                                listenTo: this.props.flow,
                                propertyName: "sequences",
                            },
                            {
                                listenTo: this.editContext,
                                propertyName: "propName",
                            },
                        ], control: () => (0, jsx_runtime_1.jsx)(XFlowEditor_Designer_1.FlowDesignPage, { flow: this.props.flow, editContext: this.editContext }) })] })),
            icon: (0, jsx_runtime_1.jsx)(FlowIcon_1.FlowIcon, {}),
        }, {
            value: FlowBuilderPage_1.FlowBuilderPage.Data,
            renderUI: () => {
                return ((0, jsx_runtime_1.jsx)(DataBuilder_1.DataBuilder, { definition: this.props.flow.getInputDefinition(), readOnly: !this.props.flow.canChangeInputs }));
            },
            icon: (0, jsx_runtime_1.jsx)(DataInputIcon_1.DataInputIcon, {}),
        });
        if (this.props.flow.defineOutputs === FlowConfiguration_1.FlowOutputType.DEFINED || !this.props.flow.canChangeOutputs) {
            sideBarTabs.push({
                value: FlowBuilderPage_1.FlowBuilderPage.OutputData,
                renderUI: () => {
                    return ((0, jsx_runtime_1.jsx)(DataBuilder_1.DataBuilder, { definition: this.props.flow.getExecutionResult(), readOnly: !this.props.flow.canChangeOutputs }));
                },
                icon: (0, jsx_runtime_1.jsx)(DataOutputIcon_1.DataOutputIcon, {}),
            });
        }
        sideBarTabs.push({
            value: FlowBuilderPage_1.FlowBuilderPage.Configuration,
            renderUI: () => (0, jsx_runtime_1.jsx)(XBuilderEditPage_1.XBuilderEditPage, { builder: this.props.flow, updateCallback: () => { } }),
            icon: (0, jsx_runtime_1.jsx)(CodingIcon_1.CodingIcon, {}),
        }, {
            value: FlowBuilderPage_1.FlowBuilderPage.Test,
            renderUI: () => ((0, jsx_runtime_1.jsx)(XExecutableTester_1.XExecutableTester, { saveUnitTest: this.props.saveUnitTest, builderName: "Test", executable: this.props.flow })),
            icon: (0, jsx_runtime_1.jsx)(TestDataIcon_1.TestDataIcon, {}),
        });
        return sideBarTabs;
    }
    onChangeFlowName(newName) {
        this.editContext.flowName = newName;
        StateManager_1.StateManager.propertyChanged(this.editContext, FlowEditContext_1.FlowEditContext.FLOW_NAME);
        if (this.props.onFlowNameUpdate)
            this.props.onFlowNameUpdate(newName);
    }
    render() {
        let afterElems = [];
        if (this.props.viewAPIUrl) {
            afterElems.push((0, jsx_runtime_1.jsx)(CommonStyles_1.TopbarViewButton, { color: "primary", startIcon: (0, jsx_runtime_1.jsx)(ViewIcon_1.ViewIcon, {}), href: this.editContext.viewAPIUrl, children: "View API" }));
        }
        return ((0, jsx_runtime_1.jsx)(ObserveState_1.ObserveState, { listenTo: this, control: () => ((0, jsx_runtime_1.jsx)(react_beautiful_dnd_1.DragDropContext, { onBeforeCapture: this.onBeforeCapture, onBeforeDragStart: this.onBeforeDragStart, onDragEnd: this.onDragEnd, onDragUpdate: this.onDragUpdate, children: (0, jsx_runtime_1.jsxs)(FlowEditorDiv, { children: [(0, jsx_runtime_1.jsx)(ObserveState_1.ObserveState, { listenTo: this.editContext, properties: [
                                FlowEditContext_1.FlowEditContext.FLOW_NAME,
                                FlowEditContext_1.FlowEditContext.SELECTION_ELEMENT,
                                FlowEditContext_1.FlowEditContext.IS_SHOW_DESCRIPTION,
                                FlowEditContext_1.FlowEditContext.IS_SHOW_ERROR_BRANCH,
                                FlowEditContext_1.FlowEditContext.IS_COLLAPSED,
                            ], control: () => {
                                let afterItems = [
                                    {
                                        label: "Show",
                                        type: Topbar_1.IInjectTopItemType.ICONBUTTONGROUP,
                                        onSelect: (value) => {
                                            switch (value) {
                                                case "description":
                                                    this.editContext.isShowDescription =
                                                        !this.editContext.isShowDescription;
                                                    break;
                                                case "collapse":
                                                    this.editContext.isCollapsed = !this.editContext.isCollapsed;
                                                    break;
                                            }
                                        },
                                        items: [
                                            {
                                                value: "description",
                                                label: "Show / Hide All Description",
                                                icon: (0, jsx_runtime_1.jsx)(DescriptionGrayIcon_1.DescriptionGrayIcon, {}),
                                                isSelected: () => {
                                                    return this.editContext.isShowDescription;
                                                },
                                                belowLabel: this.editContext.isShowDescription ? ((0, jsx_runtime_1.jsx)(CommonStyles_2.OnDiv, { children: "on" })) : ((0, jsx_runtime_1.jsx)(CommonStyles_2.OffDiv, { children: "off" })),
                                            },
                                            {
                                                value: "error_branch",
                                                label: "Show Error and End Connections",
                                                icon: (0, jsx_runtime_1.jsx)(ErrorBranchIcon_1.ErrorBranchIcon, {}),
                                                isSelected: () => {
                                                    return this.editContext.isShowErrorBranch;
                                                },
                                                belowLabel: this.editContext.isShowErrorBranch ? ((0, jsx_runtime_1.jsx)(CommonStyles_2.OnDiv, { children: "on" })) : ((0, jsx_runtime_1.jsx)(CommonStyles_2.OffDiv, { children: "off" })),
                                                onMouseDown: () => {
                                                    this.editContext.isShowErrorBranch = true;
                                                },
                                                onMouseUp: () => {
                                                    this.editContext.isShowErrorBranch = false;
                                                },
                                            },
                                            {
                                                value: "collapse",
                                                label: "Collapse / Expand all sequences",
                                                icon: this.editContext.isCollapsed ? ((0, jsx_runtime_1.jsx)(ExpandAllIcon_1.ExpandAllIcon, {})) : ((0, jsx_runtime_1.jsx)(CollapseAllIcon_1.CollapseAllIcon, {})),
                                                isSelected: () => {
                                                    return this.editContext.isCollapsed;
                                                },
                                                belowLabel: this.editContext.isCollapsed ? ((0, jsx_runtime_1.jsx)(CommonStyles_2.OnDiv, { children: "on" })) : ((0, jsx_runtime_1.jsx)(CommonStyles_2.OffDiv, { children: "off" })),
                                            },
                                        ],
                                        wrapperStyle: { border: "none" },
                                    },
                                ];
                                return ((0, jsx_runtime_1.jsx)(Topbar_1.Topbar, { name: this.editContext.flowName, onChangeName: this.onChangeFlowName, editContext: this.editContext, isActionDisabled: !this.editContext.lastSelectionElement, isRequiredActionGroup: true, onSave: this.editContext.onFlowSave
                                        ? () => {
                                            if (this.editContext.onFlowSave) {
                                                this.editContext.onFlowSave();
                                            }
                                        }
                                        : undefined, onClose: this.editContext.onFlowCancel, afterItems: afterItems, afterElems: afterElems }));
                            } }), (0, jsx_runtime_1.jsx)(ObserveState_1.ObserveState, { listenTo: this.editContext, properties: [FlowEditContext_1.FlowEditContext.MODE, FlowConfiguration_1.FlowConfiguration.OUTPUT_STRATEGY], control: () => ((0, jsx_runtime_1.jsx)(Sidebar_1.Sidebar, { items: this.getDefaultTabs(), value: this.editContext.mode, onChange: (mode) => {
                                    Reflect.set(this.editContext, "mode", mode);
                                    StateManager_1.StateManager.propertyChanged(this.editContext, FlowEditContext_1.FlowEditContext.MODE);
                                } })) })] }) })) }));
    }
    onBeforeCapture(before) {
        this.editContext.draggingControl = {
            source: {
                current: before.draggableId,
            },
            pos: this.mousePosition,
        };
    }
    onBeforeDragStart(initial) {
        this.editContext.clearSelection();
        this.editContext.draggingControl = {
            source: {
                parent: initial.source.droppableId,
                current: initial.draggableId,
            },
            pos: this.editContext.draggingControl.pos,
        };
    }
    onDragUpdate(initial) {
        this.editContext.draggingControl = {
            source: {
                parent: initial.source.droppableId,
                current: initial.draggableId,
            },
            destination: initial.destination?.droppableId,
            pos: this.editContext.draggingControl.pos,
        };
    }
    onDragEnd(result) {
        this.editContext.draggingControl = null;
        // if not destination... then we should not do anything
        if (!result.destination) {
            console.log("not a dest");
            return;
        }
        // do not drag in toolbox
        if (result.destination.droppableId === FlowConstants_1.FlowConstants.ToolboxId)
            return;
        // do not drag from normal sequences to error sequence, vice versa.
        if ((result.destination.droppableId === FlowConstants_1.FlowConstants.ERROR_SEQUENCE &&
            result.source.droppableId !== FlowConstants_1.FlowConstants.ToolboxId) ||
            result.source.droppableId === FlowConstants_1.FlowConstants.ERROR_SEQUENCE) {
            console.log("its error");
            return;
        }
        let control;
        let registeredControl = RegisterFlowEditor_1.FlowStepEditorRegistration.getByTypeName(result.draggableId);
        if (registeredControl) {
            control = registeredControl.create(this.editContext);
            this.editContext.registerStepEditor(control.getFlowStepData()._id, control);
        }
        else {
            control = this.editContext.getStepEditor(result.draggableId);
        }
        try {
            if (control) {
                let fromSeqId = result.source.droppableId;
                let toSeqId = result.destination.droppableId;
                let fromSeqBranch = 0;
                let toSeqBranch = 0;
                if (fromSeqId.indexOf("::") !== -1) {
                    let pieces = fromSeqId.split("::");
                    fromSeqId = pieces[0];
                    fromSeqBranch = Number.parseInt(pieces[1]);
                }
                if (toSeqId.indexOf("::") !== -1) {
                    let pieces = toSeqId.split("::");
                    toSeqId = pieces[0];
                    toSeqBranch = Number.parseInt(pieces[1]);
                }
                let toSeq = this.flow.getCandidateOrRealSequence(toSeqId);
                let fromSeq = this.flow.getCandidateOrRealSequence(fromSeqId);
                if (!toSeq) {
                    throw new Error("Can not find the droppable sequence");
                }
                if (fromSeqId === toSeqId) {
                    // changing order
                    this.props.flow.moveInSequence(control.getFlowStepData(), toSeqId, result.destination.index, fromSeqBranch, toSeqBranch);
                    StateManager_1.StateManager.propertyChanged(toSeq, FlowStepSequence_1.FlowStepSequence.STEPS_CHANGED);
                }
                else {
                    if (toSeq instanceof CandidateSequence_1.CandidateSequence) {
                        if (!fromSeq) {
                            // dropping on candidate from toolbox
                            this.editContext.addStepToCandidate(control.getFlowStepData(), toSeq);
                            StateManager_1.StateManager.propertyChanged(toSeq, FlowStepSequence_1.FlowStepSequence.STEPS_CHANGED);
                        }
                        else if (fromSeq instanceof FlowStepSequence_1.FlowStepSequence) {
                            // dropping on candidate from real sequences.
                            this.editContext.moveStepToCandidate(control.getFlowStepData(), fromSeq, toSeq);
                            this.editContext.onStepMoved(fromSeq, toSeq, control.getFlowStepData());
                            StateManager_1.StateManager.propertyChanged(toSeq, FlowStepSequence_1.FlowStepSequence.STEPS_CHANGED);
                            StateManager_1.StateManager.propertyChanged(fromSeq, FlowStepSequence_1.FlowStepSequence.STEPS_CHANGED);
                        }
                    }
                    else if (toSeq instanceof FlowStepSequence_1.FlowStepSequence) {
                        if (!fromSeq) {
                            // dropping on real sequence from toolbox.
                            this.flow.add(control.getFlowStepData(), toSeq, result.destination.index, toSeqBranch);
                            StateManager_1.StateManager.propertyChanged(toSeq, FlowStepSequence_1.FlowStepSequence.STEPS_CHANGED);
                        }
                        else if (fromSeq instanceof FlowStepSequence_1.FlowStepSequence) {
                            // dropping on real sequence from real sequences.
                            this.flow.moveToSequence(control.getFlowStepData(), fromSeq, toSeq, result.destination.index, toSeqBranch);
                            this.editContext.onStepMoved(fromSeq, toSeq, control.getFlowStepData());
                        }
                    }
                }
            }
        }
        catch (e) {
            this.editContext.notification = {
                message: e.message,
                onSuccess: () => { },
            };
        }
        // if (control) {
        //     this.editContext.setSelection(control);
        // }
        // else {
        //     this.editContext.clearSelection();
        // }
    }
}
tslib_1.__decorate([
    AutoBind_1.AutoBind
], FlowBuilder.prototype, "onChangeFlowName", null);
tslib_1.__decorate([
    AutoBind_1.AutoBind
], FlowBuilder.prototype, "onBeforeCapture", null);
tslib_1.__decorate([
    AutoBind_1.AutoBind
], FlowBuilder.prototype, "onBeforeDragStart", null);
tslib_1.__decorate([
    AutoBind_1.AutoBind
], FlowBuilder.prototype, "onDragUpdate", null);
tslib_1.__decorate([
    AutoBind_1.AutoBind
], FlowBuilder.prototype, "onDragEnd", null);
exports.FlowBuilder = FlowBuilder;
//# sourceMappingURL=FlowBuilder.js.map