import * as React from 'react';
import * as go from 'gojs';
import { Diagram, ToolManager, Node } from 'gojs';
import { GojsDiagram } from 'react-gojs';
import './MyDiagram.css';
import { BPMNLinkingTool } from './BPMNClasses';
import { DrawCommandHandler } from './DrawCommandHandler';
//import { BPMN } from './BPMN';

class MyDiagram extends React.Component<any, any> {
    private _myDiagram: Diagram;
    constructor(props: any) {
        super(props);
        this.createDiagram = this.createDiagram.bind(this);

    }

    public render(): JSX.Element {
        return (
            <GojsDiagram
                diagramId="myDiagramDiv"
                model={this.props.model}
                createDiagram={this.createDiagram}
                className="myDiagram"
            />
        );
    }

    public addNodeData(node: any) {
        this._myDiagram.model.addNodeData(node);
    }

    public removeNodeData(node: any) {
        this._myDiagram.commandHandler.deleteSelection();
    }

    _ActionRules = (showActionRulesPanel: boolean) => {
        this.props.ActionRules(showActionRulesPanel);
    };
    _ActionHandlers = (shoActionHandlersPanel: boolean) => {
        this.props.ActionHandlers(shoActionHandlersPanel);
    };
    _actionPermissions = (shoActionHandlersPanel: boolean) => {
        this.props.actionPermissions(shoActionHandlersPanel);
    };
    _actionProperties(shoactionPropertiesPanel: boolean) {
        this.props.actionProperties(shoactionPropertiesPanel);
    }
    // Define a function for creating a "port" that is normally transparent.
    // The "name" is used as the GraphObject.portId,
    // the "align" is used to determine where to position the port relative to the body of the node,
    // the "spot" is used to control how links connect with the port and whether the port
    // stretches along the side of the node,
    // and the boolean "output" and "input" arguments control whether the user can draw links from or to the port.
    // private makePort(name :any, align :any, spot :any, output :any, input:any) {
    //     const $ = go.GraphObject.make;
    //     var horizontal = align.equals(go.Spot.Top) || align.equals(go.Spot.Bottom);
    //     // the port is basically just a transparent rectangle that stretches along the side of the node,
    //     // and becomes colored when the mouse passes over it
    //     return $(go.Shape,
    //       {
    //         fill: "transparent",  // changed to a color in the mouseEnter event handler
    //         strokeWidth: 0,  // no stroke
    //         width: horizontal ? NaN : 8,  // if not stretching horizontally, just 8 wide
    //         height: !horizontal ? NaN : 8,  // if not stretching vertically, just 8 tall
    //         alignment: align,  // align the port on the main Shape
    //         stretch: (horizontal ? go.GraphObject.Horizontal : go.GraphObject.Vertical),
    //         portId: name,  // declare this object to be a "port"
    //         fromSpot: spot,  // declare where links may connect at this port
    //         fromLinkable: output,  // declare whether the user may draw links from here
    //         toSpot: spot,  // declare where links may connect at this port
    //         toLinkable: input,  // declare whether the user may draw links to here
    //         cursor: "pointer",  // show a different cursor to indicate potential link point
    //         mouseEnter: function(e:any, port:any) {  // the PORT argument will be this Shape
    //           if (!e.diagram.isReadOnly) port.fill = "rgba(255,0,255,0.5)";
    //         },
    //         mouseLeave: function(e:any, port:any) {
    //           port.fill = "transparent";
    //         }
    //       });
    //   }

    AddAction(myDiagram: any, evType: any, evDim: any) {

        myDiagram.startTransaction("addBoundaryEvent");
        myDiagram.selection.each(function (node: any) {

            // skip any selected Links
            if (!(node instanceof go.Node)) return;
            if (node.data && (node.data.category === "activity" || node.data.category === "subprocess")) {
                // compute the next available index number for the side
                var i = 0;
                var defaultPort = node.findPort("");
                while (node.findPort("be" + i.toString()) !== defaultPort) i++;           // now this new port name is unique within the whole Node because of the side prefix
                var name = "be" + i.toString();
                if (!node.data.boundaryEventArray) { myDiagram.model.setDataProperty(node.data, "boundaryEventArray", []); }       // initialize the Array of port data if necessary
                // create a new port data object
                var newportdata = {
                    portId: name,
                    eventType: evType,
                    eventDimension: evDim,
                    color: "white",
                    text: 'murad',
                    alignmentIndex: i
                    // if you add port data properties here, you should copy them in copyPortData above  ** BUG...  we don't do that.
                };
                // and add it to the Array of port data
                myDiagram.model.insertArrayItem(node.data.boundaryEventArray, -1, newportdata);
            }
        });
        myDiagram.commitTransaction("addBoundaryEvent");
        //alert("Add User action")
    }

    removeActivityNodeBoundaryEvent(myDiagram: any, obj: any) {
        myDiagram.startTransaction("removeBoundaryEvent");
        var pid = obj.portId;
        var arr = obj.panel.itemArray;
        for (var i = 0; i < arr.length; i++) {
            if (arr[i].portId === pid) {
                myDiagram.model.removeArrayItem(arr, i);
                break;
            }
        }
        myDiagram.commitTransaction("removeBoundaryEvent");
    }
    
    private nodeEventTypeConverter(s: any) {  // order here from BPMN 2.0 poster
        var tasks = ["NotAllowed",
            "Empty",
            "BpmnTaskMessage",
            "BpmnEventTimer",
            "BpmnEventEscalation",
            "BpmnEventConditional",
            "Arrow",
            "BpmnEventError",
            "ThinX",
            "BpmnActivityCompensation",
            "Triangle",
            "Pentagon",
            "ThickCross",
            "Circle"];
        if (s < tasks.length) return tasks[s];
        return "NotAllowed"; // error
    }

    private nodeActivityTaskTypeColorConverter(s: any) {
        return (s == 5) ? "dimgray" : "white";
    }

    private nodeActivityTaskTypeConverter(s: any) {
        var tasks = ["Empty",
            "BpmnTaskMessage",
            "BpmnTaskUser",
            "BpmnTaskManual",   // Custom hand symbol
            "BpmnTaskScript",
            "BpmnTaskMessage",  // should be black on white
            "BpmnTaskService",  // Custom gear symbol
            "InternalStorage"];
        if (s < tasks.length) return tasks[s];
        return "NotAllowed"; // error
    }
    private makeSubButton(sub: any) {
        const $ = go.GraphObject.make;

        if (sub)
            return [$("SubGraphExpanderButton"),
            { margin: 2, visible: false },
            new go.Binding("visible", "isSubProcess")];
        return [];
    }
    private makeMarkerPanel(sub: any, scale: any) {
        var ActivityMarkerStrokeWidth = 1.5;

        const $ = go.GraphObject.make;
        return $(go.Panel, "Horizontal",
            { alignment: go.Spot.MiddleBottom, alignmentFocus: go.Spot.MiddleBottom },
            $(go.Shape, "BpmnActivityLoop",
                { width: 12 / scale, height: 12 / scale, margin: 2, visible: false, strokeWidth: ActivityMarkerStrokeWidth },
                new go.Binding("visible", "isLoop")),
            $(go.Shape, "BpmnActivityParallel",
                { width: 12 / scale, height: 12 / scale, margin: 2, visible: false, strokeWidth: ActivityMarkerStrokeWidth },
                new go.Binding("visible", "isParallel")),
            $(go.Shape, "BpmnActivitySequential",
                { width: 12 / scale, height: 12 / scale, margin: 2, visible: false, strokeWidth: ActivityMarkerStrokeWidth },
                new go.Binding("visible", "isSequential")),
            $(go.Shape, "BpmnActivityAdHoc",
                { width: 12 / scale, height: 12 / scale, margin: 2, visible: false, strokeWidth: ActivityMarkerStrokeWidth },
                new go.Binding("visible", "isAdHoc")),
            $(go.Shape, "BpmnActivityCompensation",
                { width: 12 / scale, height: 12 / scale, margin: 2, visible: false, strokeWidth: ActivityMarkerStrokeWidth, fill: null },
                new go.Binding("visible", "isCompensation")),
            this.makeSubButton(sub)
        ); // end activity markers horizontal panel
    }
    private nodeActivityBESpotConverter(s: any) {
        var EventNodeSize = 42;

        var x = 10 + (EventNodeSize / 2);
        if (s === 0) return new go.Spot(0, 1, x, 0);    // bottom left
        if (s === 1) return new go.Spot(1, 1, -x, 0);   // bottom right
        if (s === 2) return new go.Spot(1, 0, -x, 0);   // top right
        return new go.Spot(1, 0, -x - (s - 2) * EventNodeSize, 0);    // top ... right-to-left-ish spread
    }
    // private _actionProperties() {
    //     this.setState({ showPanel: false });
    // }
    
// this is called after nodes have been moved or lanes resized, to layout all of the Pool Groups again
// private relayoutDiagram() {
//     this._myDiagram.layout.invalidateLayout();
//     this._myDiagram.findTopLevelGroups().each(function (g) { if (g.category === "Pool") g.layout.invalidateLayout(); });
//     this._myDiagram.layoutDiagram();
//   }

private relayoutDiagram() {
    this._myDiagram.layout.invalidateLayout();
    this._myDiagram.findTopLevelGroups().each(function (g) { if (g.category === "Pool") g.layout.invalidateLayout(); });
    this._myDiagram.layoutDiagram();
  }
  
    // this is called after nodes have been moved or lanes resized, to layout all of the Pool Groups again

    private createDiagram(diagramId: string): Diagram {
        // const myDiagram: Diagram = new BPMN().myDiagram;
        const $ = go.GraphObject.make;
        const myDiagram: Diagram =  $(go.Diagram, diagramId, {
    initialContentAlignment: go.Spot.TopCenter,
    layout: $(go.TreeLayout, {
        angle: 90,
        arrangement: go.TreeLayout.ArrangementVertical,
        treeStyle: go.TreeLayout.StyleLayered
    }),
    isModelReadOnly: false,
    isReadOnly: false,
    allowHorizontalScroll: true,
    allowVerticalScroll: true,
    allowZoom: false,
    allowSelect: true,
    autoScale: Diagram.Uniform,
    contentAlignment: go.Spot.Center,
    
  // defined in DrawCommandHandler.js
// default to having arrow keys move selected nodes


mouseDrop: function(e:any) {
  // when the selection is dropped in the diagram's background,
  // make sure the selected Parts no longer belong to any Group
  var ok = myDiagram.commandHandler.addTopLevelParts(myDiagram.selection, true);
  if (!ok) myDiagram.currentTool.doCancel();
},
linkingTool: new BPMNLinkingTool(), // defined in BPMNClasses.js
"SelectionMoved": this.relayoutDiagram.bind(this),  // defined below
"SelectionCopied": this.relayoutDiagram.bind(this)
});
        var EventNodeSize = 42;
        var EventNodeInnerSize = EventNodeSize - 6;
        var EventNodeSymbolSize = EventNodeInnerSize - 14;
        var ActivityNodeWidth = 120;
        var ActivityNodeHeight = 80;
        var ActivityNodeFill = $(go.Brush, "Linear", { 0: "OldLace", 1: "PapayaWhip" });
        var ActivityNodeStroke = "#CDAA7D";
        var ActivityNodeStrokeWidthIsCall = 4;
        var ActivityNodeStrokeWidth = 1;

        const boundaryEventMenu =  // context menu for each boundaryEvent on Activity node
            $(go.Adornment, "Vertical",
                $("ContextMenuButton",
                    $(go.TextBlock, "Remove event"),
                    // in the click event handler, the obj.part is the Adornment; its adornedObject is the port
                    { click: (e: any, obj: any) => { this.removeActivityNodeBoundaryEvent(myDiagram, obj.part.adornedObject); } }),
                $("ContextMenuButton",
                    $(go.TextBlock, "Action Handlers"),
                    // in the click event handler, the obj.part is the Adornment; its adornedObject is the port
                    { click: () => { this._ActionHandlers(true) } }),
                $("ContextMenuButton",
                    $(go.TextBlock, "Action Permissions"),
                    // in the click event handler, the obj.part is the Adornment; its adornedObject is the port
                    { click: () => { this._actionPermissions(true) } }),
                $("ContextMenuButton",
                    $(go.TextBlock, "Action Rules"),
                    // in the click event handler, the obj.part is the Adornment; its adornedObject is the port
                    { click: () => { this._ActionRules(true) } }),
                $("ContextMenuButton",
                    $(go.TextBlock, "Properties"),
                    // in the click event handler, the obj.part is the Adornment; its adornedObject is the port
                    { click: (e: any, obj: any) => { this._actionProperties(true); } }),
            );

        const boundaryEventItemTemplate =
            $(go.Panel, "Spot",
                {
                    contextMenu: boundaryEventMenu,
                    alignmentFocus: go.Spot.Center,
                    fromLinkable: true, toLinkable: false, cursor: "pointer", fromSpot: go.Spot.Bottom,
                    fromMaxLinks: 1, toMaxLinks: 0
                },
                new go.Binding("portId", "portId"),
                new go.Binding("alignment", "alignmentIndex", this.nodeActivityBESpotConverter),
                $(go.Shape, "Circle",
                    { desiredSize: new go.Size(EventNodeSize, EventNodeSize) },
                    new go.Binding("strokeDashArray", "eventDimension", function (s) { return (s === 6) ? [4, 2] : null; }),
                    new go.Binding("fromSpot", "alignmentIndex",
                        function (s) {
                            //  nodeActivityBEFromSpotConverter, 0 & 1 go on bottom, all others on top of activity
                            if (s < 2) return go.Spot.Bottom;
                            return go.Spot.Top;
                        }),
                    new go.Binding("fill", "color")),
                $(go.Shape, "Circle",
                    {
                        alignment: go.Spot.Center,
                        desiredSize: new go.Size(EventNodeInnerSize, EventNodeInnerSize), fill: null
                    },
                    new go.Binding("strokeDashArray", "eventDimension", function (s) { return (s === 6) ? [4, 2] : null; })
                ),
                $(go.Shape, "NotAllowed",
                    {
                        alignment: go.Spot.Center,
                        desiredSize: new go.Size(EventNodeSymbolSize, EventNodeSymbolSize), fill: "white"
                    },
                    new go.Binding("figure", "eventType", this.nodeEventTypeConverter)
                )
            );

        //------------------------------------------  Activity Node contextMenu   ---------------------------------------------


        const activityNodeMenu =
            $(go.Adornment, "Vertical",
                $("ContextMenuButton",
                    $(go.TextBlock, "Add User action", { margin: 3 }),
                    { click: (e: any, obj: any) => { this.AddAction(myDiagram, 1, 1) } }),
                $("ContextMenuButton",
                    $(go.TextBlock, "Add Timer Action", { margin: 3 }),
                    { click: (e: any, obj: any) => { this.AddAction(myDiagram, 3, 5) } }),
                $("ContextMenuButton",
                    $(go.TextBlock, "State Handlers", { margin: 3 }),
                    { click: (e: any, obj: any) => { this.AddAction(myDiagram, 4, 5) } }),
                $("ContextMenuButton",
                    $(go.TextBlock, "State Permissions", { margin: 3 }),
                    { click: (e: any, obj: any) => { this.AddAction(myDiagram, 7, 5) } }),
                $("ContextMenuButton",
                    $(go.TextBlock, "State Rules", { margin: 3 }),
                    { click: (e: any, obj: any) => { this.AddAction(myDiagram, 10, 5) } }),
                $("ContextMenuButton",
                    $(go.TextBlock, "Delete State", { margin: 3 }),
                    { click: (e: any, obj: any) => { this.removeNodeData.bind(this) } }),
            )

        // define the appearance of tooltips, shared by various templates
        const tooltiptemplate =
            $(go.Adornment, go.Panel.Auto,
                $(go.Shape, "RoundedRectangle",
                    { fill: "whitesmoke", stroke: "gray" }),
                $(go.TextBlock,
                    { margin: 3, editable: true },
                    new go.Binding("text", "", function (data) {
                        if (data.item !== undefined) return data.item;
                        return "(unnamed item)";
                    }))
                  
            );

        // end go.Node, which is a Spot Panel with bound itemArray
        //var nodeTemplateMap = new go.Map("string", go.Node);
        // for each of the node categories, specify which template to use

        ////////////////////////////////////
        //////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////////////////////////////////
        
        let commandHandler = new DrawCommandHandler();
        commandHandler.setArrowKeyBehavior("move");
        myDiagram.commandHandler = commandHandler;
        myDiagram.toolManager.panningTool.isEnabled = false;
        myDiagram.toolManager.mouseWheelBehavior = ToolManager.WheelScroll;

        myDiagram.contextMenu =
            $(go.Adornment, "Vertical",
                $("ContextMenuButton",
                    $(go.TextBlock, "Add State…"),
                    {
                        click: function () {
                            this.addState.bind(this)
                        }
                    }),
                $("ContextMenuButton",
                    $(go.TextBlock, "Auto Arrange elements"),
                    {
                        click: function () {
                            alert('hello')
                        }
                    }),
                $("ContextMenuButton",
                    $(go.TextBlock, "Save Workflow"),
                    {
                        click: function () {
                            alert('hello')
                        }
                    })
            );
        myDiagram.initialContentAlignment = go.Spot.Center;

        myDiagram.nodeTemplate = $(
            go.Node,
            'Auto',
            {
                selectionChanged: (node: Node) => this.props.onNodeSelection(node.key as string, node.isSelected)
            },
            $(go.Shape, 'Circle', {
                strokeWidth: 0, alignment: go.Spot.Center,
                fromSpot: go.Spot.Left, toSpot: go.Spot.Right,
                stretch: go.GraphObject.Vertical, cursor: "pointer"
            }, new go.Binding('fill', 'color')),
            $(go.TextBlock, { margin: 8, cursor: "pointer" }, new go.Binding('text', 'text')), {
                selectionAdornmentTemplate:
                    $(go.Adornment, "Auto",
                        $(go.Shape, "RoundedRectangle",
                            { fill: null, stroke: "dodgerblue", strokeWidth: 8 }),
                        $(go.Placeholder)
                    )  // end Adornment
            }
        );
        myDiagram.nodeTemplateMap.add("activity", $(go.Node, "Spot",
            {
                locationObjectName: "SHAPE", locationSpot: go.Spot.Center,
                resizable: true, resizeObjectName: "PANEL",
                toolTip: tooltiptemplate,
                selectionAdorned: false,  // use a Binding on the Shape.stroke to show selection
                contextMenu: activityNodeMenu,
                itemTemplate: boundaryEventItemTemplate
            },

            new go.Binding("itemArray", "boundaryEventArray"),
            new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
            // move a selected part into the Foreground layer, so it isn"t obscured by any non-selected parts
            new go.Binding("layerName", "isSelected", function (s) { return s ? "Foreground" : ""; }).ofObject(),
            $(go.Panel, "Auto",
                {
                    name: "PANEL",
                    minSize: new go.Size(ActivityNodeWidth, ActivityNodeHeight),
                    desiredSize: new go.Size(ActivityNodeWidth, ActivityNodeHeight)
                },
                new go.Binding("desiredSize", "size", go.Size.parse).makeTwoWay(go.Size.stringify),

                $(go.Panel, "Spot",
                    $(go.Shape, "RoundedRectangle",  // the outside rounded rectangle
                        {
                            name: "SHAPE",
                            fill: ActivityNodeFill, stroke: ActivityNodeStroke,
                            parameter1: 10, // corner size
                            portId: "", fromLinkable: false, toLinkable: true, cursor: "pointer",
                            fromSpot: go.Spot.RightSide, toSpot: go.Spot.LeftSide
                        },
                        new go.Binding("fill", "color"),
                        new go.Binding("strokeWidth", "isCall",
                            function (s) { return s ? ActivityNodeStrokeWidthIsCall : ActivityNodeStrokeWidth; })
                    ),

                    //        $(go.Shape, "RoundedRectangle",  // the inner "Transaction" rounded rectangle
                    //          { margin: 3,
                    //            stretch: go.GraphObject.Fill,
                    //            stroke: ActivityNodeStroke,
                    //            parameter1: 8, fill: null, visible: false
                    //          },
                    //          new go.Binding("visible", "isTransaction")
                    //         ),
                    // task icon
                    $(go.Shape, "BpmnTaskScript",    // will be None, Script, Manual, Service, etc via converter
                        {
                            alignment: new go.Spot(0, 0, 5, 5), alignmentFocus: go.Spot.TopLeft,
                            width: 22, height: 22
                        },
                        new go.Binding("fill", "taskType", this.nodeActivityTaskTypeColorConverter),
                        new go.Binding("figure", "taskType", this.nodeActivityTaskTypeConverter)
                    ), // end Task Icon
                    this.makeMarkerPanel(false, 1) // sub-process,  loop, parallel, sequential, ad doc and compensation markers
                ),  // end main body rectangles spot panel
                $(go.TextBlock,  // the center text
                    {
                        alignment: go.Spot.Center, textAlign: "center", margin: 12,
                        editable: true
                    },
                    new go.Binding("text").makeTwoWay())
            )  // end Auto Panel
        ));
        myDiagram.nodeTemplateMap.add("Conditional",
            $(go.Node, "Table", {
                selectionChanged: (node: Node) => this.props.onNodeSelection(node.key as string, node.isSelected)
            },
                // the main object is a Panel that surrounds a TextBlock with a rectangular Shape
                $(go.Panel, "Auto",
                    $(go.Shape, "Diamond",
                        {
                            fill: "#00A9C9", strokeWidth: 0, alignment: go.Spot.Center,
                            fromSpot: go.Spot.Left, toSpot: go.Spot.Right,
                            stretch: go.GraphObject.Vertical, cursor: "pointer", fromLinkable: false, toLinkable: true,
                        },
                        new go.Binding("fill", "color")),

                    new go.Binding("fill", "color"),
                    new go.Binding("strokeWidth", "isCall",
                        function (s) { return s ? ActivityNodeStrokeWidthIsCall : ActivityNodeStrokeWidth; }),


                    $(go.TextBlock,
                        {
                            margin: 8,
                            maxSize: new go.Size(160, NaN),
                            wrap: go.TextBlock.WrapFit, cursor: "pointer"
                        },
                        new go.Binding("text", 'text'))
                ), {
                    selectionAdornmentTemplate:
                        $(go.Adornment, "Auto",
                            $(go.Shape, "RoundedRectangle",
                                { fill: null, stroke: "dodgerblue", strokeWidth: 8 }),
                            $(go.Placeholder)
                        )  // end Adornment
                }
            ));
        myDiagram.nodeTemplateMap.add("Action",
            $(go.Node, "Table", {
                selectionChanged: (node: Node) => this.props.onNodeSelection(node.key as string, node.isSelected)
            },
                // the main object is a Panel that surrounds a TextBlock with a rectangular Shape
                $(go.Panel, "Auto",
                    $(go.Shape, "TriangleDown",
                        {
                            fill: "#00A9C9", strokeWidth: 0, alignment: go.Spot.Center,
                            fromSpot: go.Spot.Left, toSpot: go.Spot.Right,
                            stretch: go.GraphObject.Vertical, cursor: "pointer"
                        },
                        new go.Binding("fill", "color")),
                    $(go.TextBlock,
                        {
                            margin: 8,
                            maxSize: new go.Size(160, NaN),
                            wrap: go.TextBlock.WrapFit, cursor: "pointer"
                        },
                        new go.Binding("text", 'text'))
                ), {
                    selectionAdornmentTemplate:
                        $(go.Adornment, "Auto",
                            $(go.Shape, "RoundedRectangle",
                                { fill: null, stroke: "dodgerblue", strokeWidth: 8 }),
                            $(go.Placeholder)
                        )  // end Adornment
                }
            ));
        myDiagram.nodeTemplateMap.add("State",
            $(go.Node, "Table", {
                selectionChanged: (node: Node) => this.props.onNodeSelection(node.key as string, node.isSelected)
            },
                // the main object is a Panel that surrounds a TextBlock with a rectangular Shape
                $(go.Panel, "Auto",
                    $(go.Shape, "RoundedRectangle",
                        {
                            fill: "#00A9C9", strokeWidth: 0, alignment: go.Spot.Center,
                            fromSpot: go.Spot.Left, toSpot: go.Spot.Right,
                            stretch: go.GraphObject.Vertical, cursor: "pointer"
                        },
                        new go.Binding("fill", "color")),
                    $(go.TextBlock,
                        {
                            margin: 8,
                            maxSize: new go.Size(160, NaN),
                            wrap: go.TextBlock.WrapFit, cursor: "pointer"
                        },
                        new go.Binding("text", 'text'))
                ), {
                    selectionAdornmentTemplate:
                        $(go.Adornment, "Auto",
                            $(go.Shape, "RoundedRectangle",
                                { fill: null, stroke: "dodgerblue", strokeWidth: 8 }),
                            $(go.Placeholder)
                        )  // end Adornment
                }
            ));
        myDiagram.nodeTemplateMap.add("Start",
            $(go.Node, "Table",
                new go.Binding("itemArray", "boundaryEventArray"),
                new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
                // move a selected part into the Foreground layer, so it isn"t obscured by any non-selected parts
                new go.Binding("layerName", "isSelected", function (s) { return s ? "Foreground" : ""; }).ofObject(),

                $(go.Panel, "Auto",
                    $(go.Shape, "Circle",
                        {
                            minSize: new go.Size(40, 40), fill: "#79C900", strokeWidth: 0, alignment: go.Spot.TopCenter,
                            fromSpot: go.Spot.Left, toSpot: go.Spot.Right,
                            stretch: go.GraphObject.Vertical, cursor: "pointer", fromLinkable: true, toLinkable: true,
                        }),

                    $(go.TextBlock, "Start", { margin: 8, cursor: "pointer" }, new go.Binding('text', 'text'))
                ), {
                    selectionAdornmentTemplate:
                        $(go.Adornment, "Auto",
                            $(go.Shape, "RoundedRectangle",
                                { fill: null, stroke: "dodgerblue", strokeWidth: 8 }),
                            $(go.Placeholder)
                        )  // end Adornment
                }
            ));

        myDiagram.nodeTemplateMap.add("End",
            $(go.Node, "Table",
                $(go.Panel, "Auto",
                    $(go.Shape, "Circle",
                        {
                            minSize: new go.Size(40, 40), fill: "#DC3C00", strokeWidth: 0, alignment: go.Spot.BottomCenter,
                            fromSpot: go.Spot.Left, toSpot: go.Spot.Right,
                            stretch: go.GraphObject.Vertical
                        },
                    ),
                    $(go.TextBlock, "End", { margin: 8 }, new go.Binding('text', 'text'))
                ), {
                    selectionAdornmentTemplate: undefined
                }

                // // three named ports, one on each side except the bottom, all input only:
                // this.makePort("T", go.Spot.Top, go.Spot.Top, false, true),
                // this.makePort("L", go.Spot.Left, go.Spot.Left, false, true),
                // this.makePort("R", go.Spot.Right, go.Spot.Right, false, true)
            ));

        myDiagram.nodeTemplateMap.add("Comment",
            $(go.Node, "Auto", {
                selectionChanged: (node: Node) => this.props.onNodeSelection(node.key as string, node.isSelected)
            },
                $(go.Shape, "File",
                    {
                        fill: "#EFFAB4", strokeWidth: 0, alignment: go.Spot.Center,
                        fromSpot: go.Spot.Left, toSpot: go.Spot.Right,
                        stretch: go.GraphObject.Vertical, cursor: "pointer"
                    }),
                $(go.TextBlock,
                    {
                        margin: 5,
                        maxSize: new go.Size(200, NaN),
                        wrap: go.TextBlock.WrapFit,
                        textAlign: "center",
                        editable: true,
                        font: "bold 12pt Helvetica, Arial, sans-serif",
                        stroke: '#454545'
                    },
                    new go.Binding('text', 'text').makeTwoWay())
            ));
        this._myDiagram = myDiagram;
        return myDiagram;
    }
    componentDidMount() {
        this.props.onRef(this)
    }
    componentWillUnmount() {
        this.props.onRef(undefined)
    }
}

export default MyDiagram;
