import icons from './icon.js'

function FlowDesigner(diagramDiv,event) {
    var G = go.GraphObject.make;
    var _this = {};
    var _designer = {};
    var myPalette = null
    var _jsonNewStep = { key: guid(), text: "审批节点", remark: '', type: 0 };

    /** 处理传入事件 */
    if(event.showEditNode){  //编辑节点
        _this.showEditNode = event.showEditNode
    }
    if(event.SelectionDeleted){  //删除事件
        _this.SelectionDeleted = event.SelectionDeleted
    }
    if(event.LinkDrawn){  //线的生成事件
        _this.LinkDrawn = event.LinkDrawn
    }
    if(event.externalobjectsdropped){  //节点的生成事件
        _this.externalobjectsdropped = event.externalobjectsdropped
    }

    if(event.LinkRelinked){  //连线修改
        _this.LinkRelinked = event.LinkRelinked
    }

    /** --------public method----------------------------------------**/
    /**
     * 初始化图例面板
     * 0审批节点 1开始节点 2结束节点 3操作节点 4服务节点
     * @returns {*}
     */
    this.initToolbar = function(div,moduleType){
        
        let modelArr = [
            // { key: guid(), text: "开始", figure: "Terminator", fill: "#4fba4f", type: 1 },
            { key: guid(), text: "审批节点", remark: '', type: 0, category:'Approval' },
            { key: guid(), text: "操作节点", remark: '', type: 4, category:'Operation' },
            { key: guid(), text: "服务节点", remark: '', type: 3, category:'Service' },
            { key: guid(), text: "子流程节点", remark: '', type: 6, category:'Subprocesses' }
            // { key: guid(), text: "结束", figure: "Terminator", fill: "#CE0620", type: 2 }
        ]
        if(!moduleType){
            modelArr = [{ key: guid(), text: "审批节点", remark: '', type: 0, category:'Approval' }]
        }
        if(!myPalette){
            var Palette =
            G(go.Palette, div, // 必须是DIV元素
                {
                    maxSelectionCount: 3,
                    nodeTemplateMap: _designer.nodeTemplateMap, // 跟设计图共同一套样式模板
                    model: new go.GraphLinksModel(modelArr)
                });
                
            myPalette = Palette
        }else{
            myPalette.model.nodeDataArray = modelArr
        }
        console.log(myPalette,222222)
        return myPalette;
    };

    /**
     * 在设计面板中显示流程图
     * @param flowData  流程图json数据
     */
    this.displayFlow = function (flowData) {

        if(!flowData) return;

        _designer.model = go.Model.fromJson(flowData);

        var pos = _designer.model.modelData.position;
        
        // if (pos) _designer.initialPosition = go.Point.parse(pos);
        this.diagram = _designer
        // 更改所有连线中间的文本背景色
        setLinkTextBg();
    };

    /**
     * 创建新步骤
     */
    this.createStep = function() {
        var jsonNewStep = {key:_jsonNewStep.key, text:_jsonNewStep.text};
        jsonNewStep.loc = "270 140";// “新步骤”显示的位置
        _designer.model.addNodeData(jsonNewStep);
    };

    /**
     * 获取流程图数据
     * @returns {*}
     */
    this.getFlowData = function () {
        _designer.model.modelData.position = go.Point.stringify(_designer.position);
        return _designer.model.toJson();
    };

    /**
     * 检验流程图是否规范
     */
    this.checkData = function() {
        var errMsg = "";

        // 检查：每个步骤必须包含角色
        if (!_designer.model.nodeDataArray) return '请绘制流程图';

        // $.each(_designer.model.nodeDataArray, function(i, item) {
        //     if (!item.hasOwnProperty("remark") || item.remark === "") {
        //         errMsg = "请为步骤【" + item.text + "】设置备注~";
        //         return false;
        //     }
        // });

        _designer.model.nodeDataArray.map(item => {
            if (!item.hasOwnProperty("remark") || item.remark === "") {
                errMsg = "请为步骤【" + item.text + "】设置备注~";
                return false;
            }
        })


        return errMsg;
    };



    /** --------public method-------------end---------------------------**/

    this.diagram = init(diagramDiv);

    /** --------private method----------------------------------------**/

    /**
     * 初始化流程设计器
     * @param divId 设计器Div
     * 
     * node type 
     */
    function init(divId) {
        _designer = G(go.Diagram, divId, // must name or refer to the DIV HTML element
                {  
                    // grid: G(go.Panel, "Grid",  背景格
                    //     G(go.Shape, "LineH", { stroke: "lightgray", strokeWidth: 0.5 }),
                    //     G(go.Shape, "LineH", { stroke: "gray", strokeWidth: 0.5, interval: 10 }),
                    //     G(go.Shape, "LineV", { stroke: "lightgray", strokeWidth: 0.5 }),
                    //     G(go.Shape, "LineV", { stroke: "gray", strokeWidth: 0.5, interval: 10 })
                    // ),
                    allowDrop: true, // must be true to accept drops from the Palette
                    allowTextEdit: false,
                    allowHorizontalScroll: true,
                    allowVerticalScroll: true,
                    // "clickCreatingTool.isDoubleClick":false,
                    // "clickCreatingTool.archetypeNodeData": {}, // 双击创建新步骤
                    // "draggingTool.dragsLink": true,
                    "draggingTool.isGridSnapEnabled": true,
                    // "linkingTool.isUnconnectedLinkValid": true,
                    "linkingTool.portGravity": 20,
                    // "relinkingTool.isUnconnectedLinkValid": true,
                    "relinkingTool.portGravity": 20,
                    "relinkingTool.fromHandleArchetype":
                        G(go.Shape, "Diamond", { segmentIndex: 0, cursor: "pointer", desiredSize: new go.Size(8, 8), fill: "tomato", stroke: "darkred" }),
                    "relinkingTool.toHandleArchetype":
                        G(go.Shape, "Diamond", { segmentIndex: -1, cursor: "pointer", desiredSize: new go.Size(8, 8), fill: "darkred", stroke: "tomato" }),
                    "linkReshapingTool.handleArchetype":
                        G(go.Shape, "Diamond", { desiredSize: new go.Size(7, 7), fill: "lightblue", stroke: "deepskyblue" }),
                    "undoManager.isEnabled": false
                });

        // 流程图如果有变动，则提示用户保存
        _designer.addDiagramListener("Modified", onDiagramModified);

        // 双击事件
        _designer.addDiagramListener("ObjectDoubleClicked", onObjectDoubleClicked);

        // 移除事件
        _designer.addDiagramListener("SelectionDeleted", function(e) {
            e.subject.each(function(n){
                _this.SelectionDeleted(n.data)
            });
        })

        //线的生成
        _designer.addDiagramListener("LinkDrawn", function(e) {
            e.subject.data.key = guid()
            _this.LinkDrawn(e.subject.data)
        })


        //线的重绘
        _designer.addDiagramListener("LinkRelinked", function(e) {
            _this.LinkRelinked(e.subject.data)
        })

        //添加监听节点生成事件
        _designer.addDiagramListener("externalobjectsdropped", function(e) {
            // var jsonNewStep = {key:_jsonNewStep.key, text:_jsonNewStep.text};
            e.subject.each(function(n){
                //得到从Palette拖过来的节点
                _this.externalobjectsdropped(n.data)
            });
            // jsonNewStep.loc = "-100 0";// “新步骤”显示的位置
            // jsonNewStep.type = 0 
            // jsonNewStep.key = guid()
            // // _designer.model.addNodeData(jsonNewStep);
            // _this.externalobjectsdropped(jsonNewStep)
        })


        //监听节点或线的删除前事件
        _designer.commandHandler.canDeleteSelection = function(e) { 
			//用例获取选中的节点或线 
			return _designer.selection.all(function(nodeOrLink) { 
				//判断是否是开始或者结束节点
				if(nodeOrLink.data.type === 1 || nodeOrLink.data.type === 2){ 
					return false; 
				}else{ 
					return true; 
				} 
			}); 
        }
        
        // var tool = _designer.toolManager.clickCreatingTool;
        // tool.insertPart = (loc) => {
        //     var jsonNewStep = {key:_jsonNewStep.key, text:_jsonNewStep.text};
        //     jsonNewStep.type = 0 
        //     jsonNewStep.loc = `${loc.x} ${loc.y}`;
        //     _designer.model.addNodeData(jsonNewStep);
        //     _this.externalobjectsdropped(jsonNewStep)
        // }
        

        // 流程步骤的样式模板
        // _designer.nodeTemplate = approvalNodeTemplate();
        // _designer.nodeTemplate = operationNodeTemplate();
        // _designer.nodeTemplateMap.add('Approval',approvalNodeTemplate)

        // 服务节点
        _designer.nodeTemplateMap.add('Subprocesses',
            G(go.Node, "Spot",
            { locationSpot: go.Spot.Center },
            new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
            { selectable: true, selectionAdornmentTemplate: makeNodeSelectionAdornmentTemplate() },
            new go.Binding("angle").makeTwoWay(),
            // the main object is a Panel that surrounds a TextBlock with a Shape
            G(go.Panel, "Auto",
                { name: "PANEL" },
                new go.Binding("desiredSize", "size", go.Size.parse).makeTwoWay(go.Size.stringify),
                G(go.Shape, "RoundedRectangle", // default figure
                        {
                            portId: "", // the default port: if no spot on link data, use closest side
                            name: "PIPE",
                            fromLinkable: true,
                            toLinkable: true,
                            cursor: "pointer",
                            fill: "white", // default color
                            strokeWidth: 1,
                            stroke: "#DCDEE2"
                        },
                        new go.Binding("figure"),
                        new go.Binding("stroke"),
                        new go.Binding("strokeDashArray"),
                        new go.Binding("strokeWidth"),
                        new go.Binding("fill")),
                G(go.Shape,
                    { 
                        margin: 5, 
                        fill: 'black', 
                        strokeWidth: 0, 
                        width: 28, 
                        height: 20,
                        alignment: go.Spot.TopRight,
                        geometry: go.Geometry.parse(geoFunc('subprocesses'))
                    }),
                G(go.TextBlock,
                        {
                            font: "bold 11pt Helvetica, Arial, sans-serif",
                            margin: 8,
                            wrap: go.TextBlock.WrapFit,
                            stroke: "#343434",
                            textAlign: "center",
                            alignment: go.Spot.Center,
                            verticalAlignment: go.Spot.Center,
                            wrap: go.TextBlock.WrapFit,
                            minSize: new go.Size(126, 27),
                            maxSize: new go.Size(126, NaN)
                        },
                        new go.Binding("text").makeTwoWay()),// the label shows the node data's text
                {
                    toolTip:// this tooltip Adornment is shared by all nodes
                        G(go.Adornment, "Auto",
                            G(go.Shape, { fill: "#FFFFCC" }),
                            G(go.TextBlock, { margin: 4 }, // the tooltip shows the result of calling nodeInfo(data)
                                new go.Binding("text", "", nodeInfo))
                        ),
                    // 绑定上下文菜单
                    // contextMenu: makePartContextMenu()
                }
            ),
            // 4个连接点
            makeNodePort("T", go.Spot.Top, false, true),
            makeNodePort("L", go.Spot.Left, true, true),
            makeNodePort("R", go.Spot.Right, true, true),
            makeNodePort("B", go.Spot.Bottom, true, false),
            {
                mouseEnter: function (e, node) { showNodePort(node, true); },
                mouseLeave: function (e, node) { showNodePort(node, false); }
            }
        )
        )

        // 服务节点
        _designer.nodeTemplateMap.add('Service',
            G(go.Node, "Spot",
            { locationSpot: go.Spot.Center },
            new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
            { selectable: true, selectionAdornmentTemplate: makeNodeSelectionAdornmentTemplate() },
            new go.Binding("angle").makeTwoWay(),
            // the main object is a Panel that surrounds a TextBlock with a Shape
            G(go.Panel, "Auto",
                { name: "PANEL" },
                new go.Binding("desiredSize", "size", go.Size.parse).makeTwoWay(go.Size.stringify),
                G(go.Shape, "RoundedRectangle", // default figure
                        {
                            portId: "", // the default port: if no spot on link data, use closest side
                            name: "PIPE",
                            fromLinkable: true,
                            toLinkable: true,
                            cursor: "pointer",
                            fill: "white", // default color
                            strokeWidth: 1,
                            stroke: "#DCDEE2"
                        },
                        new go.Binding("figure"),
                        new go.Binding("stroke"),
                        new go.Binding("strokeDashArray"),
                        new go.Binding("strokeWidth"),
                        new go.Binding("fill")),
                G(go.Shape,
                    { 
                        margin: 5, 
                        fill: 'black', 
                        strokeWidth: 0, 
                        width: 28, 
                        height: 20,
                        alignment: go.Spot.TopRight,
                        geometry: go.Geometry.parse(geoFunc('service'))
                    }),
                G(go.TextBlock,
                        {
                            font: "bold 11pt Helvetica, Arial, sans-serif",
                            margin: 8,
                            wrap: go.TextBlock.WrapFit,
                            stroke: "#343434",
                            textAlign: "center",
                            alignment: go.Spot.Center,
                            verticalAlignment: go.Spot.Center,
                            wrap: go.TextBlock.WrapFit,
                            minSize: new go.Size(126, 27),
                            maxSize: new go.Size(126, NaN)
                        },
                        new go.Binding("text").makeTwoWay()),// the label shows the node data's text
                {
                    toolTip:// this tooltip Adornment is shared by all nodes
                        G(go.Adornment, "Auto",
                            G(go.Shape, { fill: "#FFFFCC" }),
                            G(go.TextBlock, { margin: 4 }, // the tooltip shows the result of calling nodeInfo(data)
                                new go.Binding("text", "", nodeInfo))
                        ),
                    // 绑定上下文菜单
                    // contextMenu: makePartContextMenu()
                }
            ),
            // 4个连接点
            makeNodePort("T", go.Spot.Top, false, true),
            makeNodePort("L", go.Spot.Left, true, true),
            makeNodePort("R", go.Spot.Right, true, true),
            makeNodePort("B", go.Spot.Bottom, true, false),
            {
                mouseEnter: function (e, node) { showNodePort(node, true); },
                mouseLeave: function (e, node) { showNodePort(node, false); }
            }
        )
        )

        // 审批节点
        _designer.nodeTemplateMap.add('Approval',
            G(go.Node, "Spot",
            { locationSpot: go.Spot.Center },
            new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
            { selectable: true, selectionAdornmentTemplate: makeNodeSelectionAdornmentTemplate() },
            new go.Binding("angle").makeTwoWay(),
            // the main object is a Panel that surrounds a TextBlock with a Shape
            G(go.Panel, "Auto",
                { name: "PANEL" },
                new go.Binding("desiredSize", "size", go.Size.parse).makeTwoWay(go.Size.stringify),
                G(go.Shape, "RoundedRectangle", // default figure
                        {
                            portId: "", // the default port: if no spot on link data, use closest side
                            name: "PIPE",
                            fromLinkable: true,
                            toLinkable: true,
                            cursor: "pointer",
                            fill: "white", // default color
                            strokeWidth: 1,
                            stroke: "#DCDEE2"
                        },
                        new go.Binding("figure"),
                        new go.Binding("stroke"),
                        new go.Binding("strokeDashArray"),
                        new go.Binding("strokeWidth"),
                        new go.Binding("fill")),
                G(go.Shape,
                    { 
                        margin: 5, 
                        fill: 'black', 
                        strokeWidth: 0, 
                        width: 28, 
                        height: 20,
                        alignment: go.Spot.TopRight,
                        geometry: go.Geometry.parse(geoFunc('approval'))
                    }),
                G(go.TextBlock,
                        {
                            font: "bold 11pt Helvetica, Arial, sans-serif",
                            margin: 8,
                            wrap: go.TextBlock.WrapFit,
                            stroke: "#343434",
                            textAlign: "center",
                            alignment: go.Spot.Center,
                            verticalAlignment: go.Spot.Center,
                            wrap: go.TextBlock.WrapFit,
                            minSize: new go.Size(126, 27),
                            maxSize: new go.Size(126, NaN)
                        },
                        new go.Binding("text").makeTwoWay()),// the label shows the node data's text
                {
                    toolTip:// this tooltip Adornment is shared by all nodes
                        G(go.Adornment, "Auto",
                            G(go.Shape, { fill: "#FFFFCC" }),
                            G(go.TextBlock, { margin: 4 }, // the tooltip shows the result of calling nodeInfo(data)
                                new go.Binding("text", "", nodeInfo))
                        ),
                    // 绑定上下文菜单
                    // contextMenu: makePartContextMenu()
                }
            ),
            // 4个连接点
            makeNodePort("T", go.Spot.Top, false, true),
            makeNodePort("L", go.Spot.Left, true, true),
            makeNodePort("R", go.Spot.Right, true, true),
            makeNodePort("B", go.Spot.Bottom, true, false),
            {
                mouseEnter: function (e, node) { showNodePort(node, true); },
                mouseLeave: function (e, node) { showNodePort(node, false); }
            }
        )
        )

        // 操作节点
        _designer.nodeTemplateMap.add('Operation',
        G(go.Node, "Spot",
        { locationSpot: go.Spot.Center },
        new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
        { selectable: true, selectionAdornmentTemplate: makeNodeSelectionAdornmentTemplate() },
        new go.Binding("angle").makeTwoWay(),
        // the main object is a Panel that surrounds a TextBlock with a Shape
        G(go.Panel, "Auto",
            { name: "PANEL" },
            new go.Binding("desiredSize", "size", go.Size.parse).makeTwoWay(go.Size.stringify),
            G(go.Shape, "RoundedRectangle", // default figure
                    {
                        portId: "", // the default port: if no spot on link data, use closest side
                        name: "PIPE",
                        fromLinkable: true,
                        toLinkable: true,
                        cursor: "pointer",
                        fill: "white", // default color
                        strokeWidth: 1,
                        stroke: "#DCDEE2"
                    },
                    new go.Binding("figure"),
                    new go.Binding("stroke"),
                    new go.Binding("strokeDashArray"),
                    new go.Binding("strokeWidth"),
                    new go.Binding("fill")),
            G(go.Shape,
                { 
                    margin: 5, 
                    fill: 'black', 
                    strokeWidth: 0, 
                    width: 28, 
                    height: 20,
                    alignment: go.Spot.TopRight,
                    geometry: go.Geometry.parse(geoFunc('operation'))
                }),
            G(go.TextBlock,
                    {
                        font: "bold 11pt Helvetica, Arial, sans-serif",
                        margin: 8,
                        wrap: go.TextBlock.WrapFit,
                        stroke: "#343434",
                        textAlign: "center",
                        alignment: go.Spot.Center,
                        verticalAlignment: go.Spot.Center,
                        wrap: go.TextBlock.WrapFit,
                        minSize: new go.Size(126, 27),
                        maxSize: new go.Size(126, NaN)
                    },
                    new go.Binding("text").makeTwoWay()),// the label shows the node data's text
            {
                toolTip:// this tooltip Adornment is shared by all nodes
                    G(go.Adornment, "Auto",
                        G(go.Shape, { fill: "#FFFFCC" }),
                        G(go.TextBlock, { margin: 4 }, // the tooltip shows the result of calling nodeInfo(data)
                            new go.Binding("text", "", nodeInfo))
                    ),
                // 绑定上下文菜单
                // contextMenu: makePartContextMenu()
            }
        ),
        // 4个连接点
        makeNodePort("T", go.Spot.Top, false, true),
        makeNodePort("L", go.Spot.Left, true, true),
        makeNodePort("R", go.Spot.Right, true, true),
        makeNodePort("B", go.Spot.Bottom, true, false),
        {
            mouseEnter: function (e, node) { showNodePort(node, true); },
            mouseLeave: function (e, node) { showNodePort(node, false); }
        }
    )    
        )
        // 添加开始节点
        _designer.nodeTemplateMap.add("Start",
            G(go.Node, "Spot",
            { locationSpot: go.Spot.Center },
                new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
            { selectable: true, selectionAdornmentTemplate: makeNodeSelectionAdornmentTemplate() },
                new go.Binding("angle").makeTwoWay(),
            G(go.Panel, "Auto",
                    { name: "Start" },
                    new go.Binding("desiredSize", "size", go.Size.parse).makeTwoWay(go.Size.stringify),
                G(go.Shape, "Circle", // default figure
                        {
                            portId: "", // the default port: if no spot on link data, use closest side
                            name: "Start",
                            fromLinkable: true,
                            toLinkable: true,
                            cursor: "pointer",
                            fill: "#5F7790", // default color
                            strokeWidth: 1,
                            stroke: "#5F7790",
                            // geometryString: "F M0 0 L100 0 B-90 180 100 25 25 25 L0 50 B90 180 0 25 25 25"
                        },
                        new go.Binding("figure"),
                        new go.Binding("stroke"),
                        new go.Binding("strokeDashArray"),
                        new go.Binding("strokeWidth"),
                        new go.Binding("fill")),
                G(go.TextBlock,
                        {
                            font: "bold 11pt Helvetica, Arial, sans-serif",
                            margin:8,
                            wrap: go.TextBlock.WrapFit,
                            stroke: "white",
                            overflow:go.TextBlock.OverflowEllipsis
                        },
                        new go.Binding("text").makeTwoWay()),
                    {
                        toolTip: G(go.Adornment, "Auto",
                            G(go.Shape, { fill: "#FFFFCC" }),
                            G(go.TextBlock, { margin: 4 },
                                new go.Binding("text", "", nodeInfo))
                        )
                    }
                ),
                // 4个连接点
                makeNodePort("B", go.Spot.Bottom, true, false),
                {
                    mouseEnter: function (e, node) { showNodePort(node, true); },
                    mouseLeave: function (e, node) { showNodePort(node, false); }
                }
        ));
        
        // 添加结束节点
        _designer.nodeTemplateMap.add("End",
            G(go.Node, "Spot",
                { locationSpot: go.Spot.Center },
                    new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
                { selectable: true, selectionAdornmentTemplate: makeNodeSelectionAdornmentTemplate() },
                    new go.Binding("angle").makeTwoWay(),
                G(go.Panel, "Auto",
                        { name: "End" },
                        new go.Binding("desiredSize", "size", go.Size.parse).makeTwoWay(go.Size.stringify),
                    G(go.Shape, "Circle", // default figure
                            {
                                portId: "", // the default port: if no spot on link data, use closest side
                                name: "End",
                                fromLinkable: true,
                                toLinkable: true,
                                cursor: "pointer",
                                fill: "#5F7790", // default color
                                strokeWidth: 1,
                                stroke: "#5F7790",
                                // geometryString: "F M0 0 L100 0 Q175 25 100 50 L0 50 Q-75 25 0 0"
                            },
                            new go.Binding("figure"),
                            new go.Binding("stroke"),
                            new go.Binding("strokeDashArray"),
                            new go.Binding("strokeWidth"),
                            new go.Binding("fill")),
                    G(go.TextBlock,
                            {
                                font: "bold 11pt Helvetica, Arial, sans-serif",
                                margin: 8,
                                wrap: go.TextBlock.WrapFit,
                                stroke: "white"
                            },
                            new go.Binding("text").makeTwoWay()),
                        {
                            toolTip: G(go.Adornment, "Auto",
                                G(go.Shape, { fill: "#FFFFCC" }),
                                G(go.TextBlock, { margin: 4 },
                                    new go.Binding("text", "", nodeInfo))
                            )
                        }
                    ),
                    // 4个连接点
                    makeNodePort("T", go.Spot.Top, false, true),
                    {
                        mouseEnter: function (e, node) { showNodePort(node, true); },
                        mouseLeave: function (e, node) { showNodePort(node, false); }
                    }
        ));

        // 流程连接线的样式模板
        _designer.linkTemplate = makeLinkTemplate();
        
        return _designer
    }

    /**
     * 生成GUID
     * @returns {string}
     */
    function guid() {
        var r = Math.floor(Math.random() * (30000 - 1 + 1) + 1);
        return Number(r);
    }

    function geoFunc(geoname) {
        if (icons[geoname]) return icons[geoname];
        else return icons["approval"]; // default icon
    }

    /**
     * 操作节点样式模板
     * @returns {*}
     */
    function operationNodeTemplate(){
        return G(go.Node, "Spot",
            { locationSpot: go.Spot.Center },
            new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
            { selectable: true, selectionAdornmentTemplate: makeNodeSelectionAdornmentTemplate() },
            new go.Binding("angle").makeTwoWay(),
            // the main object is a Panel that surrounds a TextBlock with a Shape
            G(go.Panel, "Auto",
                { name: "PANEL" },
                new go.Binding("desiredSize", "size", go.Size.parse).makeTwoWay(go.Size.stringify),
                G(go.Shape, "RoundedRectangle", // default figure
                        {
                            portId: "", // the default port: if no spot on link data, use closest side
                            name: "PIPE",
                            fromLinkable: true,
                            toLinkable: true,
                            cursor: "pointer",
                            fill: "white", // default color
                            strokeWidth: 1,
                            stroke: "#DCDEE2"
                        },
                        new go.Binding("figure"),
                        new go.Binding("stroke"),
                        new go.Binding("strokeDashArray"),
                        new go.Binding("strokeWidth"),
                        new go.Binding("fill")),
                G(go.Shape,
                    { 
                        margin: 5, 
                        fill: 'black', 
                        strokeWidth: 0, 
                        width: 20, 
                        height: 20,
                        alignment: go.Spot.TopRight,
                        geometry: go.Geometry.parse(geoFunc('operation'))
                    }),
                G(go.TextBlock,
                        {
                            font: "bold 11pt Helvetica, Arial, sans-serif",
                            margin: 8,
                            wrap: go.TextBlock.WrapFit,
                            stroke: "#343434",
                            textAlign: "center",
                            alignment: go.Spot.Center,
                            verticalAlignment: go.Spot.Center,
                            wrap: go.TextBlock.WrapFit,
                            minSize: new go.Size(126, 27),
                            maxSize: new go.Size(126, NaN)
                        },
                        new go.Binding("text").makeTwoWay()),// the label shows the node data's text
                {
                    toolTip:// this tooltip Adornment is shared by all nodes
                        G(go.Adornment, "Auto",
                            G(go.Shape, { fill: "#FFFFCC" }),
                            G(go.TextBlock, { margin: 4 }, // the tooltip shows the result of calling nodeInfo(data)
                                new go.Binding("text", "", nodeInfo))
                        ),
                    // 绑定上下文菜单
                    // contextMenu: makePartContextMenu()
                }
            ),
            // 4个连接点
            makeNodePort("T", go.Spot.Top, false, true),
            makeNodePort("L", go.Spot.Left, true, true),
            makeNodePort("R", go.Spot.Right, true, true),
            makeNodePort("B", go.Spot.Bottom, true, false),
            {
                mouseEnter: function (e, node) { showNodePort(node, true); },
                mouseLeave: function (e, node) { showNodePort(node, false); }
            }
        );
    }

    /**
     * 操作节点样式模板
     * @returns {*}
     */
    function approvalNodeTemplate(){
      console.log(1222)
        return G(go.Node, "Spot",
            { locationSpot: go.Spot.Center },
            new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
            { selectable: true, selectionAdornmentTemplate: makeNodeSelectionAdornmentTemplate() },
            new go.Binding("angle").makeTwoWay(),
            // the main object is a Panel that surrounds a TextBlock with a Shape
            G(go.Panel, "Auto",
                { name: "PANEL" },
                new go.Binding("desiredSize", "size", go.Size.parse).makeTwoWay(go.Size.stringify),
                G(go.Shape, "RoundedRectangle", // default figure
                        {
                            portId: "", // the default port: if no spot on link data, use closest side
                            name: "PIPE",
                            fromLinkable: true,
                            toLinkable: true,
                            cursor: "pointer",
                            fill: "white", // default color
                            strokeWidth: 1,
                            stroke: "#DCDEE2"
                        },
                        new go.Binding("figure"),
                        new go.Binding("stroke"),
                        new go.Binding("strokeDashArray"),
                        new go.Binding("strokeWidth"),
                        new go.Binding("fill")),
                G(go.Shape,
                    { 
                        margin: 5, 
                        fill: 'black', 
                        strokeWidth: 0, 
                        width: 20, 
                        height: 20,
                        alignment: go.Spot.TopRight,
                        geometry: go.Geometry.parse(geoFunc('approval'))
                    }),
                G(go.TextBlock,
                        {
                            font: "bold 11pt Helvetica, Arial, sans-serif",
                            margin: 8,
                            wrap: go.TextBlock.WrapFit,
                            stroke: "#343434",
                            textAlign: "center",
                            alignment: go.Spot.Center,
                            verticalAlignment: go.Spot.Center,
                            wrap: go.TextBlock.WrapFit,
                            minSize: new go.Size(126, 27),
                            maxSize: new go.Size(126, NaN)
                        },
                        new go.Binding("text").makeTwoWay()),// the label shows the node data's text
                {
                    toolTip:// this tooltip Adornment is shared by all nodes
                        G(go.Adornment, "Auto",
                            G(go.Shape, { fill: "#FFFFCC" }),
                            G(go.TextBlock, { margin: 4 }, // the tooltip shows the result of calling nodeInfo(data)
                                new go.Binding("text", "", nodeInfo))
                        ),
                    // 绑定上下文菜单
                    // contextMenu: makePartContextMenu()
                }
            ),
            // 4个连接点
            makeNodePort("T", go.Spot.Top, false, true),
            makeNodePort("L", go.Spot.Left, true, true),
            makeNodePort("R", go.Spot.Right, true, true),
            makeNodePort("B", go.Spot.Bottom, true, false),
            {
                mouseEnter: function (e, node) { showNodePort(node, true); },
                mouseLeave: function (e, node) { showNodePort(node, false); }
            }
        );
    }

    /**
     * 选中节点的样式
     * @returns {*}
     */
    function makeNodeSelectionAdornmentTemplate(){
        return G(go.Adornment, "Auto",
            G(go.Shape, { fill: null, stroke: "deepskyblue", strokeWidth: 1.5, strokeDashArray: [4, 2] }),
            G(go.Placeholder)
        );
    }

    /**
     * 创建连接点
     * @param name
     * @param spot
     * @param output
     * @param input
     * @returns {*}
     */
    function makeNodePort(name, spot, output, input) {
        // the port is basically just a small transparent square
        return G(go.Shape, "Circle",
            {
                fill: null, // not seen, by default; set to a translucent gray by showSmallPorts, defined below
                stroke: null,
                desiredSize: new go.Size(7, 7),
                alignment: spot, // align the port on the main Shape
                alignmentFocus: spot, // just inside the Shape
                portId: name, // declare this object to be a "port"
                fromSpot: spot,
                toSpot: spot, // declare where links may connect at this port
                fromLinkable: output,
                toLinkable: input, // declare whether the user may draw links to/from here
                cursor: "pointer" // show a different cursor to indicate potential link point
            });
    }

    /**
     * tooltip上显示的信息
     * @param d
     * @returns {string}
     */
    function nodeInfo(d) {
        return '双击可编辑';
    }

    /**
     * 右键菜单
     * @returns {*}
     */
    function makePartContextMenu(){
        return G(go.Adornment, "Vertical",
            makeMenuItem("编辑",
                function(e, obj) { // OBJ is this Button
                    var contextmenu = obj.part; // the Button is in the context menu Adornment
                    var part = contextmenu.adornedPart; // the adornedPart is the Part that the context menu adorns
                    // now can do something with PART, or with its data, or with the Adornment (the context menu)
                    showEditNode(part);
                }),
            makeMenuItem("剪切",
                function(e, obj) { e.diagram.commandHandler.cutSelection(); },
                function(o) { return o.diagram.commandHandler.canCutSelection(); }),
            makeMenuItem("复制",
                function(e, obj) { e.diagram.commandHandler.copySelection(); },
                function(o) { return o.diagram.commandHandler.canCopySelection(); }),
            makeMenuItem("删除",
                function(e, obj) { e.diagram.commandHandler.deleteSelection(); },
                function(o) { return o.diagram.commandHandler.canDeleteSelection(); })
        );
    }

    /**
     * 生成右键菜单项
     * @param text
     * @param action
     * @param visiblePredicate
     * @returns {*}
     */
    function makeMenuItem(text, action, visiblePredicate) {
        return G("ContextMenuButton",
            G(go.TextBlock, text, {
                margin: 5,
                textAlign: "left",
                stroke: "#555555"
            }),
            { click: action },
            // don't bother with binding GraphObject.visible if there's no predicate
            visiblePredicate ? new go.Binding("visible", "", visiblePredicate).ofObject() : {});
    }

    /**
     * 是否显示步骤的连接点
     * @param node
     * @param show
     */
    function showNodePort(node, show) {
        node.ports.each(function (port) {
            if (port.portId !== "") { // don't change the default port, which is the big shape
                port.fill = show ? "rgba(255,0,0,.5)" : null;
            }
        });
    }

    /**
     * 连接线的选中样式
     * @returns {*}
     */
    function makeLinkSelectionAdornmentTemplate(){
        return G(go.Adornment, "Link",
            G(go.Shape,
                // isPanelMain declares that this Shape shares the Link.geometry
                { isPanelMain: true, fill: null, stroke: "deepskyblue", strokeWidth: 0 }) // use selection object's strokeWidth
        );
    }

    
    /**
     * 定义连接线的样式模板
     * @returns {*}
     */
    function makeLinkTemplate(){
        return G(go.Link, // the whole link panel
            { selectable: true, selectionAdornmentTemplate: makeLinkSelectionAdornmentTemplate() },
            { relinkableFrom: true, relinkableTo: true, reshapable: true },
            {
                routing: go.Link.AvoidsNodes,
                curve: go.Link.JumpOver,
                corner: 5,
                toShortLength: 4
            },
            G(go.Shape, // 线条
                { isPanelMain: true, stroke: "#D5D5D5", strokeWidth: 3 }),
            G(go.Shape, // 箭头
                { toArrow: "standard", stroke: null, fill: '#D5D5D5' }, new go.Binding("stroke"), new go.Binding("fill"), new go.Binding("zOrder")),
            G(go.Panel, "Auto",
                G(go.Shape, {
                    fill: null,
                    stroke: null
                }, new go.Binding("fill", "pFill"), new go.Binding("zOrder")),
                G(go.TextBlock,
                    {
                        textAlign: "center",
                        font: "10pt helvetica, arial, sans-serif",
                        stroke: "#555555",
                        margin: 4
                    },
                    new go.Binding("text", "text"), new go.Binding("zOrder")), // the label shows the node data's text
                {
                    toolTip:// this tooltip Adornment is shared by all nodes
                        G(go.Adornment, "Auto",
                            G(go.Shape, { fill: "#FFFFCC" }),
                            G(go.TextBlock, { margin: 4 }, // the tooltip shows the result of calling nodeInfo(data)
                                new go.Binding("text", "", nodeInfo))
                        ),
                    // this context menu Adornment is shared by all nodes
                    // contextMenu: makePartContextMenu()
                }
            )
        );
    }

    /**
     * 流程图元素的双击事件
     * @param ev
     */
    function onObjectDoubleClicked(ev) {
        var part = ev.subject.part;
        showEditNode(part);
    }

    /**
     * 流程图如果有变动，则提示用户保存
     * @param e
     */
    function onDiagramModified(e){
        var button = document.getElementById("btnSaveFlow");
        if (button) button.disabled = !_designer.isModified;
        var idx = document.title.indexOf("*");
        if (_designer.isModified) {
            if (idx < 0) document.title += "*";
        } else {
            if (idx >= 0) document.title = document.title.substr(0, idx);
        }
    }

    /**
     * 编辑节点信息
     */
    function showEditNode(node) {
        _this.showEditNode(node)
        return node
    }

    /**
     * 更新节点信息
     * @param oldData
     * @param newData
     */
    function updateNodeData(node, text) {
        _designer.startTransaction("vacate");
        _designer.model.setDataProperty(node.data, "text", text);
        _designer.commitTransaction("vacate");
    }

    /**
     * 更改所有连线中间的文本背景色
     */
    function setLinkTextBg() {
        _designer.links.each(function (link) {
            _designer.startTransaction("vacate");
            if (link.data.text) {
                _designer.model.setDataProperty(link.data, "pFill", window.go.GraphObject.make(go.Brush, "Radial", {
                    0: "rgb(240, 240, 240)",
                    0.3: "rgb(240, 240, 240)",
                    1: "rgba(240, 240, 240, 0)"
                }));
            }
            _designer.commitTransaction("vacate");
        });
    }

    /** --------private method------------------end----------------------**/

    return this;
}

export default FlowDesigner
