using System; using System.Collections.Generic; using Wayne.ForecourtControl.Fusion.StatusStateMachine.States; using Wayne.ForecourtControl.Vir.Fusion; using Wayne.Lib; using Wayne.Lib.Log; using Wayne.Lib.StateEngine; namespace Wayne.ForecourtControl.Fusion.ReadDeviceStatus { public class ReadDeviceStatusController : IDisposable, Wayne.Lib.IIdentifiableEntity { private readonly FUSIONForecourtControl _forecourtControl; public StateMachine StateMachine { get; private set; } // Dictionary that holds the event types for the event handlers registered by CreateEventHandler<TAsyncCompleted> method. private readonly Dictionary<object, object> _userTokenEventTypeDict = new Dictionary<object, object>(); private readonly object _eventTypeDictSyncObj = new object(); public IFSFManager IfsfManager { get { return _forecourtControl.manager.ifsfManager; } } public ReadDeviceStatusController(IIdentifiableEntity parentEntity, FUSIONForecourtControl forecourtControl) { Id = forecourtControl.Id; _forecourtControl = forecourtControl; ParentEntity = parentEntity; IServiceContainer serviceContainer = ServiceContainerFactory.Create(); StateMachine = StateMachine.Create("", StateMachineType.Synchronous, new DebugLogger(this, true), "StateMachine"); StateMachine.AddStateFactory(new StateFactory<ReadDeviceStatusController>(this, serviceContainer)); StateMachine.OnFinalStateEntered += StateMachineOnOnFinalStateEntered; StateMachine.LogNameKind = StateNameKind.InstanceName; } private void StateMachineOnOnFinalStateEntered(object sender, EventArgs eventArgs) { using (var debugLogger = new DebugLogger(this)) { if (debugLogger.IsActive(DebugLogLevel.Detailed)) debugLogger.Add("ReadDevice Status final state entered", DebugLogLevel.Detailed); } Dispose(); } /// <summary> /// Initializes the manager. Initializes the state machine. /// </summary> public void Initialize() { var stateConfigurator = new StateConfigurator(); stateConfigurator.Config(StateMachine.StateTransitionLookup); StateMachine.Initialize(); if (!StateMachine.Started) { StateMachine.Start(); } } public void Start() { StateMachine.IncomingEvent(new StateEngineEvent(EventType.ReadDeviceStatus)); } public void GetConfiguration(EventHandler<AsyncCompletedEventArgs<ConfigurationSet>> readCompleted) { //Fail the ongoing reading and replace with new. var currentResponseDelgate = CurrentReadConfigurationResponseDelegate; currentResponseDelgate.Fire(this, new AsyncCompletedEventArgs<ConfigurationSet>(false, null, null)); CurrentReadConfigurationResponseDelegate = readCompleted; StateMachine.IncomingEvent(new StateEngineEvent(EventType.GetConfiguration)); } public EventHandler<AsyncCompletedEventArgs<ConfigurationSet>> CurrentReadConfigurationResponseDelegate { get; set; } public void SetConnectedStatus() { _forecourtControl.WritableConnectionState = DeviceConnectionState.Connected; } public void GetDeviceState(string deviceType, EventHandler<AsyncCompletedEventArgs> eventHandler, object userToken) { _forecourtControl.manager.ifsfManager.GetDeviceState(deviceType, -1, eventHandler, userToken, null); } public EventHandler<TEventArgs> EventHander<TEventArgs>() where TEventArgs : EventArgs { return (sender, e) => StateMachine.IncomingEvent(GenericEvent.Create(EventType.Response, sender, e)); } public void GetFuelSaleTrx(EventHandler<AsyncCompletedEventArgs> eventHandler, object userToken) { _forecourtControl.manager.ifsfManager.GetAvailableFuelSaleTrxs(-1, eventHandler, userToken, null); } #region Generic asynchronous event handler /// <summary> /// Method for automatically creating a asynchronous completion event handler. It connects to a private method /// that generically encapsulates the event argument to a state engine generic event. /// </summary> /// <typeparam name="TAsyncCompleted">Type of the event argument.</typeparam> /// <param name="eventType">State engine event type that should be set for the generic event in the state machine.</param> /// <param name="userToken">The method creates a user token that should be used for the asynchronous call, so it can look up the eventtype properly.</param> /// <returns></returns> public EventHandler<TAsyncCompleted> CreateEventHandler<TAsyncCompleted>(object eventType, out object userToken) where TAsyncCompleted : Wayne.Lib.UserTokenEventArgs { lock (_eventTypeDictSyncObj) { userToken = new object(); _userTokenEventTypeDict.Add(userToken, eventType); return new EventHandler<TAsyncCompleted>(GenericHandleEvent<TAsyncCompleted>); } } /// <summary> /// Internal generic event handler that is the target of the event handlers created in the CreateEventHandler <TAsyncCompleted> method. /// </summary> /// <typeparam name="TAsyncCompleted"></typeparam> /// <param name="sender"></param> /// <param name="e"></param> private void GenericHandleEvent<TAsyncCompleted>(object sender, TAsyncCompleted e) where TAsyncCompleted : Wayne.Lib.UserTokenEventArgs { GenericEvent<TAsyncCompleted> genericEvent = null; lock (_eventTypeDictSyncObj) { if (_userTokenEventTypeDict.ContainsKey(e.UserToken)) { var eventType = _userTokenEventTypeDict[e.UserToken]; _userTokenEventTypeDict.Remove(e.UserToken); genericEvent = new GenericEvent<TAsyncCompleted>(eventType, sender, e); } } if (genericEvent != null) { StateMachine.IncomingEvent(genericEvent); } } /// <summary> /// Cancel the automatically created event handler. If the event handler is not cancelled, it will remain in memory forever, since it might never be used. /// </summary> /// <param name="userToken"></param> public void CancelEventHandler(object userToken) { lock (_eventTypeDictSyncObj) { if (_userTokenEventTypeDict.ContainsKey(userToken)) _userTokenEventTypeDict.Remove(userToken); } } #endregion #region Implementation of IDisposable /// <summary> /// Finalizer /// </summary> ~ReadDeviceStatusController() { Dispose(false); } /// <summary> /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// </summary> public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } private void Dispose(bool disposing) { if (disposing) StateMachine.Dispose(); } #endregion #region Implementation of IIdentifiableEntity /// <summary> /// The ID of the entity. /// </summary> public int Id { get; private set; } /// <summary> /// The main type of entity. /// </summary> public string EntityType { get { return "DeviceStatusReader"; } } /// <summary> /// This is used by the logger and should never be set by inheriting classes /// </summary> public string FullEntityName { get; set; } /// <summary> /// A more refined type of the entity, e.g. a specific implementation or brand. /// </summary> public string EntitySubType { get { return "FusionFC"; } } /// <summary> /// Reference to a possible parent device. /// </summary> public IIdentifiableEntity ParentEntity { get; private set; } public ConfigurationSet Configuration { get; set; } #endregion public bool HasVirs() { return FUSIONVirFactory.Virs.Count > 0; } } }