using DTS.Common.Base; using DTS.Common.Events; using DTS.Common.Interactivity; using DTS.Common.Interface; using DTS.Common.Interface.Sensors; using DTS.Common.Settings; using DTS.Common.Storage; using DTS.Common.Utilities.Logging; using DTS.SensorDB; using DTS.Viewer.ChartOptions.Model; using DTS.Viewer.TestModification.Model; using Prism.Commands; using Prism.Events; using Prism.Regions; using System; using System.ComponentModel; using System.Linq; using System.Threading.Tasks; using System.Windows; using Unity; // ReSharper disable CheckNamespace // ReSharper disable ConvertToAutoProperty // ReSharper disable InconsistentNaming // ReSharper disable UnusedAutoPropertyAccessor.Local // ReSharper disable NotAccessedField.Local // ReSharper disable RedundantDefaultMemberInitializer namespace DTS.Viewer.TestModification { public class TestModificationViewModel : BaseViewModel, ITestModificationViewModel { /// /// retrieves latest calibration from database (or null if not in database or an error occurs) /// private static ISensorCalDbRecord GetLatestCalibration(ISensorDbRecord sensor) { if ( null == sensor) { return null; } try { var records = GetCalibrationsDb(sensor.id, sensor.SerialNumber); if ( null == records || 0 == records.Length) { return null; } Array.Sort(records, CompareCalibrations); //calibrations should now be in ascending order so take the "last" one return records[records.Length - 1]; } catch (Exception) { //there's no access to APILogger here, so rather than adding a reference, just eat the error } return null; } private static ISensorCalDbRecord[] GetCalibrationsDb(int sensorId, string serialNumber) { _ = DbOperations.SensorCalibrationsGet(sensorId, serialNumber, out var records); return records; } /// /// compares two sensor calibration records /// private static int CompareCalibrations(ISensorCalDbRecord left, ISensorCalDbRecord right) { if (left == right) { return 0; } if (null == left) { return 1; } if (null == right) { return -1; } var res = left.CalibrationDate.CompareTo(right.CalibrationDate); if (res != 0) { return res; } return left.ModifyDate.CompareTo(right.ModifyDate); } /// /// returns sensor given serial number /// private static ISensorDbRecord GetSensor(ISensorDbRecord[] records) { if ( null == records || 0 == records.Length) { return null; } return records[0]; } /// /// updates calibration in db /// http://manuscript.dts.local/f/cases/43735/SW-NFR-DataPRO-Add-option-to-map-sensitivity-edit-in-Viewer-back-to-Sensor-Database /// public void UpdateDatabaseMethod() { try { var cal = Model.Cal; if (null == cal) { return; } cal.CalibrationId = -1; cal.ModifyDate = DateTime.Now; var sc = new SensorCalibration(cal); DbOperations.SensorCalibrationsInsert(sc, 0, true); Model.Cal = GetLatestCalibration(Model.Sensor); } catch (Exception ex) { _eventAggregator.GetEvent().Publish(new PageErrorArg(new[] { $"{Resources.StringResources.FailedToModifySensitivity} {ex.Message}" }, null)); } } public ITestModificationView View { get; set; } public IBaseViewModel Parent { get; set; } private IEventAggregator _eventAggregator { get; set; } private IUnityContainer _unityContainer { get; set; } public InteractionRequest NotificationRequest { get; private set; } public new InteractionRequest ConfirmationRequest { get; private set; } /// /// Creates a new instance of the TestModificationViewListModel. /// /// The TestModification View interface. /// The logical placeholder defined within the application's UI (in the shell or within views) into which views are displayed. /// The EventAggregator which allows different components to publish/subscribe to events without being coupled to each other. /// The unityContainer. public TestModificationViewModel(ITestModificationView view, IRegionManager regionManager, IEventAggregator eventAggregator, IUnityContainer unityContainer) : base(regionManager, eventAggregator, unityContainer) { Model = new TestModificationModel(); View = view; View.DataContext = this; NotificationRequest = new InteractionRequest(); ConfirmationRequest = new InteractionRequest(); _eventAggregator = eventAggregator; _unityContainer = unityContainer; _eventAggregator.GetEvent().Subscribe(OnRaiseNotification); _eventAggregator.GetEvent().Subscribe(OnGraphSelectedCountChanged); _eventAggregator.GetEvent().Subscribe(OnShiftT0Event); _eventAggregator.GetEvent().Subscribe(OnSetUseZeroForUnfiltered); } private void OnSetUseZeroForUnfiltered(bool useZeroForUnfiltered) { UseZeroForUnfiltered = useZeroForUnfiltered; } private void OnShiftT0Event(ShiftT0EventArguments args) { if (args.IsInitialization) { return; } if (args.IsKeyPress) { if (null == Model) { return; } //if we can't modify no reason to continue, short circuit out if (!TestModificationVisability) { return; } if (null == Model.SelectedChannel || null == Model.SelectedChannel.ParentModule) { return; } else { //go and modify the T0! //calculate a new T0 given the sample rate var t0 = Model.T0 + args.T0Steps * (1000D / Model.SelectedChannel.ParentModule.SampleRateHz); Model.T0 = t0; } _eventAggregator.GetEvent().Publish(Model); } else { Model.T0 = args.T0Time; } } #region Methods public override void Initialize() { } public override void Initialize(object parameter) { Parent = (IBaseViewModel)parameter; } /// /// Private Event handler for RaiseNotification event. /// private void OnRaiseNotification(NotificationContentEventArgs eventArgsWithTitle) { // Notification object expects a NotificationContentEventArgsWithoutTitle object and a Title string. var eventArgsWithoutTitle = new NotificationContentEventArgs(eventArgsWithTitle.Message, eventArgsWithTitle.MessageDetails, eventArgsWithTitle.Image); NotificationRequest.Raise(new Notification { Content = eventArgsWithoutTitle, Title = eventArgsWithTitle.Title }); } private static bool IsPopulating { get; set; } private void OnGraphSelectedCountChanged(GraphSelectedChannelsNotificationArg arg) { if (Parent != arg?.ParentVM) return; var channels = arg.SelectedChannels; var canModify = channels.Count == 1 && channels.Count(x => x.IsSelected) == 1; TestModificationVisability = canModify; if (canModify) { IsPopulating = true; Model.IsT0ModeTestOnly = SettingsDB.GetGlobalValueBool(Keys.ApplyShiftT0ModsTestOnly.ToString(), false); var viewModel = _unityContainer.TryResolve(); Model.EnableSensitivityControl = viewModel.DoesUserHaveEditPermission; Model.EnableLineFitControl = viewModel.DoesUserHaveEditPermission; Model.EnableDescriptionControl = viewModel.DoesUserHaveEditPermission; Model.EnableEUMultiplierControl = viewModel.DoesUserHaveEditPermission; Model.EnableEUOffsetControl = viewModel.DoesUserHaveEditPermission; Model.EnableFilterControl = viewModel.DoesUserHaveEditPermission; Model.IsT0Enabled = viewModel.DoesUserHaveEditPermission; Model.IsDataFlagEnabled = viewModel.DoesUserHaveEditPermission; Model.SelectedChannel = channels[0]; TestModelManipulation.PopulateFromChannel(Model); IsPopulating = false; IsBackedUp = TestModelManipulation.BackupExists(Model); _eventAggregator.GetEvent().Publish(true); DbOperations.SensorsGet(channels[0].SerialNumber, out var records); var sensor = GetSensor(records); if (null != sensor && 0 == sensor.SensorType) { //for now we only display analog sensor calibrations ... Model.Sensor = sensor; Model.Cal = GetLatestCalibration(Model.Sensor); } } else if (channels.Count == 0) { Model.SelectedChannel = null; } else { _eventAggregator.GetEvent().Publish(false); } } #endregion #region ContextRegion #endregion #region Commands private DelegateCommand _previewCommand; public DelegateCommand PreviewCommand => _previewCommand ?? (_previewCommand = new DelegateCommand(PreviewMethod)); private void PreviewMethod() { TestModelManipulation.PreviewLineFit(Model); } private DelegateCommand _writeCommand; public DelegateCommand WriteCommand => _writeCommand ?? (_writeCommand = new DelegateCommand(WriteMethod)); private void WriteMethod() { var window = Application.Current.MainWindow; if (null == window) { return; } //14661 Shifting T zero beyond post trigger seconds crashes application //don't allow T0 to shift beyond test data if (Model.IsModifiedT0 && !Model.ValidateT0()) { _eventAggregator.GetEvent() .Publish(new PageErrorArg(new[] { Resources.StringResources.T0MustBeInDataset }, null)); return; } var dialogResult = MessageBox.Show(window, Resources.StringResources.WriteFilesPrompt, "", MessageBoxButton.YesNo); try { UseISOCodeFilterMapping = SettingsDB.GetGlobalValueBool("UseISOCodeFilterMapping", true); } catch (Exception ex) { APILogger.Log(ex); } APILogger.Log(Resources.StringResources.WriteFilesPrompt, $"User pressed {dialogResult.ToString()}"); if (dialogResult == MessageBoxResult.Yes) { TestModelManipulation.SaveModification(Model, UseISOCodeFilterMapping, UseZeroForUnfiltered); IsBackedUp = TestModelManipulation.BackupExists(Model); } } private DelegateCommand _undoCommand; public DelegateCommand UndoCommand => _undoCommand ?? (_undoCommand = new DelegateCommand(UndoMethod)); private void UndoMethod() { var window = Application.Current.MainWindow; if (null == window) { return; } var dialogResult = MessageBox.Show(window, Resources.StringResources.UndoPrompt, "", MessageBoxButton.YesNo); APILogger.Log(Resources.StringResources.UndoPrompt, $"User pressed {dialogResult.ToString()}"); if (dialogResult == MessageBoxResult.Yes) { TestModelManipulation.UndoModification(Model); } } private DelegateCommand _undoAllCommand; public DelegateCommand UndoAllCommand => _undoAllCommand ?? (_undoAllCommand = new DelegateCommand(UndoAllMethod)); private void UndoAllMethod() { var window = Application.Current.MainWindow; if (null == window) { return; } var dialogResult = MessageBox.Show(window, Resources.StringResources.UndoAllPrompt, "", MessageBoxButton.YesNo); APILogger.Log(Resources.StringResources.UndoAllPrompt, $"User pressed {dialogResult.ToString()}"); if (dialogResult == MessageBoxResult.Yes) { TestModelManipulation.UndoAllModification(Model); IsBackedUp = TestModelManipulation.BackupExists(Model); } } public void PublishChanges() { if (!IsPopulating && Model.IsModifiedDataFlag) { //Write this immediately TestModelManipulation.SaveModificationDataFlag(Model); IsBackedUp = TestModelManipulation.BackupExists(Model); } _eventAggregator?.GetEvent().Publish(Model); } #endregion Commands #region Properties /// /// when true forces the ISOCode field filter SoftwareFilter to always match the SoftwareFilter of the channel /// Whenever the softwarefilter for a graph channel is modified it will check this value before /// modifying the channel isocode /// public bool UseISOCodeFilterMapping { get; set; } = false; private TestModificationModel _model = null; // new TestModificationModel(); public new TestModificationModel Model { get => _model; set { if (_model != null) _model.Parent = null; _model = value; if (_model != null) _model.Parent = this; OnPropertyChanged("Model"); } } public bool UseZeroForUnfiltered { get; set; } private bool _isFilterEnabled = false; public bool IsFilterEnabled { get => _isFilterEnabled; set { _isFilterEnabled = value; OnPropertyChanged("IsFilterEnabled"); } } private bool _testModificationVisability = false; public bool TestModificationVisability { get => _testModificationVisability; set { _testModificationVisability = value; OnPropertyChanged("TestModificationVisability"); } } /// ///Occurs when a property value changes. /// public new event PropertyChangedEventHandler PropertyChanged; private new void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } /// /// Gets the HeaderInfo. /// public string HeaderInfo => "TestSummaryRegion"; private bool _isBusy = false; public new bool IsBusy { get => _isBusy; set { _isBusy = value; OnPropertyChanged("IsBusy"); } } private bool _isDirty; public new bool IsDirty { get => _isDirty; set => _isDirty = value; } private bool _isNavigationIncluded; public new bool IsNavigationIncluded { get => _isNavigationIncluded; set => _isNavigationIncluded = value; } private bool _isBackedUp; public bool IsBackedUp { get => _isBackedUp; private set { _isBackedUp = value; OnPropertyChanged("IsBackedUp"); } } #endregion } }