using System; using System.Collections.Generic; using System.IO; using System.Reflection; using Wayne.Lib.StateEngine.Generic; using System.Diagnostics; namespace Wayne.Lib.StateEngine { /// /// State factory with the Main object T /// /// public class StateFactory : IStateFactory2 { private readonly Func main; private readonly IServiceLocator serviceContainer; /// /// Constructor /// /// /// public StateFactory(T main, IServiceLocator serviceContainer) { this.main = () => main; this.serviceContainer = serviceContainer; } /// /// Constructor /// /// /// public StateFactory(Func mainFunc, IServiceLocator serviceContainer) { this.main = mainFunc; this.serviceContainer = serviceContainer; } #region Implementation of IStateFactory /// /// Tries to create the requested state /// /// /// public State CreateState(string stateFactoryName) { throw new InvalidOperationException("Use CreateState with StateTypeContainer"); } private State TryCreate(Type stateType) { var constructors = stateType.GetConstructors(); var lastConstructor = constructors[constructors.Length - 1]; var parameterInfos = lastConstructor.GetParameters(); List parameters = new List(); foreach (var parameterInfo in parameterInfos) { try { parameters.Add(serviceContainer.GetService(parameterInfo.ParameterType)); } catch (ServiceContainerException ex) { Debug.WriteLine(string.Format("Creating state {0} because its dependency {1} could not be found in the container. Error message : {2}", stateType, parameterInfo.ParameterType, ex.Message)); throw; } } var stateObject = lastConstructor.Invoke(parameters.ToArray()); return stateObject as State; } /// /// Prepare a state with a Main object if it has got one. /// /// protected virtual void PrepareState(object stateObject) { IGenericState genericClientState = stateObject as IGenericState; if (genericClientState != null) genericClientState.WritableMain = main(); } /// /// Name of the State Factory /// public string Name { get { return GetType().Name; } } /// /// Creates the given state using the supplied StateTypeContainer /// /// /// /// public State CreateState(string stateFactoryName, StateTypeContainer stateTypeContainer) { Type stateType; if (stateTypeContainer.TryGetStateType(stateFactoryName, out stateType)) { //Check if Main is of same type as T. List ancestry = new List(); var mainObjectValue = main(); Type type = mainObjectValue.GetType(); do { ancestry.Add(type); type = type.BaseType; } while (type != typeof(object)); State state = TryCreate(stateType); foreach (Type t in ancestry) { Type genericType = typeof(IGenericState<>); Type actualType = genericType.MakeGenericType(t); if (actualType.IsInstanceOfType(state)) { PropertyInfo propertyInfo = actualType.GetProperty("WritableMain"); propertyInfo.SetValue(state, mainObjectValue, new object[] { }); } } return state; } return null; } #endregion } }