using System;
using System.Collections.Generic;
using Wayne.Lib;
using Wayne.Lib.Log;
using Wayne.Lib.StateEngine;
using Wayne.Lib.StateEngine.Generic;


namespace SinochemInternetPlusApp
{
    public enum TimeoutType
    {
    }

    /// <summary>
    /// The base class for the Managers in Eps. It contains some support functionality that can be shared by the 
    /// descendant classes.
    /// </summary>
    public abstract class StateManager : IDisposable, IStateFactory, IIdentifiableEntity
    {
        static NLog.Logger logger = NLog.LogManager.LoadConfiguration("nlog.config").GetLogger("SinochemEpsApp");

        #region Fields

        protected StateMachine stateMachine;
        protected DebugLogger debugLogger;
        private bool disposed = false;
        private int id;
        public int Id { get { return id; } }
        #endregion

        public DebugLogger DebugLogger { get { return debugLogger; } }

        #region Constuction

        /// <summary>
        /// Initializes a new instance of the CustomManager class.
        /// </summary>
        protected StateManager(int id, string name)
        {
            this.id = id;
            debugLogger = new DebugLogger(this);

            stateMachine = StateMachine.Create(name, StateMachineType.Synchronous, debugLogger, null);
            stateMachine.AddStateFactory(new StateFactory<StateManager>(this, null));
        }

        /// <summary>
        /// Finalizer
        /// </summary>
        ~StateManager()
        {
            Dispose(false);
        }
        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (disposed) return;
            disposed = true;

            if (disposing)
            {
                stateMachine.Dispose();
                debugLogger.Dispose();
            }
        }

        #endregion

        #region Methods

        // States.CONFIGURATION.Config(stateMachine.StateTransitionLookup);         
        protected abstract void ConfigStates();

        /// <summary>
        /// Starts the manager.
        /// </summary>
        public virtual void Start()
        {
            ConfigStates();
            stateMachine.Start();
        }

        public int GetTimeout(State state, TimeoutType timeoutType)
        {
            return 1000;
        }



        #endregion

        #region IStateFactory

        /// <summary>
        /// This method should be overridden for each manager that is defined in another assembly than it's parent manager. I.e. an extension of EpsManager 
        /// defined in another assembly than Wayne.Eps must override this method and add the same code there also.
        /// </summary>
        /// <param name="stateFactoryName"></param>
        /// <returns></returns>
        public virtual State CreateState(string stateFactoryName)
        {
            Type stateType = Type.GetType(stateFactoryName);
            if (stateType != null)
            {
                System.Reflection.ConstructorInfo constructorInfo = stateType.GetConstructor(new Type[0]);
                object stateObject = constructorInfo.Invoke(new object[0]);

                PrepareState(stateObject);

                return stateObject as State;
            }
            return null;
        }

        /// <summary>
        /// This method should be overridden by each manager type that defines generic states with it's own type.
        /// </summary>
        /// <param name="stateObject"></param>
        protected virtual void PrepareState(object stateObject)
        {
            IGenericState<StateManager> genericClientState = stateObject as IGenericState<StateManager>;
            if (genericClientState != null)
                genericClientState.WritableMain = this;

            CompositeState<StateManager> compositeState = stateObject as CompositeState<StateManager>;
            if (compositeState != null)
                compositeState.StateMachine.AddStateFactory(this);
        }

        public string Name
        {
            get { return this.GetType().Name; }
        }

        public abstract string EntityType { get; }

        public string FullEntityName { get => EntityType + "_" + Name; set => throw new NotImplementedException(); }

        public abstract string EntitySubType { get; }

        public IIdentifiableEntity ParentEntity => null;

        #endregion
    }
}