private void TransformBubble(VisualNode node, TranslateTransform transform)
        {
            uint errorBubbleId = node.GetErrorBubbleId();
            uint previewBubbleId = node.GetPreviewBubbleId();

            if (errorBubbleId != uint.MaxValue)
            {
                DrawingVisual errorVisual = visualHost.GetDrawingVisualForBubble(errorBubbleId);
                //RearrangeVisual(errorBubbleId, true);
                errorVisual.Transform = transform;
            }

            if (previewBubbleId != uint.MaxValue)
            {
                DrawingVisual previewVisual = visualHost.GetDrawingVisualForBubble(previewBubbleId);
                //RearrangeVisual(previewBubbleId, true);
                previewVisual.Transform = transform;
            }
        }
        private bool HandleEndNodeEdit(GraphCommand command)
        {
            uint   nodeId = (uint)command.GetArgument(0);
            string text   = command.GetArgument(1) as string;
            bool   commit = (bool)command.GetArgument(2);

            VisualNode node = this.GetVisualNode(nodeId);
            bool       setToPreviousValue = false;
            bool       setToDefaultValue  = false;
            bool       recordAsCreation   = false;
            bool       recordAndDelete    = false;
            bool       validate           = false;
            bool       delete             = false;

            text = node.PreprocessInputString(text);
            bool committingEmptyContent       = text == string.Empty;
            bool committingSameContent        = text == this.previousText;
            bool startedOffDefaultValueDriver = this.previousText == Configurations.DriverInitialTextValue;
            bool committingEmptyCodeBlock     = text == string.Empty || text == Configurations.CodeBlockInitialMessage;
            bool startedOffEmptyCodeBlock     = this.previousText == string.Empty || this.previousText == Configurations.CodeBlockInitialMessage;

            //Flow logic
            if (node.VisualType == NodeType.CodeBlock)
            {
                if (commit)
                {
                    if (committingEmptyCodeBlock)
                    {
                        if (startedOffEmptyCodeBlock)
                        {
                            delete = true;
                        }
                        else
                        {
                            recordAndDelete = true;
                        }
                    }
                    else //Not Empty
                    {
                        if (!committingSameContent)
                        {
                            validate = true;
                        }
                        if (startedOffEmptyCodeBlock)
                        {
                            recordAsCreation = true;
                        }
                    }
                }
                else //Not committing
                {
                    if (startedOffEmptyCodeBlock)
                    {
                        delete = true;
                    }
                }
            }
            else if (node.VisualType == NodeType.Driver)
            {
                if (commit)
                {
                    if (committingEmptyContent)
                    {
                        if (node.IsEditingText)
                        {
                            setToDefaultValue = true;
                        }
                        else if (node.IsEditingCaption)
                        {
                            setToPreviousValue = true;
                        }
                    }
                    else //Not Empty
                    {
                        if (!committingSameContent)
                        {
                            validate = true;
                        }
                    }
                }
            }
            else //Other nodes
            {
                if (commit)
                {
                    if (committingEmptyContent)
                    {
                        setToPreviousValue = true;
                    }
                    else //Not empty
                    {
                        if (!committingSameContent)
                        {
                            validate = true;
                        }
                    }
                }
            }

            //Execution
            node.Edit(this.previousText, false);
            if (delete)
            {
                if (null != visualHost)
                {
                    this.visualHost.RemoveDrawingVisual(node.NodeId);
                    this.visualHost.RemoveDrawingVisual(node.GetErrorBubbleId());
                    this.visualHost.RemoveDrawingVisual(node.GetPreviewBubbleId());
                    this.visualHost.RemoveExtendedBubble(node.GetPreviewBubbleId());
                }
                uint[] outputSlots = node.GetOutputSlots();
                uint[] inputSlots  = node.GetInputSlots();
                if (inputSlots != null)
                {
                    foreach (uint inputSlot in inputSlots)
                    {
                        this.slotCollection.Remove(inputSlot);
                    }
                }
                if (outputSlots != null)
                {
                    foreach (uint outputSlot in outputSlots)
                    {
                        this.slotCollection.Remove(outputSlot);
                    }
                }
                this.nodeCollection.Remove(node.NodeId);
                this.bubbleCollection.Remove(node.GetErrorBubbleId());
                this.bubbleCollection.Remove(node.GetPreviewBubbleId());
            }
            if (recordAndDelete)
            {
                DeltaNodes deltaNodes = new DeltaNodes();
                deltaNodes.AppendToRemovedNodes(node);
                deltaNodes.AppendToModifiedNodes(FindAssociatedNodesFromNodes(deltaNodes.RemovedNodes));

                this.undoRedoRecorder.BeginGroup();
                this.undoRedoRecorder.RecordRuntimeStatesForUndo(this.graphProperties.RuntimeStates);
                this.undoRedoRecorder.RecordNodeDeletionForUndo(deltaNodes.RemovedNodes);
                this.undoRedoRecorder.RecordNodeModificationForUndo(deltaNodes.ModifiedNodes);
                this.DeleteNodes(deltaNodes.RemovedNodes);
                this.undoRedoRecorder.EndGroup();

                this.ValidateDefinedAndReferencedVariables();
                this.UpdateSlotsVisiblity();
                this.SynchronizeToLiveRunner(deltaNodes);
            }
            if (setToDefaultValue)
            {
                if (!startedOffDefaultValueDriver)
                {
                    DeltaNodes deltaNodes = new DeltaNodes();
                    deltaNodes.AppendToModifiedNodes(node);

                    this.undoRedoRecorder.BeginGroup();
                    this.undoRedoRecorder.RecordNodeModificationForUndo(deltaNodes.ModifiedNodes);
                    this.undoRedoRecorder.EndGroup();

                    node.Edit(Configurations.DriverInitialTextValue, false);
                    this.SynchronizeToLiveRunner(deltaNodes);
                }

                string warningMessage = "Field cannot be empty. Value will be set to 0.";
                node.SetErrorValue((object)warningMessage, ErrorType.Warning);
            }
            if (setToPreviousValue)
            {
                string warningMessage = "Field cannot be empty. Value will be reverted to previous state.";
                node.SetErrorValue((object)warningMessage, ErrorType.Warning);
            }
            if (validate)
            {
                DeltaNodes         deltaNodes    = new DeltaNodes();
                List <IVisualNode> addedNodes    = new List <IVisualNode>();
                List <IVisualNode> modifiedNodes = new List <IVisualNode>();
                addedNodes.Add(node); // deltaNodes.AppendToAddedNodes(node);

                // Start monitoring if we are going to undefine any variables.
                this.graphProperties.RuntimeStates.BeginDefinitionMonitor();

                this.undoRedoRecorder.BeginGroup();
                this.undoRedoRecorder.RecordRuntimeStatesForUndo(this.graphProperties.RuntimeStates);
                if (recordAsCreation)
                {
                    this.undoRedoRecorder.RecordNodeCreationForUndo(addedNodes);
                }
                else //record edited node as modification
                {
                    deltaNodes.AppendToModifiedNodes(node);
                    deltaNodes.AppendToModifiedNodes(FindAssociatedNodesFromNodes(addedNodes));
                    this.undoRedoRecorder.RecordNodeModificationForUndo(deltaNodes.ModifiedNodes);
                }

                // These methods (especially the first two and last two) must be
                // called in this particular order (due to their dependencies).
                //
                // GC.ValidateNodesSyntax
                // RS.UpdateVariableDefinitionMap
                // GC.ValidateDefinedAndReferencedVariables
                // GC.UpdateSlotsVisiblity
                // GC.EstablishImplicitConnections
                //
                node.SetErrorValue(null, ErrorType.None);
                node.Edit(text, false);
                this.ValidateNodesSyntax(addedNodes);
                this.graphProperties.RuntimeStates.UpdateVariablesDefinedInNode(node, false);
                this.ValidateDefinedAndReferencedVariables();
                this.UpdateSlotsVisiblity();
                this.EstablishImplicitConnections(modifiedNodes);
                this.edgeController.DeleteUnnecessaryEdges();
                this.undoRedoRecorder.EndGroup();

                // Now all the modifications are over, see what we have undefined.
                Dictionary <uint, List <string> > undefinedVariables = null;
                this.graphProperties.RuntimeStates.EndDefinitionMonitor(out undefinedVariables);
                deltaNodes.AppendUndefinedVariables(undefinedVariables);

                if (recordAsCreation)
                {
                    deltaNodes.AppendToAddedNodes(addedNodes);
                }

                deltaNodes.AppendToModifiedNodes(modifiedNodes);
                this.SynchronizeToLiveRunner(deltaNodes);
            }

            this.UpdateDirtyNodes();
            this.edgeController.UpdateEdgeConnectTo(node);
            node.DisableEdit();
            if (validate && visualHost != null)
            {
                visualHost.ScrollToVisual(visualHost.GetDrawingVisualForNode(node.NodeId));
            }
            return(true);
        }
        // if it is node, once it is selected, it will be brought to the top
        // if it is bubble, if its selected, it will follow its owners' z-index, if unselected, send to back,
        // edge is different, when the edge is moving, it is drawn in another drawingVisual which is topmost,
        // when the edge moving is done, it will draw on the old/own drawingVisual
        //
        private void RearrangeNodeAndBubbleVisual(VisualNode node, bool bringToFront)
        {
            if (null == visualHost)
                return;

            uint errorBubbleId = node.GetErrorBubbleId();
            uint previewBubbleId = node.GetPreviewBubbleId();

            if (bringToFront)
            {
                visualHost.RearrangeDrawingVisual(node.NodeId, bringToFront, uint.MaxValue);

                if (errorBubbleId != uint.MaxValue)
                    visualHost.RearrangeDrawingVisual(errorBubbleId, bringToFront, node.NodeId);

                if (previewBubbleId != uint.MaxValue)
                    visualHost.RearrangeDrawingVisual(previewBubbleId, bringToFront, node.NodeId);
            }
            else
            {
                if (errorBubbleId != uint.MaxValue)
                    visualHost.RearrangeDrawingVisual(errorBubbleId, bringToFront, uint.MaxValue);

                if (previewBubbleId != uint.MaxValue)
                    visualHost.RearrangeDrawingVisual(previewBubbleId, bringToFront, uint.MaxValue);
            }
        }