예제 #1
0
        /// <summary>
        /// Checks a state's starting state
        /// </summary>
        /// <param name="state">Specifies state</param>
        private void CheckStartingState(MartyState state)
        {
            // Check if state is null.
            if (state == null)
            {
                throw new ArgumentNullException("Cannot check the starting state of a null state.");
            }

            // Check if state's starting state is null.
            if (state.StartingState == null)
            {
                // Leave.
                return;
            }

            // Check if state has children.
            if (state.Children != null && state.Children.Count == 0)
            {
                throw new FormatException(string.Format("A state cannot have a starting state if it has no children; State = {0}, Invalid Starting State = {1}.",
                                                        state.Name,
                                                        this.GetState(state.StartingState).Name));
            }

            // Check if starting state is one of the states children.
            if (!state.IsChild(state.StartingState))
            {
                throw new FormatException(string.Format("A state cannot have a starting state that isn't one of its children; State = {0}, Invalid Starting State = {1}.",
                                                        state.Name,
                                                        this.GetState(state.StartingState).Name));
            }
        }
예제 #2
0
        /// <summary>
        /// Process exit event
        /// </summary>
        /// <param name="destinationState">Specifies destination state</param>
        internal void Exit(MartyState destinationState)
        {
            // Start event processing.
            this.ProcessingHandler(true);

            // Block transitioning.
            this.BlockTransitionHandler();

            MartyState parentState = this.StateLookupHandler(this.ParentState);

            // Check if destination state is a descendant of this state.
            if (!this.IsDescendant(destinationState))
            {
                // Process this state's exit event.
                this.EventHandler(MartyBase.Exit, null);

                // Check if this state's parent needs to process its exit event.
                if (!(this.ParentState == null || parentState.IsTopState || this.IsSibling(destinationState)))
                {
                    // Process parent's exit event.
                    parentState.EventHandler(MartyBase.Exit, null);
                }
            }

            // Stop event processing.
            this.ProcessingHandler(false);
        }
예제 #3
0
        internal bool IsDescendant(MartyState state)
        {
            if (this.IsChild(state))
            {
                return(true);
            }

            return(this.children.Any(child => this.StateLookupHandler(child).IsDescendant(state)));
        }
예제 #4
0
        internal bool IsSibling(MartyState state)
        {
            if (this.Id == state.Id)
            {
                return(false);
            }

            return(this.ParentState == state.ParentState);
        }
예제 #5
0
        /// <summary>
        /// Prepares Top state for use
        /// </summary>
        private void PrepareTopState()
        {
            // Initailize top state.
            this.Top = new MartyState(MartyConstants.TopStateName);

            // Register Top state.
            this.RegisterState(this.Top, this.TopHandler, null);

            // Throw an exception if starting state is null.
            if (this.TopStartingState == null)
            {
                throw new NullReferenceException(string.Format("The starting state for the {0} state cannot be null.", MartyConstants.TopStateName));
            }

            // Set starting state for Top state.
            this.Top.StartingState = this.TopStartingState.Id;
        }
예제 #6
0
        /// <summary>
        /// Changes states during state transition
        /// </summary>
        /// <param name="destinationState">Specifies destination state</param>
        private void ChangeState(MartyState destinationState)
        {
            // Mark that state transition is in progress.
            this.IsTransitioning = true;

            // Initialize old state as current state.
            MartyState oldState = this.CurrentState;

            // Check if current state is null.
            if (this.CurrentState != null)
            {
                this.CurrentState.Exit(destinationState);
            }

            // Set current state to be destination state.
            this.CurrentState = destinationState;

            // Check if starting state of current state is null.
            if (this.CurrentState.StartingState != null)
            {
                // Process start events until the actual starting state has been reached.
                do
                {
                    // Process start event.
                    this.CurrentState.Start();

                    // Set current state's starting state as current state.
                    this.CurrentState = this.GetState(this.CurrentState.StartingState);
                } while (this.CurrentState.StartingState != null);
            }

            // Check if old state is null.
            if (oldState != null)
            {
                // Process entry event if it isn't null.
                this.CurrentState.Enter(oldState);
            }

            // Store that transitioning has ended.
            this.IsTransitioning = false;

            // Run next instruction.
            this.RunNextInstruction();
        }
예제 #7
0
        /// <summary>
        /// Transitions to a registered state
        /// </summary>
        /// <param name="destination">Specifies destination state</param>
        protected void TransitionTo(MartyState destination)
        {
            // Check if destination state is null.
            if (destination == null)
            {
                // Throw an exception if destination state is null.
                throw new InvalidOperationException(string.Format("Cannot transition to a null state."));
            }

            // Throw an exception if a designation state is not registered.
            if (!this.states.Keys.Any(key => key == destination.Id))
            {
                throw new InvalidOperationException(string.Format("The state {0} hasn't been registered.", destination.Name));
            }

            // Throw an exception if transitioning is blocked in current state.
            if (!this.AllowTransitions)
            {
                throw new InvalidOperationException(string.Format("Transitions cannot be made during Start or Exit events.  See state {0}.", this.CurrentState.Name));
            }

            // Check if current state equals destination.
            if (this.CurrentState == destination)
            {
                // Leave.
                return;
            }

            // Check if state is busy.
            if (this.IsBusy)
            {
                // Queue instruction.
                this.instructions.Enqueue(new MartyInstruction(MartyInstructionTypes.Transition, destination.Id, null));

                // Leave.
                return;
            }

            // Change state.
            this.ChangeState(destination);
        }
예제 #8
0
        /// <summary>
        /// Performs entry action
        /// </summary>
        /// <param name="source">Specifies source state</param>
        internal void Enter(MartyState source)
        {
            // Mark that the event is being processed.
            this.ProcessingHandler(true);

            MartyState parentState = this.StateLookupHandler(this.ParentState);

            // Check if parent's entry event needs processing.
            if (!(null == parentState || parentState.IsTopState || source.IsAncestor(parentState) || this.IsDescendant(source)))
            {
                // Process parent's entry event.
                parentState.EventHandler(MartyBase.Entry, null);
            }

            // Check if source is NOT a descendant.
            if (!this.IsDescendant(source))
            {
                // Process
                this.EventHandler(MartyBase.Entry, null);
            }

            // Release processing.
            this.ProcessingHandler(false);
        }
예제 #9
0
 internal bool IsChild(MartyState state)
 {
     return(this.children.Any(child => child == state.Id));
 }
예제 #10
0
 internal bool IsAncestor(MartyState state)
 {
     return(!state.IsTopState && state.IsDescendant(this));
 }
예제 #11
0
        /// <summary>
        /// Registers a state
        /// </summary>
        /// <param name="state">Specifies state</param>
        /// <param name="eventHandler">Specifies event handler</param>
        /// <param name="parentState">Specifies parent</param>
        /// <param name="startingState">Specifies starting state</param>
        protected void RegisterState(MartyState state, EventHandler eventHandler, MartyState parentState = null, MartyState startingState = null)
        {
            // Check if state is null.
            if (state == null)
            {
                throw new ArgumentNullException("Cannot register a null state.");
            }

            // Check if state is being set as its own parent.
            if (state == parentState)
            {
                throw new ArgumentException(string.Format("State {0} cannot be its own parent.", state.Name));
            }

            // Check if state is being set as its own starting state.
            if (state == startingState)
            {
                throw new ArgumentException(string.Format("State {0} cannot be its own starting state.", state.Name));
            }

            // Try adding state to dictionary.
            try
            {
                // Add state to dictionary.
                this.states.Add(state.Id, state);
            }
            // Catch argument exceptions.
            catch (Exception exception)
            {
                // Throw exception with more detailed error message.
                throw new InvalidOperationException(string.Format("An exception occurred during state registration: {0}; Exception: {1}", state.Name, exception.Message));
            }

            // Add state to parent state's children.
            if (parentState != null)
            {
                if (state.IsTopState)
                {
                    throw new InvalidOperationException(string.Format("Cannot set '{0}' state as parent state. Use NULL instead.", MartyConstants.TopStateName));
                }

                parentState.AddChild(state.Id);
            }
            else
            {
                if (!state.IsTopState)
                {
                    parentState = this.Top;

                    parentState.AddChild(state.Id);
                }
            }

            // Set state's properties.
            state.StartingState          = startingState == null ? default(long?) : startingState.Id;
            state.ParentState            = parentState == null ? default(long?) : parentState.Id;
            state.EventHandler           = eventHandler;
            state.StateLookupHandler     = this.GetState;
            state.ProcessingHandler      = this.SetProcessing;
            state.BlockTransitionHandler = this.BlockTransitioning;
        }