public void GetScheduledInstrumentAlarmEventDownloadAction()
        {
            // arrange
            instrument     = Helper.GetInstrumentForTest(DeviceType.VPRO, DeviceSubType.VentisPro4);
            dockingStation = Helper.GetDockingStationForTest(DeviceType.MX4);
            InstrumentAlarmEventsDownloadOperation operation = new InstrumentAlarmEventsDownloadOperation();

            List <EventJournal> eventJournals = new List <EventJournal>();

            eventJournals.Add(new EventJournal(EventCode.GetCachedCode(EventCode.InstrumentDiagnostics), instrument.SerialNumber, DateTime.Now.AddMonths(-1), DateTime.Now.AddMonths(-1), true, instrument.SoftwareVersion));
            eventJournals.Add(new EventJournal(EventCode.GetCachedCode(EventCode.DownloadAlarmEvents), instrument.SerialNumber, DateTime.Now.AddMonths(-1), DateTime.Now.AddMonths(-1), true, instrument.SoftwareVersion));

            _eventJournalDataAccess.Setup(x => x.FindBySerialNumbers(It.IsAny <string[]>(), It.IsAny <IDataAccessTransaction>())).Returns(eventJournals);
            _eventJournalDataAccess.Setup(x => x.FindLastEventByInstrumentSerialNumber(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <IDataAccessTransaction>())).Returns(eventJournals);

            _scheduleDailyAccess.Setup(x => x.FindGlobalSchedules(It.IsAny <IDataAccessTransaction>())).Returns(new List <Schedule>()
            {
                new ScheduledDaily(DomainModelConstant.NullId, DomainModelConstant.NullId, string.Empty, EventCode.GetCachedCode(EventCode.DownloadAlarmEvents), EquipmentTypeCode.Instrument, string.Empty, true, true, 1, DateTime.Now.AddYears(-1), new TimeSpan(9, 0, 0))
            });

            Initialize();

            // act
            schema.Setup(x => x.Activated).Returns(true);
            dsEvent = new InstrumentAlarmEventsDownloadEvent(operation);
            CreateMasterForTest();
            nextAction = scheduler.GetNextAction(dsEvent);

            // assert
            Xunit.Assert.True(nextAction is InstrumentAlarmEventsDownloadAction);
        }
        public void InstrumentRequiresOperatorAction()
        {
            // arrange
            SettingsReadOperation operation = new SettingsReadOperation();

            dsEvent = new SettingsReadEvent(operation);

            dockingStation = Helper.GetDockingStationForTest(DeviceType.MX4);
            instrument     = Helper.GetInstrumentForTest(DeviceType.VPRO, DeviceSubType.VentisPro4);

            Initialize();

            Sensor sensor = new Sensor();

            sensor.Enabled           = true;
            sensor.CalibrationStatus = Status.Failed;
            sensor.Type.Code         = SensorCode.O3;

            InstalledComponent installedComponent = new InstalledComponent();

            installedComponent.Position  = 1;
            installedComponent.Component = sensor;
            instrument.InstalledComponents.Add(installedComponent);

            Configuration.DockingStation = dockingStation;

            CreateMasterForTest();

            // act
            nextAction = scheduler.GetNextAction(dsEvent);

            // assert
            Xunit.Assert.True(nextAction is ManualCalibrationRequiredAction);
        }
        public void ReturnManualBumpTestRequiredActionForInstrumentWithBumpFailedSensor()
        {
            // arrange
            InstrumentBumpTestAction action = Helper.GetBumpTestAction(DeviceType.VPRO, new List <string>()
            {
                GasCode.CO, GasCode.H2S, GasCode.O3
            }, DeviceSubType.VentisPro4);

            foreach (InstalledComponent installedComponent in action.Instrument.InstalledComponents.Where(comp => comp.Component is Sensor))
            {
                Sensor sensor = installedComponent.Component as Sensor;
                sensor.BumpTestStatus = false;
            }
            instrument = action.Instrument;
            Initialize();

            CreateMasterForTest();

            // act
            InstrumentBumpTestOperation operation = new InstrumentBumpTestOperation(action);

            dsEvent    = new InstrumentBumpTestEvent(operation);
            nextAction = scheduler.GetNextAction(dsEvent);

            // assert
            Xunit.Assert.True(nextAction is ManualBumpTestRequiredAction);
        }
        public void GetNothingActionIfNoEventIsScheduled()
        {
            // arrange
            instrument     = Helper.GetInstrumentForTest(DeviceType.VPRO, DeviceSubType.VentisPro4);
            dockingStation = Helper.GetDockingStationForTest(DeviceType.MX4);
            InstrumentAlarmEventsClearOperation operation = new InstrumentAlarmEventsClearOperation();

            List <EventJournal> eventJournals = new List <EventJournal>();

            eventJournals.Add(new EventJournal(EventCode.GetCachedCode(EventCode.InstrumentDiagnostics), instrument.SerialNumber, DateTime.Now.AddMonths(-1), DateTime.Now.AddMonths(-1), true, instrument.SoftwareVersion));

            _eventJournalDataAccess.Setup(x => x.FindBySerialNumbers(It.IsAny <string[]>(), It.IsAny <IDataAccessTransaction>())).Returns(eventJournals);
            _eventJournalDataAccess.Setup(x => x.FindLastEventByInstrumentSerialNumber(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <IDataAccessTransaction>())).Returns(eventJournals);

            Initialize();

            // act
            schema.Setup(x => x.Activated).Returns(true);
            dsEvent = new InstrumentAlarmEventsClearEvent(operation);
            CreateMasterForTest();
            nextAction = scheduler.GetNextAction(dsEvent);

            // assert
            Xunit.Assert.True(nextAction is NothingAction);
        }
        public void ReforceCalibration()
        {
            // arrange
            dockingStation = Helper.GetDockingStationForTest(DeviceType.GBPRO);
            instrument     = Helper.GetInstrumentForTest(DeviceType.GBPRO);
            List <InstalledComponent> installedComponents = Helper.GetSensorsForTest(new List <string>()
            {
                GasCode.CO
            });

            instrument.InstalledComponents.AddRange(installedComponents);
            Initialize();

            // act
            dsEvent = new NothingEvent();
            CreateMasterForTest();
            scheduler.ReForceEvent(new InstrumentCalibrationAction()
            {
                Trigger = TriggerType.Forced
            });
            nextAction = scheduler.GetNextAction(dsEvent);

            // assert
            Xunit.Assert.True(nextAction is InstrumentCalibrationAction);
            Xunit.Assert.True(nextAction.Trigger == TriggerType.Forced);
        }
        public void GetCalibrationActionForSensorRemoved()
        {
            // arrange
            InstrumentCalibrationAction action = new InstrumentCalibrationAction();

            instrument = Helper.GetInstrumentForTest(DeviceType.VPRO, DeviceSubType.VentisPro4);
            List <InstalledComponent> installedComponents = Helper.GetSensorsForTest(new List <string>()
            {
                GasCode.CO, GasCode.H2S, GasCode.O2, GasCode.CombustibleLEL
            });

            dockingStation = Helper.GetDockingStationForTest(DeviceType.MX4);

            List <EventJournal> eventJournals = new List <EventJournal>();

            eventJournals.Add(new EventJournal(EventCode.GetCachedCode(EventCode.InstrumentDiagnostics), instrument.SerialNumber, DateTime.Now.AddMonths(-1), DateTime.Now.AddMonths(-1), true, instrument.SoftwareVersion));
            installedComponents.ForEach(comp => eventJournals.Add(new EventJournal(EventCode.Calibration, comp.Component.Uid, instrument.SerialNumber, DateTime.Now.AddMonths(-1), DateTime.Now.AddMonths(-1), true, comp.Position, instrument.SoftwareVersion)));
            installedComponents.Remove(installedComponents.Last());
            instrument.InstalledComponents.AddRange(installedComponents);
            _eventJournalDataAccess.Setup(x => x.FindBySerialNumbers(It.IsAny <string[]>(), It.IsAny <IDataAccessTransaction>())).Returns(eventJournals);
            _eventJournalDataAccess.Setup(x => x.FindLastEventByInstrumentSerialNumber(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <IDataAccessTransaction>())).Returns(eventJournals);

            Initialize();

            // act
            CreateMasterForTest();
            schema.Setup(x => x.Activated).Returns(true);
            InstrumentCalibrationOperation operation = new InstrumentCalibrationOperation(action);

            dsEvent    = new InstrumentCalibrationEvent(operation);
            nextAction = scheduler.GetNextAction(dsEvent);

            // assert
            Xunit.Assert.True(nextAction is InstrumentCalibrationAction);
        }
        private DockingStationAction ExamineErrors(DockingStationEvent dsEvent, InetUploader inet)
        {
            DockingStationErrorLevel highestError = DockingStationErrorLevel.None;

            DockingStationAction dsAction = null;

            foreach (DockingStationError error in dsEvent.Errors)
            {
                highestError = (DockingStationErrorLevel)Math.Max((int)error.ErrorLevel, (int)highestError);
            }

            if (dsAction != null)
            {
                return(dsAction);
            }

            if (highestError >= DockingStationErrorLevel.Error)
            {
                dsAction = new UnavailableAction();
                Log.Debug(string.Format("{0}Returning {1}", Name, dsAction.Name));
                return(dsAction);
            }

            return(null);
        }
        public void GetCalibrationActionforForcedBumpTestOnCalFailedSensors()
        {
            // arrange
            instrument = Helper.GetInstrumentForTest(DeviceType.VPRO, DeviceSubType.VentisPro4);
            List <InstalledComponent> installedComponents = Helper.GetSensorsForTest(new List <string>()
            {
                GasCode.CO, GasCode.H2S, GasCode.O2, GasCode.CombustibleLEL
            });

            foreach (InstalledComponent installComp in installedComponents)
            {
                Sensor sensor = installComp.Component as Sensor;
                sensor.CalibrationStatus = Status.Failed;
            }

            instrument.InstalledComponents.AddRange(installedComponents);
            ScheduledNow scheduledNow = new ScheduledNow(0, 0, string.Empty, new EventCode(EventCode.BumpTest, 1, EquipmentTypeCode.Instrument, typeof(InstrumentBumpTestAction)), EquipmentTypeCode.VDS, null, false);

            scheduledNow.SerialNumbers.Add(instrument.SerialNumber);

            Initialize();
            CreateMasterForTest();

            // act
            dsEvent = new InstrumentBumpTestEvent();
            scheduler.StackForcedSchedule(scheduledNow);
            nextAction = scheduler.GetNextAction(dsEvent);

            // assert
            Xunit.Assert.True(nextAction is CalibrationFailureAction);
        }
        public DockingStationAction ReportFlowFailedError(GasEndPoint gasEndPoint)
        {
            Log.Debug(string.Format("Empty Cylinder was reported on position {0} during gas operation.", gasEndPoint.Position));

            using (InetUploader inetUploader = new InetUploader())
            {
                DockingStationAction dsAction = ProcessEmptyGasEndPoint(gasEndPoint, inetUploader);
                return(dsAction);
            }
        }
        public void GetInstrumentDatalogClearActionAsFollowUpActionForInstrumentDatalogDownloadToClearErrors()
        {
            // arrange
            InstrumentDatalogDownloadEvent dsEvent = new InstrumentDatalogDownloadEvent();

            dsEvent.Errors.Add(new DockingStationError("Test Error!"));
            Initialize();

            CreateMasterForTest();

            // act
            nextAction = scheduler.GetNextAction(dsEvent);

            // assert
            Xunit.Assert.True(nextAction is InstrumentDatalogClearAction);
        }
        public void GetSettingsReadActionAsFollowUpActionForCylinderPressureReset()
        {
            // arrange
            CylinderPressureResetOperation operation = new CylinderPressureResetOperation();

            dsEvent = new CylinderPressureResetEvent(operation);
            Initialize();

            CreateMasterForTest();

            // act
            nextAction = scheduler.GetNextAction(dsEvent);

            // assert
            Xunit.Assert.True(nextAction is SettingsReadAction);
        }
        public void GetSettingsReadActionAsFollowUpActionForSettingsUpdate()
        {
            // arrange
            SettingsUpdateOperation operation = new SettingsUpdateOperation();

            dsEvent = new SettingsUpdateEvent(operation);
            Initialize();

            CreateMasterForTest();

            // act
            nextAction = scheduler.GetNextAction(dsEvent);

            // assert
            Xunit.Assert.True(nextAction is SettingsReadAction);
        }
        public void GetInstrumentDatalogClearActionAsFollowUpActionForInstrumentDatalogDownloadToClearInstrumentSessions()
        {
            // arrange
            InstrumentDatalogDownloadEvent dsEvent = new InstrumentDatalogDownloadEvent();

            dsEvent.InstrumentSessions.Add(new DatalogSession());
            Initialize();

            CreateMasterForTest();

            // act
            nextAction = scheduler.GetNextAction(dsEvent);

            // assert
            Xunit.Assert.True(nextAction is InstrumentDatalogClearAction);
        }
        public void GetInstrumentAlarmEventClearActionAsFollowUpActionForInstrumentAlarmEventDownloadToClearInstrumentAlarmEvents()
        {
            // arrange
            InstrumentAlarmEventsDownloadOperation operation = new InstrumentAlarmEventsDownloadOperation();
            InstrumentAlarmEventsDownloadEvent     dsEvent   = new InstrumentAlarmEventsDownloadEvent(operation);

            dsEvent.AlarmEvents = new AlarmEvent[] { new AlarmEvent() };
            Initialize();

            CreateMasterForTest();

            // act
            nextAction = scheduler.GetNextAction(dsEvent);

            // assert
            Xunit.Assert.True(nextAction is InstrumentAlarmEventsClearAction);
        }
        public void GetForcedSettingsReadForDockingStation()
        {
            // arrange
            instrument = Helper.GetInstrumentForTest(DeviceType.VPRO, DeviceSubType.VentisPro4);
            ScheduledNow scheduledNow = new ScheduledNow(0, 0, string.Empty, new EventCode(EventCode.SettingsRead, 1, EquipmentTypeCode.VDS, typeof(SettingsReadAction)), EquipmentTypeCode.VDS, null, false);

            Initialize();
            CreateMasterForTest();

            // act
            dsEvent = new NothingEvent();
            scheduler.StackForcedSchedule(scheduledNow);
            nextAction = scheduler.GetNextAction(dsEvent);

            // assert
            Xunit.Assert.True(nextAction is SettingsReadAction);
        }
        public void ForceCylinderResetEvent()
        {
            // arrange
            dockingStation = Helper.GetDockingStationForTest(DeviceType.SC);
            instrument     = Helper.GetInstrumentForTest(DeviceType.SC);
            Initialize();

            // act
            dsEvent = new NothingEvent();
            CreateMasterForTest();
            scheduler.ForceEvent(EventCode.CylinderPressureReset, true);
            nextAction = scheduler.GetNextAction(dsEvent);

            // assert
            Xunit.Assert.True(nextAction is CylinderPressureResetAction);
            Xunit.Assert.True(nextAction.Trigger == TriggerType.Forced);
        }
        public void GetNothingActionDueToInstrumentCriticalError()
        {
            // arrange
            InstrumentDiagnosticAction    action    = new InstrumentDiagnosticAction();
            InstrumentDiagnosticOperation operation = new InstrumentDiagnosticOperation(action);
            InstrumentDiagnosticEvent     dsEvent   = new InstrumentDiagnosticEvent(operation);

            instrument = Helper.GetInstrumentForTest(DeviceType.VPRO, DeviceSubType.VentisPro4);
            dsEvent.InstrumentInCriticalError = true;

            Initialize();
            CreateMasterForTest();
            // act
            nextAction = scheduler.GetNextAction(dsEvent);

            // assert
            Xunit.Assert.True(nextAction is NothingAction);
        }
        public void DSXNotSynchronized()
        {
            // arrange
            SettingsReadOperation operation = new SettingsReadOperation();

            dsEvent = new SettingsReadEvent(operation);

            Mock <Schema> schema = new Mock <Schema>();

            schema.Setup(x => x.Synchronized).Returns(false);
            Configuration.Schema = schema.Object;

            // act
            nextAction = scheduler.GetNextAction(dsEvent);

            // assert
            Xunit.Assert.True(nextAction is NothingAction);
        }
        public void InitialReadingNeeded()
        {
            // arrange
            SettingsUpdateOperation operation = new SettingsUpdateOperation();

            dsEvent = new SettingsUpdateEvent(operation);
            Initialize();

            switchService.Setup(x => x.InitialReadSettingsNeeded).Returns(true);

            CreateMasterForTest();

            // act
            nextAction = scheduler.GetNextAction(dsEvent);

            // assert
            Xunit.Assert.True(nextAction is NothingAction);
        }
        public void ExecuteFollowUpAction()
        {
            // arrange
            SettingsUpdateOperation operation = new SettingsUpdateOperation();

            dsEvent = new SettingsUpdateEvent(operation);
            Initialize();

            dsEvent.Trigger = TriggerType.Scheduled;

            CreateMasterForTest();

            // act
            nextAction = scheduler.GetNextAction(dsEvent);

            // assert
            Xunit.Assert.True(nextAction is CylinderPressureResetAction);
        }
        public void GetScheduledInstrumentDiagnosticsAction()
        {
            // arrange
            instrument     = Helper.GetInstrumentForTest(DeviceType.VPRO, DeviceSubType.VentisPro4);
            dockingStation = Helper.GetDockingStationForTest(DeviceType.MX4);
            InstrumentSettingsUpdateOperation operation = new InstrumentSettingsUpdateOperation();

            Initialize();

            // act
            schema.Setup(x => x.Activated).Returns(true);
            dsEvent = new InstrumentSettingsUpdateEvent(operation);
            CreateMasterForTest();
            nextAction = scheduler.GetNextAction(dsEvent);

            // assert
            Xunit.Assert.True(nextAction is InstrumentDiagnosticAction);
        }
        public void GetDockingStationFirmwareUpgradeAction()
        {
            // arrange
            instrument = Helper.GetInstrumentForTest(DeviceType.MX6);
            List <InstalledComponent> installedComponents = Helper.GetSensorsForTest(new List <string>()
            {
                GasCode.CO, GasCode.H2S, GasCode.O2
            });

            instrument.InstalledComponents.AddRange(installedComponents);
            dockingStation = Helper.GetDockingStationForTest(DeviceType.MX6);
            dockingStation.SoftwareVersion = "7.6.0.1";

            List <EventJournal> eventJournals = new List <EventJournal>();

            eventJournals.Add(new EventJournal(EventCode.GetCachedCode(EventCode.InstrumentDiagnostics), instrument.SerialNumber, DateTime.Now.AddMonths(-1), DateTime.Now.AddMonths(-1), true, instrument.SoftwareVersion));
            installedComponents.ForEach(installComp => eventJournals.Add(new EventJournal(EventCode.Calibration, installComp.Component.Uid, instrument.SerialNumber, DateTime.Now.AddMonths(-1), DateTime.Now.AddMonths(-1), true, installComp.Position, instrument.SoftwareVersion)));
            installedComponents.ForEach(installComp => eventJournals.Add(new EventJournal(EventCode.BumpTest, installComp.Component.Uid, instrument.SerialNumber, DateTime.Now.AddMonths(-1), DateTime.Now.AddMonths(-1), true, installComp.Position, instrument.SoftwareVersion)));

            List <Schedule> schedules       = new List <Schedule>();
            Schedule        firmwareUpgrade = new ScheduledOnce(DomainModelConstant.NullId, DomainModelConstant.NullId, string.Empty, EventCode.GetCachedCode(EventCode.FirmwareUpgrade), dockingStation.Type.ToString(), null, true, DateTime.Now.AddYears(-1), new TimeSpan(9, 0, 0));

            firmwareUpgrade.ScheduleProperties.Add(new ScheduleProperty(DomainModelConstant.NullId, ScheduleProperty.FirmwareUpgradeVersion, 0, "7.6.2.1"));
            schedules.Add(firmwareUpgrade);
            _scheduleUponDockingAccess.Setup(x => x.FindGlobalTypeSpecificSchedules(It.IsAny <string[]>(), It.IsAny <IDataAccessTransaction>())).Returns(schedules);
            _eventJournalDataAccess.Setup(x => x.FindBySerialNumbers(It.IsAny <string[]>(), It.IsAny <IDataAccessTransaction>())).Returns(eventJournals);
            _eventJournalDataAccess.Setup(x => x.FindLastEventByInstrumentSerialNumber(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <IDataAccessTransaction>())).Returns(eventJournals);
            _queueDataAccess.Setup(x => x.GetCount()).Returns(0);

            Initialize();

            // act
            schema.Setup(x => x.Activated).Returns(true);
            schema.Setup(x => x.AccountNum).Returns("12345");
            schema.Setup(x => x.ServiceCode).Returns("REPAIR");
            controllerWrapper.Setup(x => x.FirmwareVersion).Returns("7.6.0.1");

            CreateMasterForTest();
            dsEvent    = new NothingEvent();
            nextAction = scheduler.GetNextAction(dsEvent);

            // assert
            Xunit.Assert.True(nextAction is FirmwareUpgradeAction);
        }
        public void GetInstrumentManualOperationsClearActionAsFollowUpActionForInstrumentManualOperationsDownloadToClearGasReponses()
        {
            // arrange
            InstrumentManualOperationsDownloadAction    action    = new InstrumentManualOperationsDownloadAction();
            InstrumentManualOperationsDownloadOperation operation = new InstrumentManualOperationsDownloadOperation(action);
            InstrumentManualOperationsDownloadEvent     dsEvent   = new InstrumentManualOperationsDownloadEvent(operation);

            dsEvent.GasResponses.Add(new SensorGasResponse());

            Initialize();

            CreateMasterForTest();

            // act
            nextAction = scheduler.GetNextAction(dsEvent);

            // assert
            Xunit.Assert.True(nextAction is InstrumentManualOperationsClearAction);
        }
        public void GetBadPumpTubingDetectedActionForCalibration()
        {
            // arrange
            InstrumentManualOperationsDownloadAction    action    = new InstrumentManualOperationsDownloadAction();
            InstrumentManualOperationsDownloadOperation operation = new InstrumentManualOperationsDownloadOperation(action);

            dsEvent    = new InstrumentManualOperationsDownloadEvent(operation);
            instrument = Helper.GetInstrumentForTest(DeviceType.VPRO, DeviceSubType.VentisPro4);
            Initialize();

            switchService.Setup(x => x.BadPumpTubingDetectedDuringCal).Returns(true);

            CreateMasterForTest();
            // act
            nextAction = scheduler.GetNextAction(dsEvent);

            // assert
            Xunit.Assert.True(nextAction is BadPumpTubingDetectedAction);
        }
        public void GetNextForcedAction()
        {
            // arrange
            SettingsReadOperation operation = new SettingsReadOperation();

            dsEvent = new SettingsReadEvent(operation);

            instrument = Helper.GetInstrumentForTest(DeviceType.VPRO, DeviceSubType.VentisPro4);

            Initialize();

            // ScheduledNow nowSched = new ScheduledNow(DomainModelConstant.NullId, DomainModelConstant.NullId, string.Empty, EventCode.GetCachedCode(EventCode.Calibration), null, null, true);
            CreateMasterForTest();
            // act
            scheduler.ForceEvent(EventCode.Calibration, false);
            nextAction = scheduler.GetNextAction(dsEvent);

            // assert
            Xunit.Assert.True(nextAction is InstrumentCalibrationAction);
        }
        /// <summary>
        /// Reports a docking station event to the server.
        /// </summary>
        /// <param name="dockingStationEvent">
        /// The event to be reported
        /// </param>
        /// <returns>
        /// A docking station action indicating the next task
        /// the docking station should perform.
        /// </returns>
        public DockingStationAction ReportEvent(DockingStationEvent dsEvent)
        {
            if (dsEvent == null)
            {
                return(null);
            }

            if (dsEvent.DockingStation.SerialNumber == string.Empty)
            {
                return(null);
            }

            LogEventDetails(dsEvent);

            DockingStationAction dsAction = null;

            // We don't yet instantiate the Uploader instance.  We wait until we know for sure
            // we're going to use it. Note that it's Disposed of in the finally block below.
            InetUploader inetUploader = null;

            try
            {
                try
                {
                    // It's now finally safe to log the event.

                    _eventProcessor.Save(dsEvent, Master.Instance.SwitchService.DockedTime);

                    // These upload calls won't actually try and upload if we're not associated with any account.
                    // or even if we DO have an account number, it won't upload if we're not activated on iNet.
                    // Yet it WILL upload if we're in Service mode, regardless if activated or not.
                    // Confusing, eh?
                    inetUploader = new InetUploader();
                    inetUploader.UploadEvent(dsEvent, Configuration.DockingStation.TimeZoneInfo);

                    if (dsEvent is InstrumentGasResponseEvent)
                    {
                        // Print automated bumps and cals
                        new PrintManager().Print((InstrumentGasResponseEvent)dsEvent);
                    }

                    // Only save event to USB drive when in Cal Station mode and not Service mode
                    if (!Configuration.Schema.Activated && !Configuration.ServiceMode)
                    {
                        if (dsEvent is InstrumentDatalogDownloadEvent)
                        {
                            // if the full datalog can not be saved to the USB drive an exception will
                            // be thrown to make the docking station go unavailable; this is to prevent
                            // the DS from erasing the datalog when it wasn't able to save it
                            new CsvFileManager().Save((InstrumentDatalogDownloadEvent)dsEvent);
                        }
                        else if (dsEvent is InstrumentGasResponseEvent)
                        {
                            // only bumps and cals are saved
                            new CsvFileManager().Save((InstrumentGasResponseEvent)dsEvent);
                        }
                    }

                    ReportQueuedErrors(inetUploader);

                    // See if docking station needs to take any special action for any of the event's errors.
                    dsAction = ExamineErrors(dsEvent, inetUploader);

                    if (dsAction != null)
                    {
                        Log.Debug(string.Format("{0}: ExamineErrors returned {1}", Name, dsAction.Name));
                        return(dsAction);
                    }
                }
                catch (Exception e)
                {
                    Log.Error(Name, e);

                    dsAction = new UnavailableAction(e);
                    // DO NOT report the error.  If we have an error uploading, then it makes
                    // no sense to try and upload and error notifying of a problem trying to upload.
                    //ProcessNotificationAction( dsAction, inet );

                    return(dsAction);
                }

                try
                {
                    // Determine if the event that just transpired requires a followed up RebootAction.
                    dsAction = CheckRebootableEvent(dsEvent);

                    if (dsAction == null)
                    {
                        // Before determining our next action, make sure we have the most up-to-date
                        // schedules and eventjournals, etc., from iNet.
                        ExchangeInetStatus(dsEvent);

                        // Find out what we're supposed to do next.
                        dsAction = Master.Scheduler.GetNextAction(dsEvent);

                        if (dsAction is InstrumentAction)
                        {
                            InstrumentAction instAction = (InstrumentAction)dsAction;

                            if (instAction is InstrumentGasAction)
                            {
                                // Get the resources from the resource manager.
                                StringBuilder explanation     = new StringBuilder();
                                List <string> consoleMessages = new List <string>(); // SGF  20-Feb-2013  INS-3821
                                List <string> errorCodes      = new List <string>(); // SGF  20-Feb-2013  INS-3821

                                InstrumentGasAction gasAction = instAction as InstrumentGasAction;

                                string eventCode = null;
                                if (gasAction is InstrumentBumpTestAction)
                                {
                                    eventCode = EventCode.BumpTest;
                                }
                                else if (gasAction is InstrumentCalibrationAction)
                                {
                                    eventCode = EventCode.Calibration;
                                }
                                else
                                {
                                    throw new ArgumentOutOfRangeException("Unrecognized GasAction: " + gasAction.GetType().ToString());
                                }

                                // SGF  20-Feb-2013  INS-3821
                                // SGF  03-Nov-2010  Single Sensor Cal and Bump
                                gasAction.GasEndPoints = Master.Instance.ResourceService.GetGasEndPoints(eventCode, gasAction, explanation, consoleMessages, errorCodes);

                                if (gasAction.GasEndPoints.Count == 0)
                                {
                                    Log.Warning(string.Format("No gases for {0}. {1}", eventCode, explanation.ToString()));
                                    // Maintain the empty cylinder error state resulting from forced actions by re-forcing the action
                                    Master.Instance.Scheduler.ReForceEvent(instAction);

                                    dsAction = new ResourceUnavailableAction(errorCodes, consoleMessages); // SGF  20-Feb-2013  INS-3821
                                }
                            }

                            // For instrument firmware upgrades, we don't want to allow the upgrade to take place
                            // if there's no gas to both calibrate and bump the instrument.  This is because at the
                            // end of the upgrade, the VDS will automatically calibrate then bump test the instrument.
                            if (instAction is InstrumentFirmwareUpgradeAction)
                            {
                                StringBuilder explanation     = new StringBuilder();
                                List <string> consoleMessages = new List <string>(); // SGF  20-Feb-2013  INS-3821
                                List <string> errorCodes      = new List <string>(); // SGF  20-Feb-2013  INS-3821

                                // SGF  20-Feb-2013  INS-3821
                                // SGF  03-Nov-2010  Single Sensor Cal and Bump
                                if (Master.Instance.ResourceService.GetGasEndPoints(EventCode.Calibration, instAction, explanation, consoleMessages, errorCodes).Count == 0)
                                {
                                    Log.Warning(string.Format("No gases for firmware upgrade {0}. {1}", EventCode.Calibration, explanation.ToString()));

                                    dsAction = new ResourceUnavailableAction(errorCodes, consoleMessages);   // SGF  20-Feb-2013  INS-3821
                                }
                                else
                                {
                                    explanation = new StringBuilder();
                                    consoleMessages.Clear(); // SGF  20-Feb-2013  INS-3821
                                    errorCodes.Clear();      // SGF  20-Feb-2013  INS-3821

                                    // SGF  20-Feb-2013  INS-3821
                                    // SGF  03-Nov-2010  Single Sensor Cal and Bump
                                    if (Master.Instance.ResourceService.GetGasEndPoints(EventCode.BumpTest, instAction, explanation, consoleMessages, errorCodes).Count == 0)
                                    {
                                        Log.Warning(string.Format("No gases for firmware upgrade {0}. {1}", EventCode.BumpTest, explanation.ToString()));

                                        dsAction = new ResourceUnavailableAction(errorCodes, consoleMessages);   // SGF  20-Feb-2013  INS-3821
                                    }
                                }
                            }
                        }
                    }
                }
                // INS-8228 RHP v7.6 Log and report InstrumentSystemAlarmException thrown from Scheduler
                catch (InstrumentSystemAlarmException e)
                {
                    Log.Error(Name, e);
                    Master.ConsoleService.UpdateState(ConsoleState.InstrumentSystemAlarm);
                    Master.ExecuterService.ReportExceptionError(e);
                }
                catch (Exception e)
                {
                    Log.Error(Name, e);
                    dsAction = new UnavailableAction(e);
                }


                // If the scheduler says there's currently nothing to do, then check
                // if we have an illegal cylinder or not.  Report an unsupported cylinder if so.
                if (dsAction is NothingAction)
                {
                    DockingStationAction cylinderAction = ExamineGasEndPoints();

                    if (cylinderAction != null)
                    {
                        dsAction = cylinderAction;
                    }
                }

                // If the action we're about to return is telling the VDS to display an error message,
                // then we should tell iNet the error too. We pass in our Uploader instance to re-use the
                // socket which should give a couple seconds performance benefit.
                ProcessNotificationAction(dsAction, inetUploader);
            }
            finally
            {
                if (inetUploader != null)
                {
                    inetUploader.Dispose();
                }
            }

            return(dsAction);
        }
        /// <summary>
        /// For certain 'actions' that the VDS decides to do, iNet needs to be
        /// notified of.  e.g. failed Leak check, Unavailable Gas, etc.
        /// </summary>
        /// <param name="dsAction"></param>
        /// <param name="inetUploader">May be null.
        /// If null is passed, the method will instantiate an Inet object to use.</param>
        private void ProcessNotificationAction(DockingStationAction dsAction, InetUploader inetUploader)
        {
            // _lastNotificationError is the last CONSECUTIVE NotificationAction.
            // This the passed-in action is not a NotificationAction, then that
            // breaks the current series of consecutive NotificationActions.
            // So, we set it to null to denote that.
            if (!(dsAction is INotificationAction))
            {
                _lastNotificationError = null;
                return;
            }

            const string funcMsg = "ProcessNotificationAction: ";

            StringBuilder errMsg = new StringBuilder(dsAction.Name);

            foreach (string m in dsAction.Messages)
            {
                errMsg.AppendFormat("\r\n{0}", m);
            }

            if (dsAction is UnsupportedCylinderAction)
            {
                errMsg.AppendFormat("\r\non Port {0}", ((UnsupportedCylinderAction)dsAction).GasEndPoint.Position);
            }

            // If it's an UnavailableAction, then the content of the error should
            // be the Exception's error (if there is an Exception).
            if ((dsAction is UnavailableAction) && (((UnavailableAction)dsAction).Exception != null))
            {
                errMsg.AppendFormat("\r\n{0}", ((UnavailableAction)dsAction).Exception.ToString());
            }

            DockingStationError dsError;

            //Suresh 02-Feb-2012 INS-2392
            if (Master.SwitchService.Instrument == null)
            {
                dsError = new DockingStationError(errMsg.ToString());
            }
            else
            {
                dsError = new DockingStationError(errMsg.ToString(), Master.SwitchService.Instrument.SerialNumber);
            }

            // If this NotificationError's detail is the exact same as the last NotificationError's
            // detail, then we assume it's a duplicate.  We don't want to upload duplicates.
            if (_lastNotificationError != null && _lastNotificationError.Description == dsError.Description)
            {
                Log.Debug(string.Format("{0}Ignoring duplicate: {1}", funcMsg, dsAction.ToString()));
                return;
            }

            _lastNotificationError = dsError;

            // We upload the error immediately (don't just queue it to our "Errors" List).
            if (inetUploader != null)
            {
                Log.Debug(string.Format("{0}Uploading ", funcMsg, dsAction.Name));
                inetUploader.UploadError(dsError, Configuration.DockingStation.TimeZoneInfo);
            }
            else
            {
                // if an uploader wasn't passed in to us to be re-used, then we need to create our own local one.
                using (InetUploader localUploader = new InetUploader())
                {
                    Log.Debug(string.Format("{0}Uploading {1}", funcMsg, dsAction.Name));
                    localUploader.UploadError(dsError, Configuration.DockingStation.TimeZoneInfo);
                }
            }
        }
        internal List <GasEndPoint> GetGasEndPoints(string eventCode, DockingStationAction dsAction, StringBuilder explanation, List <string> explanationCodes, List <string> errorCodes)
        {
            Log.Debug(string.Format("{0}.GetGasEndPoints, {1}", Name, eventCode));
            //explanationCodes.Clear();
            //errorCodes.Clear(); // SGF  20-Feb-2013  INS-3821

            ISC.iNet.DS.DomainModel.Instrument dockedInstrument = Master.Instance.SwitchService.Instrument;
            DockingStation dockingStation = Configuration.DockingStation;

            List <GasEndPoint> gasEndPoints = new List <GasEndPoint>();

            foreach (InstalledComponent installedComponent in dockedInstrument.InstalledComponents)
            {
                if (!(installedComponent.Component is Sensor))
                {
                    continue;
                }

                Sensor sensor = (Sensor)installedComponent.Component;
                if (!sensor.Enabled)
                {
                    Log.Info(string.Format("{0}: Ignoring disabled sensor {1}", Name, sensor.Uid));
                    continue;
                }

                // SGF  21-May-2012  INS-3078 -- Comment out the following if statement
                //if (!GasOperationsSupported(sensor))
                //{
                //    Log.Debug( string.Format( "{0}.GasOperationsSupported returned False for sensor {1}. Ignoring sensor.", Name, sensor.SerialNumber ) );
                //    continue;
                //}

                if (sensor.CalibrationGas.Code.Length == 0)
                {
                    throw new ApplicationException("Sensor " + sensor.Uid + " has null calibration gas code.");
                }

                // SGF  03-Nov-2010  Single Sensor Cal and Bump
                if (dsAction is InstrumentGasAction)
                {
                    InstrumentGasAction gasAction = (InstrumentGasAction)dsAction;
                    if (gasAction.ComponentCodes.Count != 0 && !gasAction.ComponentCodes.Contains(sensor.Type.Code))
                    {
                        Log.Debug(string.Format("{0}: Component type {1} is not included in the defined list of components to test. Ignoring sensor.", Name, sensor.Type.Code));
                        continue;
                    }
                }

                Log.Debug(string.Format("{0}: Looking for sensor {1}'s cal gas ({2})", Name, sensor.Uid, sensor.CalibrationGas.Code));

                _empty     = _expired = _gasFound = _freshFound = _zeroFound = false;
                _gasNeeded = true;  // SGF  21-May-2012  INS-3078

                // INS-8630 RHP v7.5 clear the messages for every installed component to avoid confusion
                explanationCodes.Clear();
                errorCodes.Clear(); // SGF  20-Feb-2013  INS-3821

                // Loop thru the cylinders for the docking station and if the cylinder contains the gas that
                // the sensor needs, add that cylinder as a gas end point in the docking station action.
                FindInstalledCylinderGases(eventCode, gasEndPoints, dockingStation, installedComponent, explanation, explanationCodes, errorCodes);

                if (!_freshFound && !_zeroFound)
                {
                    // Present which type of air should be, but is not, available.  If the port1 restrictions
                    // only allow for zero air, present 'ZERO AIR'; otherwise, present 'FRESH AIR'.
                    if (Configuration.DockingStation.Port1Restrictions == PortRestrictions.ZeroAir)
                    {
                        explanationCodes.Add("ZEROAIR");
                        errorCodes.Add(string.Format("{0} ({1})", "ZEROAIR", GasCode.O2));     // SGF  20-Feb-2013  INS-3821
                    }
                    else if (Configuration.DockingStation.Port1Restrictions == PortRestrictions.FreshAir)
                    {
                        GasType gasType = GasType.Cache[GasCode.FreshAir];
                        if (gasType != null)
                        {
                            explanationCodes.Add(gasType.Symbol);
                            errorCodes.Add(string.Format("{0} ({1})", gasType.Symbol, gasType.Code));     // SGF  20-Feb-2013  INS-3821
                        }
                    }

                    else // SGF  19-Jan-2012  INS-1913 & INS-1914
                    {
                        // either fresh air or zero air is allowed; present which type is connected, if something is connected.
                        GasEndPoint gasEndPoint = dockingStation.GasEndPoints[0];
                        Cylinder    cyl         = gasEndPoint.Cylinder;
                        if (cyl.IsZeroAir)
                        {
                            explanationCodes.Add("ZEROAIR");
                            errorCodes.Add(string.Format("{0} ({1})", "ZEROAIR", GasCode.O2));     // SGF  20-Feb-2013  INS-3821
                        }
                        else //suresh 14-Mar-2012 INS-4427 (DEV)
                        {
                            // If port 1 cylinder is not Zero Air then we report that 'Fresh air' is unavailable
                            GasType gasType = GasType.Cache[GasCode.FreshAir];
                            if (gasType != null)
                            {
                                explanationCodes.Add(gasType.Symbol);
                                errorCodes.Add(string.Format("{0} ({1})", gasType.Symbol, gasType.Code));     // SGF  20-Feb-2013  INS-3821
                            }
                        }
                    }

                    if (_expired)
                    {
                        explanationCodes.Add("Expired");
                        errorCodes.Add("Expired");  // INS-8630 RHP v7.5 - Notify iNet on the expired state
                    }
                    else if (_empty)
                    {
                        explanationCodes.Add(PressureLevel.Empty.ToString());
                        errorCodes.Add(PressureLevel.Empty.ToString());     // INS-8630 RHP v7.5 - Notify iNet on the empty state
                    }
                    explanation.Append("Fresh air not found for sensor " + sensor.Uid + '\n');

                    Log.Debug(string.Format("{0}: Returning nothing: gasFound={1}, freshFound={2}, expired={3}, empty={4}", Name, _gasFound, _freshFound, _expired, _empty));
                    return(new List <GasEndPoint>());
                }

                if (_gasNeeded && !_gasFound)    // SGF  21-May-2012  INS-3078 -- add the '_gasNeeded' clause to the if-condition
                {
                    // If gas not found, IDS needs the symbol for that gas for display on its LCD.
                    // Look it up in our cache.  For Fresh Air, we just return the gas code;
                    // The IDS knows to look for that as a special case.
                    if (sensor.CalibrationGas.Code == GasCode.FreshAir)
                    {
                        GasType gasType = GasType.Cache[GasCode.FreshAir];
                        if (gasType != null)
                        {
                            explanationCodes.Add(gasType.Symbol);
                            errorCodes.Add(string.Format("{0} ({1})", gasType.Symbol, gasType.Code));     // SGF  20-Feb-2013  INS-3821
                        }
                    }
                    // DSW-1758 RHP v9.6.1 - Added (! (_expired || _empty) ) since gas symbol has already been added to explanationCodes for Empty/Expired states.
                    else if (!(_expired || _empty))
                    {
                        // If we're doing a bump test, and this is a combustible sensor either in LEL or PPM mode,
                        // and docking station has a CombustibleBumpTestGas setting, then make sure we report that the
                        // gas type not found is the CombustibleBumpTestGas and not the sensor cal gas.
                        string sensorGasCode = sensor.CalibrationGas.Code;
                        if ((eventCode == EventCode.BumpTest) &&
                            (sensor.Type.Code == SensorCode.CombustibleLEL || sensor.Type.Code == SensorCode.CombustiblePPM) &&
                            (Configuration.DockingStation.CombustibleBumpTestGas.Length > 0))
                        {
                            sensorGasCode = Configuration.DockingStation.CombustibleBumpTestGas;
                        }
                        GasType gasType = GasType.Cache[sensorGasCode];
                        if (gasType != null)
                        {
                            explanationCodes.Add(gasType.Symbol);
                            errorCodes.Add(string.Format("{0} ({1})", gasType.Symbol, gasType.Code));     // SGF  20-Feb-2013  INS-3821
                        }
                    }

                    if (_expired)
                    {
                        explanationCodes.Add("Expired");
                        errorCodes.Add("Expired");  // INS-8630 RHP v7.5 - Notify iNet on the expired state
                    }
                    else if (_empty)
                    {
                        explanationCodes.Add(PressureLevel.Empty.ToString());
                        errorCodes.Add(PressureLevel.Empty.ToString());     // INS-8630 RHP v7.5 - Notify iNet on the empty state
                    }

                    explanation.Append("Could not find cylinder needed for sensor " + sensor.Uid + ", CalGasCode=\"" + sensor.CalibrationGas.Code + "\" (");
                    for (int i = 0; i < explanationCodes.Count; i++)
                    {
                        if (i > 0)
                        {
                            explanation.Append(" ");
                        }
                        explanation.Append(explanationCodes[i]);
                    }
                    explanation.Append(")\n");

                    Log.Debug(string.Format("{0}: Returning nothing: gasFound={1}, freshFound={2}, expired={3}, empty={4}", Name, _gasFound, _freshFound, _expired, _empty));
                    return(new List <GasEndPoint>());
                }

                // Zero air is required for CO2 sensors; Only zero air is used to zero CO2, never fresh air.
                if ((sensor.CalibrationGas.Code == GasCode.CO2) && !_zeroFound)
                {
                    GasType gasType = GasType.Cache[GasCode.O2];
                    if (gasType != null)
                    {
                        explanationCodes.Add("ZEROAIR");                                   // SGF  5-Feb-2013  INS-3837
                        errorCodes.Add(string.Format("{0} ({1})", "ZEROAIR", GasCode.O2)); // SGF  20-Feb-2013  INS-3821
                    }
                    if (_expired)
                    {
                        explanationCodes.Add("Expired");
                    }
                    else if (_empty)
                    {
                        explanationCodes.Add(PressureLevel.Empty.ToString());
                    }
                    explanation.Append("Zero air not found for CO2 sensor " + sensor.Uid + '\n');
                    Log.Debug(string.Format("{0}: Returning nothing: gasFound={1}, freshFound={2}, expired={3}, empty={4}", Name, _gasFound, _freshFound, _expired, _empty));
                    return(new List <GasEndPoint>());;
                }
            }

            Log.Debug(string.Format("{0}.GetGasEndPoints returned {1} gas end points", Name, gasEndPoints.Count));
            return(gasEndPoints);
        }