let store;
let edgeStore;
let jsonData;
let popup;
let form;
let scenarioParam = {};

const nodeType = {
    Intent: "Intent",
    Speak: "Speak",
    Slot: "Slot",
    Split: "Split",
    API: "API",
    Common: "Common",
    Function: "Function",
    Call: "Call",
}

// 테스트 변수
let scenarioTestToken = "";
let scenarioTestInitUserTalk = "";  // $#{id1}|{id2}|{id3}
let callId = "";


function initNodeValue(obj, key, initVal) {
    if (obj[key] == undefined) {
        obj[key] = initVal
    }
}

var ResEvent = {

    resInsertData : function(data){
        switch (data) {
            case 1:
                $.utils.success("수정된 내용이 없습니다.");
                break;
            default:
                $.utils.success("정상적으로 저장되었습니다.");
                $('#scenarioInfo').attr("checksum", $.utils.getStringToChecksum(JSON.stringify(jsonData)));
        }
    },

    resGetApiNodeList : function (data) {
        for (let i = 0; i < data.getList.length; i++) {
            apiNodeList[i] = {display : data.getList[i].nodeName, value : data.getList[i].seq};
        }
    },

    resGetCommonNodeList : function (data) {
        for (let i=0 ; i < data.getList.length; i++) {
            commonNodeList[i] = {display: data.getList[i].nodeName, value: data.getList[i].seq};
        }
    },

    resGetIntentNodeList : function (data) {
        let json = JSON.parse(data);
        for (let i = 0; i < json.list.length; i++) {
            defIntent[i] = {display: json.list[i].intentName, value: json.list[i].seq};
        }
    },

    resGetEntityList : function (data) {
        for(let index in data) {
            entity = {display: data[index].entityName, value: data[index].entityName};
            defEntityType.push(entity);
        }
    },

    resScenarioTestInit: function (data) {
        // 시나리오 테스트 정보 확인 완료 후
        // 1. 버튼 상태 변경
        // 2. 시나리오 변수 세팅
        // 3. Call bot init 값 요청

        $("#btnTestConnect").text("연결중");
        $("#btnTestConnect").attr("class", "minico on");

        $("#scenarioTestNum").attr("disabled", "disabled");
        $('#scenarioTestNum').niceSelect('update');

        scenarioTestInitUserTalk = "$#" + data.rfSeq +"|" + data.tableCode + "|" + data.columnCode;

        ReqEvent.reqScenarioTestAPI("INIT", "");
    },

    resScenarioTestAPI: function (data) { // Todo: 시나리오 테스트 기능 개발
        let result = data.result;
        let params = result.parameter;

        if(result.returnCode == "200" || result.returnCode == "500") {
            if (scenarioTestToken == "") {  // 초기화 요청 답변,
                if (result.token == "") {
                    $.utils.warning("토큰 값을 초기화 하지 못하였습니다.");
                    $('.refresh').click();
                    return;
                }

                scenarioTestToken = result.token;
                if(scenarioTestInitUserTalk == "") {
                    $.utils.warning("테스트할 수 있는 시나리오가 초기화되지 않았습니다.");
                }

                // 시나리오 테스트 시작 전송
                ReqEvent.reqScenarioTestAPI("STT", scenarioTestInitUserTalk);
            }

            // 응답 결과 파라메터 추가
            let debugString = "";
            ViewEvent.clearTestParam();
            if(!$.utils.isBlank(params)) {
                for (key in params) {
                    debugString += (key + "[\"" +params[key] + "\"] ");
                    if (!$.utils.isBlank(params[key])){
                        ViewEvent.addTestParam(key, params[key]);
                    }
                }
            }

            // 답변 채팅 추가 (디버깅 메시지 포함)
            let botResult = {
                botTalk: result.botTalk,
                time: $.utils.getDateTimeNow(["-", "-", " ", ":",":"]),
                debug: debugString,
                // debug: JSON.stringify(params),
            }
            ViewEvent.replyChat(botResult);
            $(".content-scroll").scrollTop($(".content-scroll")[0].scrollHeight);
        } else {
            $.utils.error("API 연동 오류가 발생하였습니다.");
            $('.refresh').click();
        }
    },

    resCallNumList : function (data) {

        $("#scenarioTestNum").empty();
        data.getList.forEach(function (e, f) {
            let testNum = e.attribute1
            let display = e.attribute1 + " (" + e.codeName + ")";

            let selCallNum = `<option value="${testNum}">${display}</option>`;
            $("#scenarioTestNum").append(selCallNum);
        });

        $('#scenarioTestNum').niceSelect('update');
    },

    resGetData : function(data){
        if(!$.utils.isBlank(data.scenarioName)) {
            $('#scenarioInfo').text("시나리오명: " + data.scenarioName);
            $("#scenarioName").val(data.scenarioName);
        }
        $('#scenarioInfo').attr("checksum", data.checksum);

        let generatedID = 0;
        if(data === null || data.textContents == "") {
            data = {textContents: ""};
        } else {
            let diagramObj = JSON.parse(data.textContents);
            if (diagramObj.shapes.length != 0) {
                generatedID = diagramObj.shapes.map(o => o.customData.nodeCode).reduce((max, curr) => max < curr ? curr : max );
            }
            // 시나리오 변수 세팅
            scenarioParam = diagramObj.scenarioParam;
            ViewEvent.ScenarioVarList(false);
        }

        store = new DevExpress.data.ArrayStore({
            key: 'ID',
            onInserting(values) {
                let nodeTypes = values.type;
                let nodeID;
                if (values.ID !== undefined) {
                    let nodes = $('#diagram').dxDiagram('instance').getNodeDataSource().items();
                    if (nodes.find( node => node.ID === values.ID) === undefined) {
                        nodeID = values.ID;
                        if (nodeID > generatedID) {
                            generatedID = nodeID;
                        }
                    } else {
                        nodeID = ++generatedID;
                    }
                } else {
                    nodeID = ++generatedID;
                }
                values.ID = nodeID;
                values.Key = values.Key;
                values.nodeCode = values.ID;
                values.nodeName = values.nodeName;
                values.type = values.type;
                values.nodeType = nodeTypes.toUpperCase();

                initNodeValue(values, "nodeName", "");

                // Todo: node 별 기본값 설정
                switch (values.type) {
                    case nodeType.Intent:
                        initNodeValue(values, "nodeMent", "");
                        initNodeValue(values, "intentSeq", -1);
                        break;
                    case nodeType.Speak:
                        initNodeValue(values, "nodeMent", "");
                        initNodeValue(values, "bargeIn", "Y");
                        initNodeValue(values, "endFlag", false);
                        break;
                    case nodeType.Slot:
                        initNodeValue(values, "paramName", "");
                        initNodeValue(values, "nodeMent", "");
                        initNodeValue(values, "bargeIn", "Y");
                        initNodeValue(values, "reNodeMent", "");
                        initNodeValue(values, "reBargeIn", "N");
                        initNodeValue(values, "nodeQstCnt", 3);
                        initNodeValue(values, "requiredYn", false);
                        initNodeValue(values, "actionType", "STT");
                        initNodeValue(values, "entityType", "");
                        initNodeValue(values, "maxDigit", 1);
                        break;
                    case nodeType.Split:
                        // Todo: 다음 노드가 있을 경우 어떻게 초기화 할 것인지?
                        break;
                    case nodeType.API:
                        initNodeValue(values, "apiNodeSeq", -1);
                        break;
                    case nodeType.Common:
                        initNodeValue(values, "commonNodeSeq", -1);
                        break;
                    case nodeType.Function:
                        initNodeValue(values, "javaScript", "");
                        initNodeValue(values, "funcParam", {0: ""});
                        break;
                    case nodeType.Call:
                        initNodeValue(values, "nodeMent", "");
                        initNodeValue(values, "bargeIn", "Y");
                        initNodeValue(values, "callProcess", "none");
                        initNodeValue(values, "shopPhoneNumber", "");
                        break;
                    default:
                }
            },
            // 데이터가 변경될때의 이벤트
            onPush: (data) => {
                $('.toolbox-text-item').each(function () {
                    var toolboxDataName = $(this).attr('data-tb-type');
                    var toolboxDataNameTrim = toolboxDataName.replace(/ /gi, "");
                    var toolboxDataNameCase = toolboxDataNameTrim.toLowerCase()
                    $(this).addClass(toolboxDataNameCase)
                })
            },

        });

        edgeStore = new DevExpress.data.ArrayStore({
            key: "ID",
        });

        let popupContentTemplate = function (options) {

            return ($container) => {
                $container.append("<div id='scrollView' class='custom-scrollView'/>")
                const formElement = $("<div id='form'/>");

                let edgeItems = $('#diagram').dxDiagram('instance').getEdgeDataSource().items();
                let edgeSearch = edgeItems.filter(edge => edge.from == options.formData.ID);
                let nodeItems = $('#diagram').dxDiagram('instance').getNodeDataSource().items();

                switch (options.type) {
                    case nodeType.Intent :
                        formElement.dxForm({
                            formData: options.formData,
                            items: [ formIntent ],
                        });
                        break;
                    case nodeType.Speak :
                        formElement.dxForm({
                            formData: options.formData,
                            items: [ formSpeak ],
                        })
                        break;
                    case nodeType.Slot :
                        formElement.dxForm({
                            formData: options.formData,
                            items: [ formSlot ],
                        });
                        break;
                    case nodeType.Split :
                        formElement.dxForm({
                            formData: options.formData,
                            items: [ formSplit ],
                        });
                        break;
                    case nodeType.API :
                        formElement.dxForm({
                            formData: options.formData,
                            items: [ formApi ],
                        })
                        break;
                    case nodeType.Common :
                        formElement.dxForm({
                            formData: options.formData,
                            items: [ formCommon ],
                        });
                        break;
                    case nodeType.Function :
                        formElement.dxForm({
                            formData: options.formData,
                            items: [ formFunction ],
                        });
                        break;

                    case nodeType.Call :
                        formElement.dxForm({
                            formData: options.formData,
                            items: [ formCall ],
                        });

                        break;
                    case "verticalContainer": case "horizontalContainer" :
                        // items = [];
                        break;

                    default:

                        break;
                }

                form = formElement.dxForm("instance");
                // 인스턴스 생성 이후 작업

                if (options.type == nodeType.Split) {
                    let formItems = form.option("items");

                    edgeSearch.forEach((edge, i) => {
                        let findNode = nodeItems.find( node => node.ID == edge.to);
                        let splitGroup = JSON.parse(JSON.stringify(formGroupSplitNextNode));    // Object deep copy
                        splitGroup.items[0].dataField = "conditionList." + i + ".nextNodeName";
                        splitGroup.items[0].editorOptions.value = findNode.nodeName;    // diagram json 값 설정을 위해서는  value, text 둘다 세팅 필요
                        splitGroup.items[0].editorOptions.text = findNode.nodeName; // 화면에 표시만 하려면 text 값만 세팅
                        form.updateData("conditionList." + i + ".nextNodeName", findNode.nodeName);

                        splitGroup.items[1].dataField = "conditionList."+ i +".nextNode";
                        splitGroup.items[1].editorOptions.value = findNode.nodeCode;
                        splitGroup.items[1].editorOptions.text = findNode.nodeCode;
                        form.updateData("conditionList."+ i +".nextNode", findNode.nodeCode);

                        splitGroup.items[2].dataField = "conditionList." + i +".condition";
                        splitGroup.items[3].dataField = "conditionList." + i +".nodeMent";

                        formItems.push(splitGroup);
                    });
                } else if (options.type == nodeType.API){
                    if(!$.utils.isBlank(options.formData.apiNodeSeq) && !(options.formData.apiNodeSeq == -1)){
                        ViewEvent.apiNodeValueChanged(options.formData.apiNodeSeq, false);
                    }
                } else if (options.type == nodeType.Function) {
                    if ((Object.keys(options.formData).includes('funcParam')) && Object.keys(form.option("formData").funcParam).length != 0) {
                        functionParamList = form.option("formData").funcParam;
                    } else {
                        functionParamList = {0: ""};
                    }

                    let formItems = form.option("items");
                    let functionGroup = JSON.parse(JSON.stringify(formGroupFunctionParameter));

                    functionGroup.items[0].items = ViewEvent.getFunctionParameter(functionParamList);
                    functionGroup.items[1].buttonOptions.onClick = ViewEvent.functionParameterBtn;

                    formItems.push(functionGroup);
                    formItems.push(formItemFunctionJavaScript);

                    setTimeout(ViewEvent.switchTabSpace, 1);
                    setTimeout(ViewEvent.deleteSpace, 1);

                } else if (options.type == nodeType.Common) {
                    if(!$.utils.isBlank(options.formData.commonNodeSeq) && !(options.formData.commonNodeSeq === -1)){
                        ViewEvent.cmmNodeValueChanged(options.formData.commonNodeSeq);
                    }
                }

                form.option("showColonAfterLabel", false);
                if(!checkPermissionPolicy("rcpconversationscenariomanageFull")) {
                    form.option("readOnly", true);
                }
                $container.children().append(formElement);

                const $buttonsContainer = $('<div class="dx-fieldset buttons" />').appendTo($container.children());
                $buttonsContainer.append(
                    $('<button class="btn grey" />').dxButton({
                        text: '취소',
                        onClick: cancelEditNode,
                    }),
                    $('<button class="btn" />').dxButton({
                        text: '저장',
                        // type: 'default',
                        onClick: updateNode,
                    }),
                );

                $("#popup").dxPopup({
                    title: options.type,
                });

                // ViewEvent.createScrollBar(data);

                $("#scrollView").dxScrollView({
                    // useNative : true,
                });
            }
        }

        const editNode = function (options) {
            popup = $('#popup').dxPopup("instance");
            popup.option("contentTemplate", popupContentTemplate(options))
            popup.show();
        };
        const updateNode = function () {
            // 2레벨 데이터 초기화를 위해 Object 복사
            let tmp = Object.assign({}, form.option("formData"));
            switch (form.option("formData").type ) {
                case nodeType.Split:
                    // conditionList 하위 초기화
                    tmp.conditionList = "";
                    store.push([{
                        type: 'update',
                        key: form.option("formData").ID,
                        data: tmp,
                    }]);
                    store.push([{
                        type: 'update',
                        key: form.option("formData").ID,
                        data: form.option("formData"),
                    }]);
                    break;
                case nodeType.API:
                    tmp.reqParamList = "";
                    tmp.resParamList = "";
                    store.push([{
                        type: 'update',
                        key: form.option("formData").ID,
                        data: tmp,
                    }]);
                    store.push([{
                        type: 'update',
                        key: form.option("formData").ID,
                        data: form.option("formData"),
                    }]);
                    break;
                case nodeType.Common:
                    // commonParam 값 하위 초기화
                    tmp.commonParam = "";
                    store.push([{
                        type: 'update',
                        key: form.option("formData").ID,
                        data: tmp,
                    }]);
                    store.push([{
                        type: 'update',
                        key: form.option("formData").ID,
                        data: form.option("formData"),
                    }]);
                    break;
                case nodeType.Function:
                    // funcParam 값 하위 초기화
                    tmp.funcParam = "";
                    store.push([{
                        type: 'update',
                        key: form.option("formData").ID,
                        data: tmp,
                    }]);
                    store.push([{
                        type: 'update',
                        key: form.option("formData").ID,
                        data: form.option("formData"),
                    }]);
                    break;
                default:
                    store.push([{
                        type: 'update',
                        key: form.option("formData").ID,
                        data: form.option("formData"),
                    }]);
            }
            popup.hide();

            setTimeout(ViewEvent.ScenarioVarList, 300, true)
            let nodeData = form.option("formData");
            let alertNode = [];
            // 각 노드별 필수값정리
            if(($.utils.isBlank(nodeData.nodeCode) && nodeData.nodeCode !== 0)) {
                alertNode.push(" 노드코드");
            }
            switch (nodeData.type) {
                case nodeType.Intent :
                    if ($.utils.isBlank(nodeData.intentSeq) || nodeData.intentSeq === -1) {
                        alertNode.push(" 인텐트 명");
                    }
                    if(alertNode.length !== 0) {
                        $.utils.info(alertNode + " 항목은 필수값 입니다");
                    }
                    break;
                case nodeType.Speak :
                    if ($.utils.isBlank(nodeData.nodeMent)) {
                        alertNode.push(" 멘트");
                    }
                    if(alertNode.length !== 0) {
                        $.utils.info(alertNode + " 항목은 필수값 입니다");
                    }
                    break;
                case nodeType.Slot :
                    if ($.utils.isBlank(nodeData.paramName)) {
                        alertNode.push(" 파라메터ID");
                    }
                    if ($.utils.isBlank(nodeData.nodeMent)) {
                        alertNode.push(" 멘트");
                    }
                    if (nodeData.actionType !== "DTMF") {
                        if ($.utils.isBlank(nodeData.entityType)) {
                            alertNode.push(" 엔티티타입");
                        }
                    }
                    if(alertNode.length !== 0) {
                        $.utils.info(alertNode + " 항목은 필수값 입니다");
                    }
                    break;
                case nodeType.Split :
                    if("conditionList" in nodeData){
                        for (let i = 0; i < Object.keys(nodeData.conditionList).length; i++) {
                            if(!("condition" in nodeData.conditionList[i]) || $.utils.isBlank(nodeData.conditionList[i].condition)) {
                                alertNode.push(" 조건");
                                break;
                            }
                        }
                    }
                    if(alertNode.length !== 0) {
                        $.utils.info(alertNode + " 항목은 필수값 입니다");
                    }
                    break;
                case nodeType.API :
                    if ($.utils.isBlank(nodeData.apiNodeSeq) || nodeData.apiNodeSeq === -1) {
                        alertNode.push(" API 노드");
                    }
                    if(alertNode.length !== 0) {
                        $.utils.info(alertNode + " 항목은 필수값 입니다");
                    }
                    break;
                case nodeType.Common :
                    if ($.utils.isBlank(nodeData.commonNodeSeq) || nodeData.commonNodeSeq === -1) {
                        alertNode.push(" Common 노드");
                    }
                    if(alertNode.length !== 0) {
                        $.utils.info(alertNode + " 항목은 필수값 입니다");
                    }

                    // todo 임시로 Common 수정할때만 작동하도록 변경
                    setTimeout( function () {
                        $.each(scenarioParam, function(key, value) {
                            if (value.length > 1) {
                                $.utils.info(key + " 변수는 중복됩니다");
                            }
                        });
                    }, 500 )
                    break;
                case nodeType.Function :
                    break;
                case nodeType.Call :
                    // javascript에서 0은 false값. callProcess가 0(콜처리선택)일때 처리
                    if ($.utils.isBlank(nodeData.nodeMent)) {
                        alertNode.push(" 멘트");
                    }
                    if (nodeData.callProcess  == "none") {
                        alertNode.push(" 콜처리");
                    }
                    if(alertNode.length !== 0) {
                        $.utils.info(alertNode + " 항목은 필수값 입니다");
                    }
                    break;

                default:
                    break;
            }

        };

        const cancelEditNode = function () {
            popup.hide();
        };


        $('#diagram').dxDiagram({
            editing: ViewEvent.editingConfig(),
            // 왼쪽 툴바의 노드 설정
            customShapes: [
                {
                    type: nodeType.Intent,
                    category: 'Node',
                    toolboxWidthToHeightRatio: 2,
                    allowEditText: false,
                    title: nodeType.Intent,
                    allowResize: false, // Not resize
                    backgroundImageUrl: commonUtil.getContextPath() + '/lib/assets/images/node-navy.png',
                    backgroundImageLeft: 0,
                    backgroundImageTop: 0.05,
                    backgroundImageWidth: 1,
                    backgroundImageHeight: 0.9,
                    defaultWidth: 1.9,
                    defaultHeight: 0.75,
                },
                {
                    type: nodeType.Speak,
                    category: 'Node',
                    title: nodeType.Speak,
                    toolboxWidthToHeightRatio: 2,
                    allowResize: false,
                    backgroundImageUrl: commonUtil.getContextPath() + '/lib/assets/images/node-mint.png',
                    backgroundImageLeft: 0,
                    backgroundImageTop: 0.05,
                    backgroundImageWidth: 1,
                    backgroundImageHeight: 0.9,
                    allowEditText: false,
                    defaultWidth: 1.9,
                    defaultHeight: 0.75,
                },
                {
                    type: nodeType.Slot,
                    category: 'Node',
                    title: nodeType.Slot,
                    toolboxWidthToHeightRatio: 2,
                    allowResize: false,
                    backgroundImageUrl: commonUtil.getContextPath() + '/lib/assets/images/node-purple.png',
                    backgroundImageLeft: 0,
                    backgroundImageTop: 0.05,
                    backgroundImageWidth: 1,
                    backgroundImageHeight: 0.9,
                    allowEditText: false,
                    defaultWidth: 1.9,
                    defaultHeight: 0.75,
                },
                {
                    type: nodeType.Split,
                    category: 'Node',
                    title: nodeType.Split,
                    toolboxWidthToHeightRatio: 2,
                    allowResize: false,
                    backgroundImageUrl: commonUtil.getContextPath() + '/lib/assets/images/node-red.png',
                    backgroundImageLeft: 0,
                    backgroundImageTop: 0.05,
                    backgroundImageWidth: 1,
                    backgroundImageHeight: 0.9,
                    allowEditText: false,
                    defaultWidth: 1.9,
                    defaultHeight: 0.75,
                },
                {
                    type: nodeType.API,
                    category: 'Node',
                    title: nodeType.API,
                    toolboxWidthToHeightRatio: 2,
                    allowResize: false,
                    backgroundImageUrl: commonUtil.getContextPath() + '/lib/assets/images/node-black.png',
                    backgroundImageLeft: 0,
                    backgroundImageTop: 0.05,
                    backgroundImageWidth: 1,
                    backgroundImageHeight: 0.9,
                    allowEditText: false,
                    defaultWidth: 1.9,
                    defaultHeight: 0.75,
                },
                {
                    type: nodeType.Common,
                    category: 'Node',
                    title: nodeType.Common,
                    toolboxWidthToHeightRatio: 2,
                    allowResize: false,
                    backgroundImageUrl: commonUtil.getContextPath() + '/lib/assets/images/node-pink.png',
                    backgroundImageLeft: 0,
                    backgroundImageTop: 0.05,
                    backgroundImageWidth: 1,
                    backgroundImageHeight: 0.9,
                    allowEditText: false,
                    defaultWidth: 1.9,
                    defaultHeight: 0.75,
                },
                {
                    type: nodeType.Function,
                    category: 'Node',
                    title: nodeType.Function,
                    toolboxWidthToHeightRatio: 2,
                    allowResize: false,
                    backgroundImageUrl: commonUtil.getContextPath() + '/lib/assets/images/node-green.png',
                    backgroundImageLeft: 0,
                    backgroundImageTop: 0.05,
                    backgroundImageWidth: 1,
                    backgroundImageHeight: 0.9,
                    allowEditText: false,
                    defaultWidth: 1.9,
                    defaultHeight: 0.75,
                },
                {
                    type: nodeType.Call,
                    category: 'Node',
                    title: nodeType.Call,
                    toolboxWidthToHeightRatio: 2,
                    allowResize: false,
                    backgroundImageUrl: commonUtil.getContextPath() + '/lib/assets/images/node-yellow.png',
                    backgroundImageLeft: 0,
                    backgroundImageTop: 0.05,
                    backgroundImageWidth: 1,
                    backgroundImageHeight: 0.9,
                    allowEditText: false,
                    defaultWidth: 1.9,
                    defaultHeight: 0.75,
                },
            ],

            // 노드를 끌어다 놨을때의 정보
            customShapeTemplate(item, $container) {
                const node = item.dataItem;
                const svgNS = 'http://www.w3.org/2000/svg';
                const $content = $(document.createElementNS(svgNS, 'svg'))
                    .addClass('template')
                    .attr({ width: "100%", height: "100%" })
                $(document.createElementNS(svgNS, 'text'))
                    .addClass('template-name')
                    .attr({ x: '50%', y: '30%' })
                    .text(item ? item.type : "")
                    .appendTo($content);
                $(document.createElementNS(svgNS, 'text'))
                    .addClass('template-title')
                    .attr({ x: '50%', y: '71%' })
                    .text(node ? ViewEvent.spliceNodeName(node.nodeName) : "")
                    .appendTo($content);
                $container.append($content);

            },
            nodes: {
                dataSource: store,
                keyExpr: 'ID',
                customDataExpr(obj, value) {
                    if (value === undefined) {
                        Object.keys(obj).forEach((key) => (obj[key] == null) && delete obj[key]);
                        return obj;
                    }
                    Object.keys(value).forEach((key) => (obj[key] = value[key]));
                    return null;
                },
                autoLayout: {
                    type: 'off',
                },
                // containerChildrenExpr: "children",
            },
            edges: {
                dataSource : edgeStore,
                keyExpr: "id",
                fromExpr: "from",
                toExpr: "to"
            },
            onContentReady(e) {
                if (!e.component._isLoaded) {
                    e.component._isLoaded = true;
                    let diagram = e.component;
                    delete diagram._diagramInstance.commandManager.shortcutsToCommand[65625]; //redo
                    delete diagram._diagramInstance.commandManager.shortcutsToCommand[65626]; //undo
                }
            },
            onRequestLayoutUpdate(e) {
                for (var i = 0; i < e.changes.length; i += 1) {
                    if (e.changes[i].type === 'remove') {
                        e.allowed = true;
                    } else if (e.changes[i].data.Head_ID !== undefined && e.changes[i].data.Head_ID !== null) {
                        e.allowed = true;
                    }
                }
            },
            onRequestEditOperation(e){
                const diagram = $('#diagram').dxDiagram().dxDiagram('instance');
                if (e.operation === 'changeConnection') {
                    const shapeType = e.args.newShape && e.args.newShape.type;

                    if (e.args.connector !== undefined) {
                        if (e.args.connectorPosition === 'end') {
                            if (e.args.connector.fromId === e.args.connector.toId) {
                                if (e.reason !== 'checkUIElementAvailability') {
                                    ViewEvent.showToast("Node는 자신을 연결할 수 없습니다.");
                                }
                                e.allowed = false;
                            }

                            if (e.args.connector.fromId != null && e.args.connector.toId != null) {
                                let edgeItems = diagram.getEdgeDataSource().items();
                                edgeItems.forEach((edge) => {
                                        if (edge.from == e.args.connector.fromKey && edge.to == e.args.connector.toKey) {

                                            if (e.reason !== 'checkUIElementAvailability') {
                                                ViewEvent.showToast("이미 연결된 화살표가 있습니다.");
                                            }
                                            e.allowed = false;
                                        }
                                    });
                            }
                        }
                    }

                    // 노드에서 커넥터를 받을 수 없음
                    if (shapeType === nodeType.Intent && e.args.connectorPosition === 'end') {
                        if (e.reason !== 'checkUIElementAvailability') {
                            ViewEvent.showToast("Intent Node는 커넥터를 받을수 없습니다");
                        }
                        e.allowed = false;
                    }

                    // 받는 노드가 없으면 화살표를 그릴수 없음
                    if (shapeType === undefined) {
                        e.allowed = false;
                    }

                    // 노드에서 커넥터를 보낼 수 없음
					if (shapeType === nodeType.Call && e.args.connectorPosition === 'start') {
						e.allowed = false;
					}

                    // Split Node 제외하고는 커넥터를 2개 이상 보낼 수 없음
                    if(shapeType !== 'Split') {
                        if (e.args.newShape !== undefined && e.args.connectorPosition === 'start') {
                            const nodeId = e.args.newShape.key;
                            let edgeItems = diagram.getEdgeDataSource().items();
                            let edgeFrom = edgeItems.filter( (edge) => edge.from === nodeId);
                            if(edgeFrom.length > 0) {
                                if (e.reason !== 'checkUIElementAvailability') {
                                    ViewEvent.showToast('커넥터를 2개 이상 사용할 수 없슴다');
                                }
                                e.allowed = false;
                            }
                        }
                    }

                    // container에서는 커넥터를 내보내거나 받을수없음
                    if (e.args.newShape !== undefined && (shapeType === 'verticalContainer' || shapeType === 'horizontalContainer')) {
                        e.allowed = false;
                    }

                }

                // Intent Node 2개 이상 사용할 수 없음
                if (e.operation === 'addShape') {
                    let intentNode = [];
                    diagram.getItems().forEach( function(data) {
                        intentNode.push(data.type);
                        let count = intentNode.filter(element =>  'Intent' === element).length;
                        if(count > 1) {
                            e.component.getItems().forEach(function(item) {
                                if (item.itemType === "shape" && item.type === e.args.shape.type) {
                                    if (e.reason !== 'checkUIElementAvailability') {
                                        ViewEvent.showToast('Intent Node는 2개 이상 사용할 수 없습니다.');
                                    }
                                    e.allowed = false;
                                }
                            });
                        }
                    });

                    let commonNode = [];
                    diagram.getItems().forEach( function(data) {
                        commonNode.push(data.type);
                        let count = commonNode.filter(element =>  'Common' === element).length;
                        if(count > 1) {
                            e.component.getItems().forEach(function(item) {
                                if (item.itemType === "shape" && item.type === e.args.shape.type) {
                                    if (e.reason !== 'checkUIElementAvailability') {
                                        ViewEvent.showToast('Common Node는 2개 이상 사용할 수 없습니다.');
                                    }
                                    e.allowed = false;
                                }
                            });
                        }
                    });
                }

                if (e.operation === 'deleteShape' && e.reason !== 'checkUIElementAvailability'){
                    const nodeId = e.args.shape.key;
                    let edgeItems = diagram.getEdgeDataSource().items();
                    let nodeItems = diagram.getNodeDataSource().items();
                    let edgeTo = edgeItems.filter( (edge) => edge.to === nodeId);
                    let edgeFrom = edgeItems.filter( (edge) => edge.from === nodeId);

                    let splitNodeItems;
                    let splitNodeId;

                    edgeTo.forEach( (e) => {
                        splitNodeItems = nodeItems.filter( (data) => data.ID === e.from )
                        splitNodeId = e.from;
                    });
                    // Split의 하위 노드를 삭제했을때 store에서도 삭제
                    if(!$.utils.isBlank(splitNodeItems)) {
                        if (splitNodeItems[0].type == nodeType.Split) {
                            let splitNodeItem;
                            let tempSplitNode = {};
                            let cnt = 0;

                            splitNodeItem = splitNodeItems[0].conditionList
                            $.each(splitNodeItem, function (i, value) {
                                if(value.nextNode !== nodeId) {
                                    tempSplitNode[cnt] = value;
                                    cnt++;
                                }
                            });

                            let newSplitNodeData = $.extend(true, {}, splitNodeItems[0]);
                            newSplitNodeData.conditionList = tempSplitNode;

                            store.push([{
                                type: 'remove',
                                key: splitNodeId
                            }]);

                            store.push([{
                                type: 'insert',
                                key: splitNodeId,
                                data: newSplitNodeData,
                            }]);
                        }
                    }

                    edgeTo.forEach( (e) => {
                        edgeStore.push([{ type: "remove", key: e.ID }]);
                    });

                    edgeFrom.forEach( (e) => {
                        edgeStore.push([{ type: "remove", key: e.ID }]);
                    });

                    store.push([{type : "remove", key : nodeId}]);
                    setTimeout(ViewEvent.ScenarioVarList, 300, true)
                }

            },
            contextToolbox: {
                shapeIconsPerRow: 1,
//				width: 150,
                enabled: false,
                visibility: "visible"
            },
            toolbox: {
                shapeIconsPerRow: 2,
                width: 170,
                showSearch: false,
                groups: [
                    { category: 'Node', title: 'Node', expanded: true, displayMode: "texts"},
                    { category: 'containers', title: 'Group', expanded: true },
                ],
            },
            viewUnits: "in",
            units: "in",
            showGrid: true,
            simpleView: true,
            historyToolbar: { visible: false, },
            mainToolbar: { visible: false, },
            propertiesPanel: { visibility: "disabled", },
            viewToolbar: {
                commands: ["zoomLevel", "fullScreen", "toolbox", {name: "Parameters", text: "Scenario Parameter list", icon: "custom-variable"}, {name: "Test", text: "Scenario Test", icon: "custom-test"}],
            },
            onCustomCommand: function(e) {
                switch (e.name){
                    case "Parameters":
                        // alert("Scenario Parameters");
                        $('.dx-icon-custom-variable').toggleClass('active');
                        $('.diagram-variable').toggleClass('active');
                        break;
                    case "Test":
                        // alert("Scenario Test");
                        $('.dx-icon-custom-test').toggleClass('active');
                        $('.diagram-test').toggleClass('active');
                        break;
                    default:
                        alert("onCustomCommand default")
                }

            },
            onItemDblClick : (node) => {
                if(node.item.dataItem.type === "verticalContainer" || node.item.dataItem.type === "horizontalContainer" || node.item.itemType === "connector"){

                } else {
                    $("#nodeType").val(node.item.dataItem.type);
                    let dataItem = node.item.dataItem;

                    if(node.item.type == nodeType.Split) {
                        let conditionList = node.item.dataItem.conditionList;
                        let edgeItems = $('#diagram').dxDiagram('instance').getEdgeDataSource().items();
                        let edgeSearch = edgeItems.filter(edge => edge.from == dataItem.ID);

                        let tempDataItem = {};
                        let cnt = 0;
                        $.each(conditionList, function (i, value) {
                            for (let j = 0; j < edgeSearch.length; j++) {
                                if(edgeSearch[j].to === value.nextNode) {
                                    tempDataItem[cnt] = value;
                                    cnt++;
                                }
                            }
                        });
                        dataItem.conditionList = tempDataItem;
                    }

                    const options = {
                        type: node.item.type,
                        name: node.item.dataItem && node.item.dataItem.name,
                        formData: dataItem
                    }

                    editNode(options);
                    setTimeout(ViewEvent.deleteSpace, 1);
                }
            }
        }).dxDiagram('instance').import(data.textContents);

        $('.toolbox-text-item').each(function () {
            var toolboxDataName = $(this).attr('data-tb-type');
            var toolboxDataNameTrim = toolboxDataName.replace(/ /gi, "");
            var toolboxDataNameCase = toolboxDataNameTrim.toLowerCase()
            $(this).addClass(toolboxDataNameCase)
        })
    },

};

var ReqEvent = {

    // 데이터 저장
    reqInsertData : function(){
        commonUtil.doAction({
            "url" : commonUtil.getContextPath() + "/admin/rcp/conversation/scenario/save/diagram",
            "data" : {
                masterSeq: $("#scenarioInfo").attr("masterSeq"),
                textContents : JSON.stringify(jsonData),
                custCode : $("#scenarioInfo").attr("custCode"),
                serviceGroup : $("#scenarioInfo").attr("serviceGroup")
                // rfSeq : $("#devName").val(),
                // tableCode : $("#devName").val(),
                // columnCode : $("#devName").val(),
            },
            "callBack" : ResEvent.resInsertData
        });
    },

    // 데이터 불러오기
    reqGetData : function(){
        commonUtil.doAction({
            "url" : commonUtil.getContextPath() + "/admin/rcp/conversation/scenario/select/diagram",
            "data" : {
                seq: $("#scenarioInfo").attr("masterSeq"),
                // rfSeq : $("#devName").val(),
                // tableCode : $("#devName").val(),
                // columnCode : $("#devName").val()
            },
            "callBack" : ResEvent.resGetData
        });
    },

    reqGetApiNodeList : function () {
        commonUtil.doAction({
            "url": commonUtil.getContextPath()+ "/admin/rcp/conversation/selectApiNodeList",
            "data" : {
                custCode : $("#scenarioInfo").attr("custCode"),
                serviceGroup : $("#scenarioInfo").attr("serviceGroup"),
                containUpper: true
            },
            "callBack" : ResEvent.resGetApiNodeList
        });
    },

    reqGetCommonNodeList : function () {
        commonUtil.doAction({
            "url": commonUtil.getContextPath()+ "/admin/rcp/conversation/selectCmmNodeList",
            "data" : {
                custCode : $("#scenarioInfo").attr("custCode"),
                serviceGroup : $("#scenarioInfo").attr("serviceGroup"),
                containUpper: true
            },
            "callBack" : ResEvent.resGetCommonNodeList
        });
    },

    reqGetIntentNodeList : function() {
        let oprMngCode = $("#scenarioInfo").attr("custCode") + "_RCP_" + $("#scenarioInfo").attr("serviceGroup");
        commonUtil.doActionText({
            "url": commonUtil.getContextPath()+ "/admin/rcp/conversation/intent/search.do",
            "data" : {
                custCode : $("#scenarioInfo").attr("custCode"),
                serviceGroup : $("#scenarioInfo").attr("serviceGroup"),
            },
            "callBack" : ResEvent.resGetIntentNodeList
        });
    },

    reqGetEntityList : function () {
        commonUtil.doActionGet({
            "url": commonUtil.getContextPath()+ "/admin/rcp/conversation/scenario/systemEntity/list",
            "data" : {},
            "callBack" : ResEvent.resGetEntityList
        });
    },

    reqScenarioTestInit : function () {
        commonUtil.doActionGet({
            "url": commonUtil.getContextPath()+ "/admin/rcp/conversation/scenario/test/contents",
            "data" : {
                masterSeq: $("#scenarioInfo").attr("masterSeq")
            },
            "callBack" : ResEvent.resScenarioTestInit
        })
    },

    reqScenarioTestAPI : function(methodType, userTalk) {
        dnis = $("#scenarioTestNum option:selected").val();

        if (methodType == "INIT") {
            callId = $.utils.getDateNow("") + "_" + $.utils.getUUID();
        }

        if (!$.utils.isBlank(callId)){
            commonUtil.doActionGet({
                "url": commonUtil.getContextPath()+ "/admin/rcp/learningTest/simulator/call-api.do",
                "data" : {
                    oprMngCode: "",
                    callId: callId,
                    token: scenarioTestToken,
                    userTalk: userTalk.replace(/\n/g, ""),  // 엔터키 제거하고 넘기기
                    methodType: methodType,
                    dnis: dnis
                },
                "callBack" : ResEvent.resScenarioTestAPI
            });
        } else {
            $.utils.warning("call id가 생성되지 않았습니다.");
        }
    },

    reqCallNumList: function () {
        commonUtil.doAction({
            "url": commonUtil.getContextPath()+ "/admin/rcp/learningTest/simulator/custCallNumlist.do",
            "data" : {
                custCode: $("#scenarioInfo").attr("custCode"),
                serviceGroup : $("#mainOpr").val(),
            },
            "callBack" : ResEvent.resCallNumList
        })
    }

};

var ViewEvent = {
    moveScenarioManager : function() {
        let url = commonUtil.getContextPath() + "/admin/rcp/conversation/scenario/manage.do";
        $.utils.redirect(url);
    },

    btnEvent : function(){

        $('#btnScenarioSave').on('click', function () {
            jsonData = JSON.parse($('#diagram').dxDiagram('instance').export());
            if (scenarioParam == undefined) {
                scenarioParam = {};
            }
            jsonData.scenarioParam = scenarioParam;

            if ($('#scenarioInfo').attr("checksum") == $.utils.getStringToChecksum(JSON.stringify(jsonData)) ) {
                $.utils.info("변경된 내용이 없습니다.");
            } else {
                ReqEvent.reqInsertData();
            }
        });

        $('#btnScenarioCancel').on('click', function () {
            // 변경사항이 없으면 목록으로, 변경사항이 없으면 url 이동
            jsonData = JSON.parse($('#diagram').dxDiagram('instance').export());
            jsonData.scenarioParam = scenarioParam;

            if ($('#scenarioInfo').attr("checksum") == $.utils.getStringToChecksum(JSON.stringify(jsonData)) ) {
                ViewEvent.moveScenarioManager();
                let url = commonUtil.getContextPath() + "/admin/rcp/conversation/scenario/manage.do";
                $.utils.redirect(url);
            } else {
                $.utils.confirm("확인버튼을 누르면 기존에 작업한 내용은 저장되지 않습니다.\n " +
                    "시나리오 관리 화면으로 이동하시겠습니까?",
                    ViewEvent.moveScenarioManager);
            }
        });

        $('#btnScenarioFileLoad').on('click', function () {
            $("#selectJsonFile, #inputJsonUpload").val("");
        });

        $('#btnScenarioDownload').on('click', function () {
            let jsonDownloadData = {};
            let jsonData = JSON.parse($('#diagram').dxDiagram('instance').export());
            jsonData.checksum = $.utils.getStringToChecksum(JSON.stringify(jsonData));
            jsonDownloadData.textContents = jsonData;
            jsonDownloadData = JSON.stringify(jsonDownloadData);

            // 오늘날짜 YYYYMMDD_HHmmSS형식
            const now = new Date();
            const year = now.getFullYear();
            const month = String(now.getMonth() + 1).padStart(2, '0');
            const day = String(now.getDate()).padStart(2, '0');
            const hours = String(now.getHours()).padStart(2, '0');
            const minutes = String(now.getMinutes()).padStart(2, '0');
            const seconds = String(now.getSeconds()).padStart(2, '0');
            const formattedDate = `${year}${month}${day}_${hours}${minutes}${seconds}`;

            let nodeName = $("#scenarioName").val();
            let filename = nodeName + "_diagram_" + formattedDate + ".json";
            let blob = new Blob([jsonDownloadData], {type: "application/json"});
            let url = URL.createObjectURL(blob);
            let link = document.createElement("a");
            link.setAttribute("href", url);
            link.setAttribute("download", filename);
            document.body.appendChild(link);
            link.click();
            document.body.removeChild(link);

        });

        $('.tabVariableClose').on('click', function (e) {
            e.preventDefault();
            $('.dx-icon-custom-variable').toggleClass('active');
            $('.diagram-variable').toggleClass('active');
        });

        $('.tabTestClose').on('click', function (e) {
            e.preventDefault();
            $('.dx-icon-custom-test').toggleClass('active');
            $('.diagram-test').toggleClass('active');
        });

        $('.debugModeBtn').on('click', function (e) {
            e.preventDefault();
            $(this).toggleClass('active');
            $('.diagram-test').toggleClass('debugMode');
        });

        $('.refresh').on('click', function (e) {
            e.preventDefault();
            ViewEvent.clearChat();
            ViewEvent.clearTestParam();

            // 시나리오 변수 변수 초기화
            callId = "";
            scenarioTestToken = "";

            // 버튼, testNum 연결 가능하도록 init
            $("#btnTestConnect").text("연결");
            $("#btnTestConnect").attr("class", "minico");

            $("#scenarioTestNum").removeAttr("disabled");
            $('#scenarioTestNum').niceSelect('update');
        });

        $("#btnTestConnect").on('click', function (e) {
            if($("#btnTestConnect").text() == "연결" ) {
                ReqEvent.reqScenarioTestInit();
            }
        });

        // 채팅 이벤트
        $("#chatInput").on("keyup", function (key) {
            if (key.keyCode == 13) {
                ViewEvent.insertChat($(this).val());
                $(this).val("");
                $(".content-scroll").scrollTop($(".content-scroll")[0].scrollHeight);
            }
        });

        // 채팅 보내기
        $("#sendChat").on("click", function () {
            ViewEvent.insertChat($("#chatInput").val());
            $("#chatInput").val("");
            $(".content-scroll").scrollTop($(".content-scroll")[0].scrollHeight);
        })

        // json 파일 선택
        $("#selectJsonFile").on("change", function () {
            let checkJsonFile = $(this).val();
            let ext = checkJsonFile.split('.').pop().toLowerCase();
            if($.inArray(ext, ["json"]) == -1) {
                $.utils.error('올바른 파일 형식이 아닙니다.');
                $(this).val("");
                return;
            }
            let fileName = $(this).prop("files")[0].name;
            let fileSize = $(this).prop("files")[0].size;

            // .json까지 포함했을때의 파일 명
            if(fileName.length+1 > 70) {
                $.utils.error('파일명이 너무 깁니다. 70자 이내로 수정해주세요.');
                $(this).val("");
                return;
            }

            // 파일의 사이즈가 3MB 초과시
            if(fileSize > (3 * 1024 * 1024) ) {
                $.utils.error('파일 크기가 3MB를 초과하여 업로드가 불가능합니다.');
                $(this).val("");
                return;
            }

            if($.utils.isBlank($(this).val())){
                $("#inputJsonUpload").val("");
            } else {
                $("#inputJsonUpload").val($(this).prop("files")[0].name);
            }
        })

        // json 파일 삭제
        $("#deleteJsonFile").on("click", function () {
            $("#selectJsonFile, #inputJsonUpload").val("");
        })

        // json 파일 읽기
        $("#jsonFileUpload").click(function() {

            let jsonFile = $("#selectJsonFile").prop("files")[0];
            let jsonReader = new FileReader();

            jsonReader.onload = function(event) {
                let jsonData = JSON.parse(event.target.result);
                let fileDiagramChecksum = jsonData.textContents.checksum;
                let fileDiagram = jsonData.textContents;
                delete fileDiagram.checksum;

                if(fileDiagramChecksum != $.utils.getStringToChecksum(JSON.stringify(fileDiagram))){
                    $.utils.error("파일이 변조되어 불러올 수 없습니다.");
                } else {
                    jsonData.textContents = JSON.stringify(jsonData.textContents);
                    ResEvent.resGetData(jsonData);
                    $.utils.success("다이어그램을 불러왔습니다.");
                    $("#scenarioLoadCancel").click();
                    setTimeout(ViewEvent.ScenarioVarList, 300, true);
                }
            }
            jsonReader.readAsText(jsonFile);
        });

    },

    clearChat : function() {
        $("#chat").empty();
    },

    insertChat : function(userTalk){

        if ($("#btnTestConnect").text() == "연결") { // 연결중 상태가 아닌때
            $.utils.warning("시나리오 테스트 연결중 상태가 아닙니다.");
            return;
        }

        if (userTalk == "" || userTalk.length == 0) {
            $.utils.warning("대화를 입력후 전송하세요.");
            return;
        }

        let nowDateTime = $.utils.getDateTimeNow(["-", "-", " ", ":", ":"]);
        let addChat = "";
        addChat = `<div class="monitering-msg user">
                    <span class="time">${nowDateTime}</span>
                    <div class="msg-desc">
                        <p> ${userTalk} </p>
                    </div>
                    <div class="msg-img">
                        <div class="msg-img userIconImg"></div>
                    </div>
                </div>`;
        $("#chat").append(addChat);
        ReqEvent.reqScenarioTestAPI("STT", userTalk);
    },

    replyChat : function(botResult){
        let addChat = "";
        addChat = `<div class="monitering-msg admin">
                    <div class="msg-img">
                        <div class="msg-img botIconImg"></div>
                    </div>
                    <div class="msg-desc gray2">
                        <p>
                            ${botResult.botTalk}
                        </p>
                    </div>
                    <span class="time">${botResult.time}</span>
                    <div class="debug-msg">${botResult.debug}</div>
                </div>`;
        $("#chat").append(addChat);
    },

    clearTestParam : function () {
        $("#testParam").empty();
    },
    addTestParam : function(key, value) {
        value = value.replace(/\"/g,"&quot;").replace(/&lt;/g, "<").replace(/&gt;/g, ">");
        let addData = "";
        addData = `<dl>
                    <dt>
                        <h4>${key}</h4>
                    </dt>
                    <dd>
                        <div class="ipt_box">
                            <input type="text" value="${value}" readonly>
                        </div>
                    </dd>
                </dl>`
        $("#testParam").append(addData);
    },

    debounce : function(){
        let timer;
        if (timer) {
            clearTimeout(timer);
        }
        timer = setTimeout(function() {
            $('.toolbox-text-item').each(function (i) {
                var toolboxDataName = $(this).attr('data-tb-type');
                var toolboxDataNameTrim = toolboxDataName.replace(/ /gi, "");
                var toolboxDataNameCase = toolboxDataNameTrim.toLowerCase()
                $(this).addClass(toolboxDataNameCase)
            })
        }, 300);
    },

    editingConfig : function() {

        var data = "";

        // true 값에 조회페이지 or 수정페이지 값을 넘김
        if(!checkPermissionPolicy("rcpconversationscenariomanageFull")) {
            data = {
                allowAddShape: false,
                allowChangeConnection: false,
                allowChangeConnectorPoints: false,
                allowChangeConnectorText: false,
                allowChangeShapeText: false,
                allowDeleteConnector: false,
                allowDeleteShape: false,
                allowMoveShape: false,
                allowResizeShape: false,
            };
        } else {
            data = {
                allowChangeConnectorText: false
            }
        }

        return data;
    },

    showToast : function(text) {
        DevExpress.ui.notify({
            position: {
                at: 'top', my: 'top', of: '#diagram', offset: '0 4',
            },
            message: text,
            type: 'warning',
            delayTime: 2000,
        });
    },

    ScenarioVarList : function (isLoad) {
        if (isLoad) {
            // 시나리오 node를 돌면서 시나리오 변수
            let nodeItems = $('#diagram').dxDiagram('instance').getNodeDataSource().items();
            scenarioParam = {
                "aiReservationReceiptYn": [],
                "reservationYn": [],
                "aiReservationConfirmYn": [],
                "downtownNum": [],
                "telNo": [],
                "talkText": [],
            };
            nodeItems.forEach( (node, i) => {
                switch (node.type) {
                    case nodeType.Slot:
                        if (node.paramName == null || node.paramName.length == 0){  return; }
                        if (scenarioParam[node.paramName] == undefined) {
                            scenarioParam[node.paramName] = [node.ID];
                        } else {
                            scenarioParam[node.paramName].push(node.ID);
                        }
                        break;
                    case nodeType.API:
                        if (node.resParamList == null || node.resParamList.length == 0){  return; }

                        Object.keys(node.resParamList).forEach(function (paramKey) {
                            if (node.resParamList[paramKey].resParamMap == null || node.resParamList[paramKey].resParamMap == undefined) { return; }

                            if (scenarioParam[node.resParamList[paramKey].resParamMap] == undefined ) {
                                scenarioParam[node.resParamList[paramKey].resParamMap] = [node.ID];
                            } else {
                                scenarioParam[node.resParamList[paramKey].resParamMap].push(node.ID);
                            }
                        })

                        break;
                    case nodeType.Function:
                        if (node.funcParam == null || node.funcParam.length == 0){  return; }

                        Object.keys(node.funcParam).forEach(function (paramKey) {
                            if (node.funcParam[paramKey] == null || node.funcParam[paramKey] == undefined) { return; }

                            if (scenarioParam[node.funcParam[paramKey]] == undefined ) {
                                scenarioParam[node.funcParam[paramKey]] = [node.ID];
                            } else {
                                scenarioParam[node.funcParam[paramKey]].push(node.ID);
                            }
                        })

                        break;
                    case nodeType.Common:
                        if (node.commonParam == null || node.commonParam.length == 0){  return; }

                        Object.keys(node.commonParam).forEach(function (paramKey) {
                            if (node.commonParam[paramKey] == null || node.commonParam[paramKey] == undefined) { return; }

                            if (scenarioParam[node.commonParam[paramKey]] == undefined ) {
                                scenarioParam[node.commonParam[paramKey]] = [node.ID];
                            } else {
                                scenarioParam[node.commonParam[paramKey]].push(node.ID);
                            }
                        })

                        break;
                    default:
                }
            });
        }

        let html = "<ul>";
        for(key in scenarioParam) {
            html += "<li>"+key+"<a href='#' class='ico copy'></a></li>";
        }
        html += "</ul>";
        $("#scenarioVarList").empty().html(html);

        $(".copy").click(function(){
            // 크롬 66 버전 이상
            // window.navigator.clipboard.writeText("#{" + $(this).parent().text() + "}").then( () =>{
            //     $.utils.success("복사되었습니다.");
            // })

            // 크롬 66 버전 미만
            let textarea = document.createElement('textarea');
            textarea.value = "#{" + $(this).parent().text() + "}";
            document.body.appendChild(textarea);
            textarea.select();
            document.execCommand('copy');
            document.body.removeChild(textarea);
            $.utils.success("복사되었습니다.");

        })
    },

    apiNodeValueChanged : function (data, isChange) {
        commonUtil.doAction({
            "url" : commonUtil.getContextPath()+ "/admin/rcp/conversation/selectApiNode",
            "data" : {
                seq : data
            },
            "callBack" : function (data) {
                let formItems = $("#form").dxForm("instance").option("items");
                // formItems에 추가된 항목 초기화
                if(formItems.length !== 1) {
                    formItems.length = 1;
                }
                
                // reqParamList, resParamList 값 초기화 후 변경된 값 저장
                if (isChange) {
                    form.option("formData").reqParamList = {};
                    form.option("formData").resParamList = {};
                }

                // API 빈 값 선택시 초기화
                if(data.apiData.length == 0){
                    formItems.length = 1;
                    $("#form").dxForm("instance").repaint();
                    return;
                }
                let json = JSON.parse(data.apiData[0].textContents);
                let apiRequestGroup = JSON.parse(JSON.stringify(formGroupApiRequest));
                let apiResponseGroup = JSON.parse(JSON.stringify(formGroupApiResponse));

                let pushData;
                for (let i = 0; i < json.request.length; i++) {
                    pushData = {
                        colSpan: 20,
                        dataField: "reqParamList[" + i +"].reqParamMap",
                        editorOptions: {
                            placeholder: "value",
                            // text : json.request[i].value
                            inputAttr: {
                                class: "paramAreaTrim"
                            }
                        },
                        label: {
                            text: json.request[i].value,
                        },
                        editorType: "dxTextBox",
                        cssClass: "ipt_box",
                    }
                    apiRequestGroup.items.push(pushData);
                    form.updateData("reqParamList[" + i +"].reqParamName", json.request[i].value);
                }

                for (let i = 0; i < json.response.length; i++) {
                    pushData = {
                        colSpan: 20,
                        dataField: "resParamList[" + i +"].resParamMap",
                        editorOptions: {
                            placeholder: "value",
                            // text : json.request[i].value
                            inputAttr: {
                                class: "paramArea"
                            }
                        },
                        label: {
                            text: json.response[i].key
                        },
                        editorType: "dxTextBox",
                        cssClass: "ipt_box",
                    }
                    apiResponseGroup.items.push(pushData);
                    form.updateData("resParamList[" + i +"].resParamName", json.response[i].key);
                }
                formItems.push(apiRequestGroup);
                formItems.push(apiResponseGroup);

                $("#form").dxForm("instance").repaint();
                setTimeout(ViewEvent.deleteSpace, 1);
                setTimeout(ViewEvent.deleteSpaceTrim, 1);
            }

        });
    },

    cmmNodeValueChanged : function (data) {
        commonUtil.doAction({
            "url" : commonUtil.getContextPath()+ "/admin/rcp/conversation/selectCmmNode",
            "data" : {
                seq : data
            },
            "callBack" : function (data) {
                let json = JSON.parse(data.textContents);
                let formItems = $("#form").dxForm("instance").option("items");
                // formItems에 추가된 항목 초기화
                if(formItems.length !== 1) {
                    formItems.length = 1;
                }

                // commonParam 값 초기화 후 저장
                form.option("formData").commonParam = {};

                // API 빈 값 선택시 초기화
                if(data.length == 0){
                    formItems.length = 1;
                    $("#form").dxForm("instance").repaint();
                    return;
                }
                let cmmParamGroup = JSON.parse(JSON.stringify(formGroupCommonParameter));

                let pushData;
                for (let i = 0; i < Object.keys(json.scenarioParam).length; i++) {
                    pushData = {
                        colSpan: 10,
                        dataField: "commonParam[" + i + "]",
                        editorOptions: {
                            placeholder: "value",
                            inputAttr: {
                                class: "paramArea"
                            },
                            readOnly : true
                            // text : Object.keys(json.scenarioParam)[i]
                        },
                        label: {
                            text: "param[" + i + "]",
                            visible: false,
                        },
                        editorType: "dxTextBox",
                        cssClass: "ipt_box",
                    }
                    cmmParamGroup.items.push(pushData);
                }
                formItems.push(cmmParamGroup);
                for (let i = 0; i < Object.keys(json.scenarioParam).length; i++) {
                    formItems[1].items[i].editorOptions.value = Object.keys(json.scenarioParam)[i];
                }

                $("#form").dxForm("instance").repaint();
                setTimeout(ViewEvent.deleteSpace, 1);
            }

        });
    },

    getFunctionParameter : function(funcParam) {
        const options = [];
        for (const key in funcParam) {
            if (funcParam.hasOwnProperty(key)) {
                options.push(ViewEvent.newFunctionParameters(key));
            }
        }

        return options;
    },

    newFunctionParameters : function (index) {
        return {
            dataField: `funcParam[${index}]`
            , editorType: 'dxTextBox'
            , label: {
                text: `funcParam[${index}]`,
                visible: false,
            }
            , editorOptions: {
                buttons: [{
                    name: "trash"
                    , location: "after"
                    , options: {
                        stylingMode: 'text'
                        , icon: 'trash'
                        , onClick() {
                            delete functionParamList[index];
                            form.itemOption('function.parameter', 'items', ViewEvent.getFunctionParameter(functionParamList));
                            setTimeout(ViewEvent.deleteSpace, 1);
                        }
                    }
                }]
                , inputAttr: {
                    class: "paramArea"
                }
            }
        }
    },

    functionParameterBtn : function() {
        if(!checkPermissionPolicy("rcpconversationscenariomanageFull")) {
            return;
        }

        let keys = Object.keys(functionParamList);
        let maxIndex = Math.max(...keys);
        if(maxIndex === -Infinity) {
            functionParamList[0] = "";
        } else {
            functionParamList[maxIndex+1] = "";
        }
        form.itemOption('function.parameter', 'items', ViewEvent.getFunctionParameter(functionParamList));
    },

    spliceNodeName : function(data) {
        if(typeof data === "string") {
            let length = 12; // 표시할 글자수 기준
            let displayNodeName = data;
            if (displayNodeName.length > length) {
                displayNodeName = displayNodeName.substr(0, length - 2) + '...';
            }
            return displayNodeName;
        } else {
            return data;
        }
    },

    switchTabSpace : function (){
        $(".jsArea").on("keydown", function (e) {
            let tabSize = 4; // 공백 대체 크기 (4칸)
            if(e.keyCode === 9) {
                let start = this.selectionStart;
                let end = this.selectionEnd;
                let value = $(this).val();
                let textBeforeCursor = value.substring(0, start); // 커서 이전 텍스트
                let textAfterCursor = value.substring(end); // 커서 이후 텍스트
                let tabSpaces = " ".repeat(tabSize); // 탭 대체 공백 문자열
                let replacedText = textBeforeCursor + tabSpaces + textAfterCursor; // 대체된 텍스트
                this.value = replacedText; // 입력 필드에 대체된 텍스트 설정
                this.selectionStart = start + tabSize; // 커서 위치 이동
                this.selectionEnd = start + tabSize; // 커서 위치 이동
                e.preventDefault();
            }
        });
    },

    deleteSpace : function(){
        $(".paramArea").on("keyup", function(event) {
            let inputVal = $(this).val();
            let newVal = inputVal.replace(/\s+/g, '');
            $(this).val(newVal);
        });
    },

    deleteSpaceTrim : function(){
        $(".paramAreaTrim").focusout(function() {
            let inputVal = $(this).val();
            let newVal = $.trim(inputVal);
            $(this).val(newVal);
        });
    },

    digitMinMax : function(){
        $(document).on("keyup", ".maxdigit", function(event) {
            let val = $(this).val();
            if (val < 1 && val !== "") {
                $(this).val(1);
            } else if (val > 30) {
                $(this).val(30);
            }
        });

        $(document).on("focusout", ".maxdigit", function(event) {
            let val = $(this).val();
            if (val < 1 && val !== "") {
                $(this).val(1);
            } else if (val > 30) {
                $(this).val(30);
            }
        });
    }

};

$(document).ready(function(){
    // 버튼 이벤트 실행
    ViewEvent.btnEvent();
    ViewEvent.digitMinMax();

    // 초기 입장 화면
    ReqEvent.reqGetData();
    ReqEvent.reqGetApiNodeList();
    ReqEvent.reqGetCommonNodeList();
    ReqEvent.reqGetIntentNodeList();
    ReqEvent.reqGetEntityList();
    ReqEvent.reqCallNumList();


    popup = $('#popup' ).dxPopup({
        width: 600,
        height: "auto",
        visible: false,
        dragEnabled: true,
        shading: false,
        hideOnOutsideClick: false,
        showCloseButton: true,
    })

    // 권한별 컨트롤 설정
    if (!checkPermissionPolicy("rcpconversationscenariomanageFull")) {
        $("#btnScenarioDownload").hide();
        $("#btnScenarioFileLoad").hide();
        $("#btnScenarioSave").hide();
    }

});

$(window).resize(function () {
    // diagram resize됐을때 이벤트
    ViewEvent.debounce();
})
