public void RemoveConnection(ConnectionUI connection)
        {
            GraphView.RemoveElement(connection);

            if (connection is TransitionConnectionUI transitionConnection)
            {
                TransitionConnections.Remove(transitionConnection);
            }

            SelectConnection(null);
        }
        public ConnectionUI CreateConnection(IConnectable source, IConnectable destination = null, bool isTemporary = true)
        {
            ConnectionUI connection = null;

            if (isTemporary)
            {
                connection = new ConnectionUI(false)
                {
                    Source = source
                };
                GraphView.AddElement(connection);
                connection.SendToBack();
            }
            else
            {
                bool isNew;
                (connection, isNew)    = source.GetConnection(destination, true);
                connection.Source      = source;
                connection.Destination = destination;

                if (isNew)
                {
                    GraphView.AddElement(connection);
                    connection.SendToBack();

                    connection.Source      = source;
                    connection.Destination = destination;
                    source.ExitConnections.Add(connection);
                    destination.EntryConnections.Add(connection);

                    source.OnExitConnect(connection);
                    destination.OnEntryConnect(connection);

                    connection.schedule.Execute(() => connection.Refresh());

                    if (connection is TransitionConnectionUI transitionConnection)
                    {
                        TransitionConnections.Add(transitionConnection);
                    }
                }
            }

            return(connection);
        }
        private void SaveStateMachine()
        {
            var stateMachine = new StateMachineNode();

            NodeUI.StateMachineNodeAsset = new StateMachineNodeAsset {
                Data = stateMachine
            };

            var parameterMap  = new Dictionary <ParameterNodeUI, Parameter>();
            var stateMap      = new Dictionary <StateNodeUI, State>();
            var anyStateMap   = new Dictionary <AnyStateNodeUI, AnyState>();
            var transitionMap = new Dictionary <TransitionInfo, Transition>();

            Parameters.Items.Values.ForEach(p =>
            {
                var parameter  = stateMachine.AddParameter(p.Name);
                parameter.Type = (ValueProviderType)p.ParameterTypeField.value;
                NodeUI.StateMachineNodeAsset.ParameterMap.Add(parameter.Id, new NodeVisualInfo(p.GetPosition().position, p.expanded));

                switch (parameter.ValueProvider)
                {
                case BoolProvider boolProvider:
                    boolProvider.Value = p.BoolField.value;
                    break;

                case IntProvider intProvider:
                    intProvider.Value = p.IntField.value;
                    break;

                case FloatProvider floatProvider:
                    floatProvider.Value = p.FloatField.value;
                    break;

                default:
                    break;
                }

                parameterMap.Add(p, parameter);
            });

            TransitionConnections.ForEach(transitionConnection =>
            {
                transitionConnection.Transitions.ForEach(transitionInfo =>
                {
                    Transition transition = new Transition()
                    {
                        DurationType            = transitionInfo.DurationType,
                        Duration                = transitionInfo.Duration,
                        OffsetType              = transitionInfo.OffsetType,
                        Offset                  = transitionInfo.Offset,
                        InterruptionSource      = transitionInfo.InterruptionSource,
                        OrderedInterruption     = transitionInfo.OrderedInterruption,
                        InterruptableByAnyState = transitionInfo.InterruptableByAnyState,
                        PlayAfterTransition     = transitionInfo.PlayAfterTransition
                    };

                    stateMachine.Transitions.Add(transition);
                    transitionMap.Add(transitionInfo, transition);
                });
            });

            States.Items.Values.ForEach(stateNode =>
            {
                var state = stateMachine.AddState(stateNode.Name);

                stateNode.ExitConnections.ForEach(connection =>
                {
                    ((TransitionConnectionUI)connection).Transitions.ForEach(transitionInfo =>
                    {
                        Transition transition  = transitionMap[transitionInfo];
                        transition.SourceState = state;
                        state.ExitTransitions.Add(transition);
                    });
                });

                stateNode.EntryConnections.ForEach(connection =>
                {
                    if (!(connection is TransitionConnectionUI transitionConnection))
                    {
                        return;
                    }

                    transitionConnection.Transitions.ForEach(transitionInfo =>
                    {
                        Transition transition       = transitionMap[transitionInfo];
                        transition.DestinationState = state;
                        state.EntryTransitions.Add(transition);
                    });
                });

                NodeUI.StateMachineNodeAsset.StateMap.Add(state.Id, new NodeVisualInfo(stateNode.GetPosition().position, stateNode.expanded));
                stateMap.Add(stateNode, state);
            });

            HashSet <AnyStateNodeUI> alreadyAddedAnyStates = new HashSet <AnyStateNodeUI>();

            if (GraphView.AnyStatePriorityManager == null)
            {
                NodeUI.StateMachineNodeAsset.AnyStatePriorityManager = null;
            }
            else
            {
                NodeUI.StateMachineNodeAsset.AnyStatePriorityManager = new NodeVisualInfo(GraphView.AnyStatePriorityManager.GetPosition().position, GraphView.AnyStatePriorityManager.expanded);

                foreach (var anyStateNode in GraphView.AnyStatePriorityManager.AnyStates)
                {
                    if (anyStateNode == null)
                    {
                        continue;
                    }

                    AnyState anyState = anyStateNode.GenerateData(stateMap);

                    anyStateNode.ExitConnections.ForEach(connection =>
                    {
                        ((TransitionConnectionUI)connection).Transitions.ForEach(transitionInfo =>
                        {
                            Transition transition  = transitionMap[transitionInfo];
                            transition.SourceState = anyState;
                            anyState.ExitTransitions.Add(transition);
                        });
                    });

                    stateMachine.AnyStates.AddItem(anyState);
                    NodeUI.StateMachineNodeAsset.AnyStateMap.Add(anyState.Id, new NodeVisualInfo(anyStateNode.GetPosition().position, anyStateNode.expanded));
                    alreadyAddedAnyStates.Add(anyStateNode);
                    anyStateMap.Add(anyStateNode, anyState);
                }
            }

            AnyStates.Items.Values.ForEach(anyStateNode =>
            {
                if (alreadyAddedAnyStates.Contains(anyStateNode))
                {
                    return;
                }

                AnyState anyState = anyStateNode.GenerateData(stateMap);

                anyStateNode.ExitConnections.ForEach(connection =>
                {
                    ((TransitionConnectionUI)connection).Transitions.ForEach(transitionInfo =>
                    {
                        Transition transition  = transitionMap[transitionInfo];
                        transition.SourceState = anyState;
                        anyState.ExitTransitions.Add(transition);
                    });
                });

                stateMachine.AnyStates.AddItem(anyState);
                NodeUI.StateMachineNodeAsset.AnyStateMap.Add(anyState.Id, new NodeVisualInfo(anyStateNode.GetPosition().position, anyStateNode.expanded));
                anyStateMap.Add(anyStateNode, anyState);
            });

            TransitionConnections.ForEach(transitionConnection =>
            {
                transitionConnection.Transitions.ForEach(transitionInfo =>
                {
                    Transition transition          = transitionMap[transitionInfo];
                    transition.Conditions.Capacity = transitionInfo.Conditions.Count;

                    transitionInfo.Conditions.ForEach(infoCondition =>
                    {
                        TransitionCondition condition = new TransitionCondition();

                        if (infoCondition.ProviderSourceType == ValueProviderSourceType.State)
                        {
                            if (infoCondition.State != null)
                            {
                                State state = stateMap[infoCondition.State];

                                switch (infoCondition.StateValueProvider)
                                {
                                case StateValueProviders.PreviousTime:
                                    condition.SetValueProvider(state.PreviousTime);
                                    break;

                                case StateValueProviders.Time:
                                    condition.SetValueProvider(state.Time);
                                    break;

                                case StateValueProviders.PreviousNormalizedTime:
                                    condition.SetValueProvider(state.PreviousNormalizedTime);
                                    break;

                                case StateValueProviders.NormalizedTime:
                                    condition.SetValueProvider(state.NormalizedTime);
                                    break;
                                }

                                FloatConditionEvaluator floatEvaluator = (FloatConditionEvaluator)condition.Evaluator;
                                floatEvaluator.Comparison      = infoCondition.FloatComparison;
                                floatEvaluator.ComparisonValue = infoCondition.FloatComparisonValue;
                            }
                        }
                        else if (infoCondition.Parameter != null)
                        {
                            condition.SetValueProvider(parameterMap[infoCondition.Parameter].ValueProvider);

                            switch (condition.Evaluator)
                            {
                            case BoolConditionEvaluator boolEvaluator:
                                boolEvaluator.ComparisonValue = infoCondition.BoolComparisonValue ? Bool.True : Bool.False;
                                break;

                            case IntConditionEvaluator intEvaluator:
                                intEvaluator.Comparison      = infoCondition.IntComparison;
                                intEvaluator.ComparisonValue = infoCondition.IntComparisonValue;
                                break;

                            case FloatConditionEvaluator floatEvaluator:
                                floatEvaluator.Comparison      = infoCondition.FloatComparison;
                                floatEvaluator.ComparisonValue = infoCondition.FloatComparisonValue;
                                break;

                            default:
                                break;
                            }
                        }

                        transition.Conditions.Add(condition);
                    });
                });
            });

            GraphView.EntryNode.GenerateData(stateMachine, stateMap);
            NodeUI.StateMachineNodeAsset.EntryState = new NodeVisualInfo(GraphView.EntryNode.GetPosition().position, GraphView.EntryNode.expanded);

            NodeUI.UpdateStatePorts();
        }