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 method. private readonly Dictionary _userTokenEventTypeDict = new Dictionary(); 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(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(); } /// /// Initializes the manager. Initializes the state machine. /// 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> readCompleted) { //Fail the ongoing reading and replace with new. var currentResponseDelgate = CurrentReadConfigurationResponseDelegate; currentResponseDelgate.Fire(this, new AsyncCompletedEventArgs(false, null, null)); CurrentReadConfigurationResponseDelegate = readCompleted; StateMachine.IncomingEvent(new StateEngineEvent(EventType.GetConfiguration)); } public EventHandler> CurrentReadConfigurationResponseDelegate { get; set; } public void SetConnectedStatus() { _forecourtControl.WritableConnectionState = DeviceConnectionState.Connected; } public void GetDeviceState(string deviceType, EventHandler eventHandler, object userToken) { _forecourtControl.manager.ifsfManager.GetDeviceState(deviceType, -1, eventHandler, userToken, null); } public EventHandler EventHander() where TEventArgs : EventArgs { return (sender, e) => StateMachine.IncomingEvent(GenericEvent.Create(EventType.Response, sender, e)); } public void GetFuelSaleTrx(EventHandler eventHandler, object userToken) { _forecourtControl.manager.ifsfManager.GetAvailableFuelSaleTrxs(-1, eventHandler, userToken, null); } #region Generic asynchronous event handler /// /// 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. /// /// Type of the event argument. /// State engine event type that should be set for the generic event in the state machine. /// The method creates a user token that should be used for the asynchronous call, so it can look up the eventtype properly. /// public EventHandler CreateEventHandler(object eventType, out object userToken) where TAsyncCompleted : Wayne.Lib.UserTokenEventArgs { lock (_eventTypeDictSyncObj) { userToken = new object(); _userTokenEventTypeDict.Add(userToken, eventType); return new EventHandler(GenericHandleEvent); } } /// /// Internal generic event handler that is the target of the event handlers created in the CreateEventHandler <TAsyncCompleted> method. /// /// /// /// private void GenericHandleEvent(object sender, TAsyncCompleted e) where TAsyncCompleted : Wayne.Lib.UserTokenEventArgs { GenericEvent genericEvent = null; lock (_eventTypeDictSyncObj) { if (_userTokenEventTypeDict.ContainsKey(e.UserToken)) { var eventType = _userTokenEventTypeDict[e.UserToken]; _userTokenEventTypeDict.Remove(e.UserToken); genericEvent = new GenericEvent(eventType, sender, e); } } if (genericEvent != null) { StateMachine.IncomingEvent(genericEvent); } } /// /// 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. /// /// public void CancelEventHandler(object userToken) { lock (_eventTypeDictSyncObj) { if (_userTokenEventTypeDict.ContainsKey(userToken)) _userTokenEventTypeDict.Remove(userToken); } } #endregion #region Implementation of IDisposable /// /// Finalizer /// ~ReadDeviceStatusController() { Dispose(false); } /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } private void Dispose(bool disposing) { if (disposing) StateMachine.Dispose(); } #endregion #region Implementation of IIdentifiableEntity /// /// The ID of the entity. /// public int Id { get; private set; } /// /// The main type of entity. /// public string EntityType { get { return "DeviceStatusReader"; } } /// /// This is used by the logger and should never be set by inheriting classes /// public string FullEntityName { get; set; } /// /// A more refined type of the entity, e.g. a specific implementation or brand. /// public string EntitySubType { get { return "FusionFC"; } } /// /// Reference to a possible parent device. /// public IIdentifiableEntity ParentEntity { get; private set; } public ConfigurationSet Configuration { get; set; } #endregion public bool HasVirs() { return FUSIONVirFactory.Virs.Count > 0; } } }