using System.Collections;
using System.Collections.Generic;

namespace Wayne.Lib.StateEngine
{
    /// <summary>
    /// A collection of State factories. A state machine can have states created by multiple state factories.
    /// When a state object should be created, the factories are queried one by one for the state name. 
    /// </summary>
    public class StateFactories
    {
        #region Fields

        private List<IStateFactory> factoryList = new List<IStateFactory>();

        #endregion

        #region Construction

        /// <summary>
        /// Constructor
        /// </summary>
        public StateFactories()
        {
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Clears the list.
        /// </summary>
        public void Clear()
        {
            factoryList.Clear();
        }

        /// <summary>
        /// Add a factory to the StateFactory Collection.
        /// </summary>
        /// <param name="stateFactory">
        /// The factory that should be added.
        /// </param>
        public void AddFactory(IStateFactory stateFactory)
        {
            if ((stateFactory != null) && !factoryList.Contains(stateFactory))
                factoryList.Add(stateFactory);
        }

        /// <summary>
        /// Calls each registered State Factory to create the requested State.
        ///		If more than one factory returns a state with the specified name,
        ///		the method will throw an exception.
        ///		
        ///		If no factory returns a state, null will be returned.
        ///		
        ///		If exactly one state was created, it will be returned.
        /// </summary>
        /// <param name="stateFactoryName">Name of the State that is going to be created.</param>
        ///<param name="stateTypeContainer"></param>
        ///<returns>The created state</returns>
        /// <exception cref="StateEngineException">If more than one factory creates the state, an exception will be thrown.</exception>
        public State CreateState(string stateFactoryName, StateTypeContainer stateTypeContainer)
        {
            State foundState = null;

            //Ask each factory to create the state object.
            foreach (IStateFactory factory in factoryList)
            {
                IStateFactory2 stateFactory2 = factory as IStateFactory2;
                State state;
                if (stateFactory2 != null)
                    state = stateFactory2.CreateState(stateFactoryName, stateTypeContainer);
                else
                    state = factory.CreateState(stateFactoryName);

                if (state != null)
                {
                    foundState = state;
                    break;
                }
            }
            CompositeState compositeState = foundState as CompositeState;
            if (compositeState != null)
            {
                compositeState.StateMachine.stateFactories = this;
                compositeState.StateMachine.SetAndMergeTypeContainer(stateTypeContainer);
            }
            return foundState;
        }

        #endregion
    }
}