using System;
using System.Collections;
using System.Collections.Generic;
using Chernobyl.Collections.Generic;
namespace Chernobyl.StateMachine
{
    /// 
    /// A default implementation of the  interface. This 
    /// class is used to provide a basic state changing mechanism for states and 
    /// make it easier to create new  types.
    /// 
    public class State : IState
    {
        /// 
        /// This event is raised when this state has become the active state.
        /// This can happen if this instances'  has been
        /// set and the   has had
        /// its  set to this instance. It can also
        /// happen if this instance has decided to activate itself. This event
        /// will only be raised once when the state has become active. It will not be
        /// invoked a second time unless it is deactivated first.
        /// 
        public event EventHandler Entered
        {
            add { _entered += value; }
            remove { _entered -= value; }
        }
        /// 
        /// This event is raised when this state is no longer an active state.
        /// This can happen if this instances'  has
        /// been set and the   has
        /// had its  set to this instance. It can also
        /// happen if this instance has decided to deactivate itself. This event
        /// will only be raised once when the state has been deactivated. It will
        /// not be raised a second time unless it was previously in an active
        /// state.
        /// 
        public event EventHandler Left
        {
            add { _left += value; }
            remove { _left -= value; }
        }
        /// 
        /// The  that this  is a
        /// sub-state of or null if this  is not sub-state
        /// of another state. When set this property will set the incoming
        ///  instances  property
        /// to this instance (unless the value set is null of course). If this
        /// property is set to null (or in other words, this state is
        /// deactivated), two things will occur: (1) the  event
        /// will be raised and (2), immediately prior to raising the
        ///  event, this state will deactivate its child state
        /// (or sub-state) which will deactivate its child states and so and so
        /// forth. Deactivating sub-states is done prior to invoking the
        ///  event so that sub-states will be deactivated from
        /// the lowest sub-state to the highest sub-state. For example, in a
        /// state machine setup like so: state1 -> state2 -> state3 -> state4
        /// If state2 was deactivated, then state4 would be deactivated first
        /// (i.e., its  event would be raised first),
        /// then state3, and finally state2.
        /// 
        public IState ParentState
        {
            get { return _parentState; }
            set { SetParent(ref _parentState, value, this, _entered, _left); }
        }
        /// 
        /// The currently active sub-state of this  or null
        /// if this  doesn't currently have an active
        /// sub-state. When set this property will set the incoming
        ///  instances  property
        /// to this instance (unless the value set is null, in which case, the
        ///  this instances
        ///  is set to null).
        /// 
        public IState ChildState
        {
            get { return _childState; }
            set { SetChild(ref _childState, value, this); }
        }
        /// 
        /// Returns an enumerator that iterates through a down the children of
        /// an  system starting at this .
        /// 
        /// 
        /// The  that allows iteration over
        /// a set of linked instance.
        /// 
        public IEnumerator GetLinkedEnumerator()
        {
            return new LinkedEnumerator(this, LinkedNextState);
        }
        /// 
        /// Returns an enumerator that iterates through the collection.
        /// 
        /// 
        /// A  that can be used to iterate through 
        /// the collection.
        /// 
        public IEnumerator GetEnumerator()
        {
            return GetLinkedEnumerator();
        }
        /// 
        /// A helper method for types deriving from . This
        /// method is used in the  property to properly
        /// set the parent and handle any other tasks that are associated with
        /// setting that property. This method will ensure that the parent isn't
        /// set twice if the  is the same as the
        /// , ensures that the 
        ///  of the old parent is set to null (if
        /// applicable), ensures that the  of the 
        ///  is set to null (if applicable), and ensures 
        /// the  and  are
        /// invoked using  and 
        /// respectively.
        /// 
        /// The previous value of the 
        ///  and the instance that is to take the
        /// new value (if applicable).
        /// The value being set on
        /// .
        /// The instance that was the child of 
        ///  and will be the child of 
        /// . Typically this is the value of 'this'.
        /// The method that is to be invoked if the
        ///  event is to be raised.
        /// The method that is to be invoked if the
        ///  event is to be raised.
        public static void SetParent(ref IState parent, IState newParent, IState child,
                                     EventHandler entered, EventHandler left)
        {
            // Make sure we don't enter or leave a state more than once.
            if (parent != newParent)
            {
                IState previousParentState = parent;
                parent = newParent;
                // The previous parent should no longer reference this
                // IState as it's child.
                if (previousParentState != null &&
                    previousParentState.ChildState == child)
                    previousParentState.ChildState = null;
                if (parent != null)
                {
                    if (entered != null)
                        entered(child, EventArgs.Empty);
                    parent.ChildState = child;
                }
                else
                {
                    // Because this state is being deactivated, that means
                    // that all of the sub-states of this state need to be 
                    // deactivated. We can do that by setting our child
                    // state to null which will deactivate our sub-state and
                    // it's sub-states and so on and so forth.
                    child.ChildState = null;
                    if (left != null)
                        left(child, EventArgs.Empty);
                }
            }
        }
        /// 
        /// A helper method for types deriving from . This
        /// method is used in the  property to properly
        /// set the child and handle any other tasks that are associated with
        /// setting that property. This method will ensure that the parent isn't
        /// set twice if the  is the same as the
        /// , and ensures that the 
        ///  of the old old child is set to null 
        /// (if applicable).
        /// 
        /// The previous value of the 
        ///  and the instance that is to take the
        /// new value (if applicable).
        /// The value being set on
        /// .
        /// The instance that was the parent of 
        ///  and will be the parent of 
        /// . Typically this is the value of 'this'.
        public static void SetChild(ref IState child, IState newChild, IState parent)
        {
            if (child != newChild)
            {
                IState previousChildState = child;
                child = newChild;
                if (child != null)
                    child.ParentState = parent;
                if (previousChildState != null &&
                    previousChildState.ParentState == parent)
                {
                    // The previous child should no longer reference this
                    // IState as it's parent.
                    previousChildState.ParentState = null;
                }
            }
        }
        /// 
        /// Retrieves the  of the passed in 
        ///  state if it has one. This method is
        /// passed to the  to allow it to
        /// iterate over the linked  machine.
        /// 
        /// The  whose 
        ///  is to be retrieved.
        /// The next  in the link or the
        /// .
        /// True if this  has a child state and
        ///  is valid upon exit of this method. False if
        /// otherwise.
        public static bool LinkedNextState(IState current, out IState next)
        {
            next = current.ChildState;
            return next != null;
        }
        /// 
        /// Returns an enumerator that iterates through a collection.
        /// 
        /// 
        /// An  object that can be used to iterate 
        /// through the collection.
        /// 
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
        /// 
        /// The backing field to .
        /// 
        EventHandler _entered;
        /// 
        /// The backing field to .
        /// 
        EventHandler _left;
        /// 
        /// The backing field to .
        /// 
        IState _parentState;
        /// 
        /// The backing field to .
        /// 
        IState _childState;
    }
}