import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { Tooltip } from "@material-ui/core";
import { CandidateSequence } from "../CandidateSequence";
import { FlowStepSequenceStrategy } from "../FlowStepSequence";
import { FlowStepOutputInstructionType } from "../FlowStepOutputInstructions";
import { FlowConstants } from "../../CommonUI/FlowConstants";
import { IInjectTopItemType } from "../../../CommonUI/BuildUI/Topbar";
import { DescriptionGrayIcon } from "../../../CommonUI/Icon/DescriptionGrayIcon";
import { ErrorBranchIcon } from "../../../CommonUI/Icon/ErrorBranchIcon";
import { HTMLUtilities } from "../../../CommonUI/HTMLUtilities";
import { BranchIcon } from "../../../CommonUI/Icon/BranchIcon";
import { OffDiv, OnDiv } from "../../DesignerUI/CommonStyles";
export class BaseDisplayBehavior {
    constructor(editContext, flow) {
        this.isEnableContextMenu = true;
        this.lineLabelPosition = "middle";
        this.sequenceOuterPadding = "4px";
        this.linePathType = "smooth";
        this.candidateWidth = FlowConstants.PATH_CANDIDATE_WIDTH;
        this.candidateHeight = FlowConstants.PATH_CANDIDATE_HEIGHT;
        this.candidateDraggingWidth = FlowConstants.PATH_DRAGGING_CANDIDATE_WIDTH;
        this.candidateDraggingHeight = FlowConstants.PATH_DRAGGING_CANDIDATE_HEIGHT;
        this.candidatePadding = "0 40px";
        this.candidateFontSize = 12;
        this.collapsedWidth = FlowConstants.DEFAULT_COLLAPSED_STACK_WIDTH;
        this.collapsedHeight = FlowConstants.DEFAULT_COLLAPSED_STACK_HEIGHT;
        this.errorCollapsedWidth = FlowConstants.COLLAPSED_ERROR_STACK_WIDTH;
        this.emptyTextFontSize = 16;
        this.sequenceTitleColor = "rgba(39, 41, 50, 0.7)";
        this.stackWidth = FlowConstants.DEFAULT_STACK_WIDTH;
        this.stackHeight = FlowConstants.DEFAULT_STACK_HEIGHT;
        this.sequenceCandidateShift = FlowConstants.SEQUENCE_CANDIDATE_SHIFT;
        this.pathCandidateShift = FlowConstants.PATH_CANDIDATE_SHIFT;
        this.editContext = editContext;
        this.flow = flow;
    }
    getShowTopItems() {
        return {
            label: "Show",
            type: 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: _jsx(DescriptionGrayIcon, {}, void 0),
                    isSelected: () => {
                        return this.editContext.isShowDescription;
                    },
                    belowLabel: this.editContext.isShowDescription ? _jsx(OnDiv, { children: "on" }, void 0) : _jsx(OffDiv, { children: "off" }, void 0),
                },
                {
                    value: "error_branch",
                    label: "Show Error and End Connections",
                    icon: _jsx(ErrorBranchIcon, {}, void 0),
                    isSelected: () => {
                        return this.editContext.isShowErrorBranch;
                    },
                    belowLabel: this.editContext.isShowErrorBranch ? _jsx(OnDiv, { children: "on" }, void 0) : _jsx(OffDiv, { children: "off" }, void 0),
                    onMouseDown: () => {
                        this.editContext.isShowErrorBranch = true;
                    },
                    onMouseUp: () => {
                        this.editContext.isShowErrorBranch = false;
                    },
                },
            ],
            wrapperStyle: { border: "none" },
        };
    }
    isCollapsed(sequence) {
        return sequence.isCollapsed;
    }
    setIsCollapsed(sequence, isCollapsed) {
        sequence.isCollapsed = isCollapsed;
    }
    toggleIsCollapsed(event, sequence) {
        event.stopPropagation();
        this.setIsCollapsed(sequence, !this.isCollapsed(sequence));
    }
    onSetSelection(sequence) {
        return;
    }
    clearSelection() {
        this.editContext.clearSelection();
    }
    onSelectStepStrategyConnect(element, step) {
        let hidden = Reflect.get(step, "hidden");
        if (!hidden) {
            // for step strategy
            this.editContext.setSelectedStepStrategy(element, step);
        }
        else if (step.sequence) {
            // for sequence strategy
            this.editContext.setSelectedSequenceStrategy(element, step.sequence);
        }
    }
    getLine(value) {
        let targetSequence = this.editContext.getCandidateOrRealSequence(value.toId);
        let isHiddenStep = Reflect.get(value.fromStep, "hidden");
        let startId = null;
        let startAnchor = "right";
        if (this.isCollapsed(value.fromSequence)) {
            // no need to split the lines by instruction. just do with squence.
            startId = value.fromSequence._id;
            startAnchor = [
                {
                    position: "bottom",
                    offset: {
                        x: 20,
                        y: -10,
                    },
                },
                {
                    position: "right",
                    offset: {
                        y: Math.ceil(value.fromSequence.instructions.filter((ins) => ins.strategy !== FlowStepOutputInstructionType.BRANCH).length / 2) * 16,
                        x: -12,
                    },
                },
                "top",
                "left",
            ];
        }
        else {
            startId = value.fromId;
        }
        if (isHiddenStep) {
            startAnchor = "bottom";
        }
        let endAnchor = [
            "left",
            "top",
            {
                position: "bottom",
                offset: {
                    x: 20,
                    y: -10,
                },
            },
        ];
        if (targetSequence instanceof CandidateSequence && !isHiddenStep) {
            endAnchor = "left";
        }
        let tooltip = value.fromInstruction.pathName;
        let label = tooltip.length > FlowConstants.MAX_CHARS_STEP_PATH_LABEL
            ? `${tooltip.slice(0, FlowConstants.MAX_CHARS_STEP_PATH_LABEL)}...`
            : tooltip;
        return {
            targetSequence,
            arrow: {
                start: startId,
                startAnchor: startAnchor,
                end: value.toId,
                endAnchor: endAnchor,
                strokeWidth: 2,
                headSize: 3,
                color: FlowConstants.DEFAULT_RELATION_LINE_COLOR,
                path: this.linePathType,
                avoidRects: this.flow.sequences.map((s) => s._id),
            },
            labels: [
                {
                    label: (_jsx(Tooltip, Object.assign({ title: tooltip }, { children: _jsxs("span", Object.assign({ style: { display: "flex", alignItems: "center" } }, { children: [isHiddenStep && _jsx(BranchIcon, {}, void 0), " ", label] }), void 0) }), void 0)),
                    value,
                    isFlowConnection: isHiddenStep,
                },
            ],
            value,
        };
    }
    getLines() {
        return this.flow.getConnections().reduce((lines, value) => {
            let line = this.getLine(value);
            let isSet = false;
            for (let l of lines) {
                // combining the lines by start sequence and end sequence.
                if (l.arrow.end === line.arrow.end && l.value.fromSequence._id === line.value.fromSequence._id) {
                    l.labels = [...l.labels, ...line.labels];
                    l.arrow.start = l.value.fromSequence._id;
                    isSet = true;
                    break;
                }
            }
            if (!isSet) {
                lines.push(line);
            }
            return lines;
        }, []);
    }
    addStepToSequence(seq, step, index) {
        // when collased, it's append to end.
        this.flow.add(step, seq, index);
    }
    moveStepToSequence(step, fromSeq, toSeq, index) {
        this.flow.moveToSequence(step, fromSeq, toSeq, index);
        // fromSeq.removeStep(step);
        // toSeq.addStep(step, index);
    }
    getCandidateCommonStyles() {
        return {
            width: this.candidateWidth,
            height: this.candidateHeight,
            padding: this.candidatePadding,
            fontSize: this.candidateFontSize,
            dragging: {
                width: this.candidateDraggingWidth,
                height: this.candidateDraggingHeight,
            },
        };
    }
    getErrorSeqeuenceMainSize(sequence) {
        if (this.isCollapsed(sequence)) {
            return {
                width: this.errorCollapsedWidth,
                height: this.collapsedHeight,
                fontSize: this.emptyTextFontSize,
                title: {
                    color: FlowConstants.ERROR_COLLAPSED_TITLE_COLOR,
                },
            };
        }
        return {
            width: FlowConstants.DEFAULT_STACK_WIDTH,
            height: sequence.steps.length === 0 ? 100 : undefined,
            fontSize: this.emptyTextFontSize,
            title: {
                color: FlowConstants.ERROR_TITLE_COLOR,
            },
        };
    }
    getErrorSequenceTitleStyle(sequence) {
        if (this.isCollapsed(sequence)) {
            return {
                color: FlowConstants.ERROR_COLLAPSED_TITLE_COLOR,
            };
        }
        return {
            color: FlowConstants.ERROR_TITLE_COLOR,
        };
    }
    getEndSequenceMainSize(sequence) {
        if (this.isCollapsed(sequence)) {
            return {
                width: this.errorCollapsedWidth,
                height: this.collapsedHeight,
            };
        }
        return {
            width: FlowConstants.DEFAULT_STACK_WIDTH,
            height: sequence.steps.length === 0 ? 100 : undefined,
        };
    }
    getEndSequenceTitleStyle(sequence) {
        if (this.isCollapsed(sequence)) {
            return {
                color: FlowConstants.END_COLLAPSED_TITLE_COLOR,
            };
        }
        return {
            color: FlowConstants.END_TITLE_COLOR,
        };
    }
    getPrimaryMainSize(sequence) {
        if (this.isCollapsed(sequence)) {
            return {
                width: this.collapsedWidth,
                height: this.collapsedHeight,
            };
        }
        return {
            width: this.stackWidth,
            height: sequence.steps.length === 0 ? this.stackHeight : undefined,
        };
    }
    getPrimarySequenceTitleStyle(sequence) {
        return {
            color: FlowConstants.PRIMARY_TITLE_COLOR,
        };
    }
    getSequenceMainSize(sequence) {
        // error stack common styles
        if (sequence.isError)
            return this.getErrorSeqeuenceMainSize(sequence);
        // end stack common styles
        if (sequence.isEnd)
            return this.getEndSequenceMainSize(sequence);
        //primary stack common styles
        if (sequence.isPrimary)
            return this.getPrimaryMainSize(sequence);
        if (this.isCollapsed(sequence)) {
            return {
                width: this.collapsedWidth,
                height: this.collapsedHeight,
            };
        }
        return {
            width: this.stackWidth,
            height: sequence.steps.length === 0 ? this.stackHeight : undefined,
        };
    }
    getSequenceExtraSize(sequence) {
        return {
            width: 0,
            height: sequence.strategy === FlowStepSequenceStrategy.LINK ? 0 : FlowConstants.FLOW_CONNECT_AREA_HEIGHT,
        };
    }
    getSequenceRealSize(sequence) {
        let size = this.getSequenceMainSize(sequence);
        let extraSize = this.getSequenceExtraSize(sequence);
        if (extraSize.width) {
            size.width += extraSize.width;
        }
        if (extraSize.height) {
            size.height = (size.height || 0) + extraSize.height;
        }
        return size;
    }
    getSequenceTitleStyle(sequence) {
        // error stack common styles
        if (sequence.isError)
            return this.getErrorSequenceTitleStyle(sequence);
        // end stack common styles
        if (sequence.isEnd)
            return this.getEndSequenceTitleStyle(sequence);
        //primary stack common styles
        if (sequence.isPrimary)
            return this.getPrimarySequenceTitleStyle(sequence);
        return {
            color: FlowConstants.DEFAULT_TITLE_COLOR,
        };
    }
    getEmptySequenceStyle(sequence) {
        return {
            fontSize: this.emptyTextFontSize,
        };
    }
    getSequenceStepsForPaths(sequence) {
        return [...sequence.steps, sequence.hiddenStep];
    }
    getPathsForStep(step) {
        let paths = step.getOutcomeInstructions();
        if (paths.length) {
            if (!Reflect.get(step, "hidden") || paths[0].strategy !== FlowStepOutputInstructionType.BRANCH)
                paths.shift();
        }
        return paths;
    }
    getSequenceInstructions(sequence) {
        return [...sequence.steps, sequence.hiddenStep].reduce((ss, s) => {
            let insts = this.getPathsForStep(s) || [];
            ss = [...ss, ...insts];
            return ss;
        }, []);
    }
    setCandidateDesiredPositionForSequenceStrategy(inst) {
        let seq = this.flow.findSequenceByStepId(inst.stepId);
        if (!seq)
            return;
        let pos = HTMLUtilities.getGeometry(seq._id, FlowConstants.DESIGN_SURFACE_ID);
        if (pos) {
            // set center below sequence.
            let instx = pos.left + pos.width / 2 - this.getCandidateCommonStyles().width / 2;
            let insty = pos.top + pos.height + this.sequenceCandidateShift;
            inst.candidateStackY = insty;
            inst.candidateStackX = instx < 0 ? 0 : instx;
        }
    }
    setCandidateDesiredPositionForStepStrategy(inst) {
        // if it's for sequence strategy
        let step = this.flow.find(inst.stepId);
        if (Reflect.get(step, "hidden")) {
            this.setCandidateDesiredPositionForSequenceStrategy(inst);
        }
        else {
            let pos = HTMLUtilities.getGeometry(inst.getElementId(), FlowConstants.DESIGN_SURFACE_ID);
            if (pos) {
                let insty = pos.top + 18 - this.getCandidateCommonStyles().height / 2;
                let instx = pos.left + this.pathCandidateShift;
                inst.candidateStackY = insty;
                inst.candidateStackX = instx;
            }
        }
    }
    setCandidateDesiredPositionForSeqeuence(sequence) {
        // when sequence is expanded, we need to set the disired position of candidates by instruction.
        if (!this.isCollapsed(sequence)) {
            for (let inst of sequence.instructions) {
                this.setCandidateDesiredPositionForStepStrategy(inst);
            }
        }
        // when sequenece is collapsed, we need to set the disired position of candidates by sequence and index
        else {
            let pos = HTMLUtilities.getGeometry(sequence._id, FlowConstants.DESIGN_SURFACE_ID);
            if (pos) {
                let idx = 0;
                for (let inst of sequence.instructions) {
                    // for hidden step
                    if (inst.stepId.endsWith("_end")) {
                        this.setCandidateDesiredPositionForSequenceStrategy(inst);
                        continue;
                    }
                    let c = this.editContext.getCandidateOrRealSequence(inst.connectedSequenceId);
                    if (c instanceof CandidateSequence) {
                        let insty = pos.top + idx * this.getCandidateCommonStyles().height + 10;
                        let instx = pos.left + pos.width + this.pathCandidateShift;
                        inst.candidateStackY = insty;
                        inst.candidateStackX = instx;
                        idx += 1;
                    }
                }
            }
        }
    }
    isShowStepConnection(step) {
        let sequence = step.sequence;
        if (!sequence)
            return false;
        let index = sequence.steps.indexOf(step);
        let isLast = sequence.steps.length <= index + 1;
        let otherPaths = step.getOutcomeInstructions();
        return !isLast || otherPaths.length !== 0;
    }
    getInitialSequenceStrategy() {
        return FlowStepSequenceStrategy.ENDFLOW;
    }
    isEnabledPlaceholderWhileDrop(sequence) {
        // no need animation for collapsed and no steps sequence.
        return sequence.steps.length > 0 && !this.isCollapsed(sequence);
    }
    getSequenceBackgroundColor(sequence) {
        // background color when candidate or stepsequence is dragging over on this sequence.
        if (sequence.isDragOver) {
            return FlowConstants.OVER_SEQUENCE_COLOR;
        }
        return sequence.color;
    }
    getSequenceBorderColor(sequence) {
        if (this.editContext.selection === sequence._id) {
            return FlowConstants.SELECTED_STACK_COLOR;
        }
        // While step is dragging over on collapsed sequence..
        if (this.flow.isDraggingOverSequence(sequence) && !this.isEnabledPlaceholderWhileDrop(sequence)) {
            return FlowConstants.SSS_STEP_DROP_OVER_BORDER_COLOR;
        }
        return "transparent";
    }
    renderSequenceTitle(sequence) {
        throw new Error("Not Implemented");
    }
    renderSequenceActions(sequence) {
        throw new Error("Not Implemented");
    }
    renderSequenceContent(sequence) {
        throw new Error("Not Implemented");
    }
    renderStepStrategy() {
        throw new Error("Not Implemented");
    }
    renderSequenceStrategy(sequence) {
        throw new Error("Not Implemented");
    }
    renderExtraContents(editContext) {
        return null;
    }
    renderEditUI(elem) {
        if (!elem)
            return null;
        return elem.renderEditUI();
    }
    getSequenceDroppableDirection(sequence) {
        return "vertical";
    }
}
//# sourceMappingURL=BaseDisplayBehavior.js.map