using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Input; using DTS.Common; using DTS.Common.Base; using DTS.Common.Classes.Viewer.Commands; using DTS.Common.DAS.Concepts; using DTS.Common.Enums.Sensors; using DTS.Common.Events; using DTS.Common.Interactivity; using DTS.Common.Interface; using DTS.Common.Utilities.Logging; using DTS.Common.Utils; using DTS.Slice.Control; using DTS.Viewer.AddCalculatedChannel.Model; using Prism.Events; using Prism.Regions; using Unity; using Test = DTS.Serialization.Test; // ReSharper disable once CheckNamespace namespace DTS.Viewer.AddCalculatedChannel { public class AddCalculatedChannelViewModel : BaseViewModel, IAddCalculatedChannelViewModel { #region enums private enum Tags { ChannelName, ChannelDescription, IsoCode, SelectedCalculation, SourceChannel, ChannelList, ChannelListObjects, SingleChannelSelectorVisibility, MultipleChannelSelectorVisibility, ThreeDIRTRACCVisibility, IRTraccChannelList, IRTraccChannel, Pot1ChannelList, Pot1Channel, Pot2ChannelList, Pot2Channel } public enum Calculation { [Description("Integral")] Integral = 0, [Description("Double Integral")] DoubleIntegral = 1, [Description("Derivative")] Derivative = 2, [Description("Sin")] Sin = 3, [Description("Cos")] Cos = 4, [Description("3D IR-Tracc")] ThreeDIRTracc = 5, [Description("SUM")] SUM = 6, [Description("Average")] AVE = 7, [Description("3D IR-TRACC Abdomen")] ThreeDIRTraccAbdomen = 8, [Description("3D IR-TRACC Lower Thorax")] ThreeDIRTraccLowerThorax = 9, [Description("Resultant")] Resultant = 10, [Description("HIC")] HIC = 11 } #endregion public IBaseView View { get; set; } public IBaseViewModel Parent { get; set; } public object ContextSearchRegion { 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 AddCalculatedChannelViewModel. /// /// The AddCalculatedChannelView 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 AddCalculatedChannelViewModel(IAddCalculatedChannelView view, IRegionManager regionManager, IEventAggregator eventAggregator, IUnityContainer unityContainer) : base(regionManager, eventAggregator, unityContainer) { View = view; View.DataContext = this; NotificationRequest = new InteractionRequest(); ConfirmationRequest = new InteractionRequest(); _eventAggregator = eventAggregator; UnityContainer = unityContainer; AddCalculatedChannelCommand = new RelayCommand(AddCalculatedChannel); } #region Methods public void PublishChanges() { //throw new NotImplementedException(); } public override void Initialize() { Initialize(null); } public override void Initialize(object parameter) { Parent = (IBaseViewModel)parameter; Subscribe(); } /// /// Subscribe for events /// private void Subscribe() { _eventAggregator.GetEvent().Subscribe(OnRaiseNotification); _eventAggregator.GetEvent().Subscribe(OnTestSummaryChanged); } /// /// 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 }); } /// /// Read all graphs, calculated channels and channels for the selected test /// and select and display first group or channel /// /// private void OnTestSummaryChanged(TestSummaryChangeNotificationArg arg) { if (Parent != arg?.ParentVM) return; var list = arg.SummaryList; var inputChannels = new List(); var inputChannelObjects = new List(); if (list?.Count > 0) { foreach (var ts in list) { if (ts.Channels.Any() && ts.Channels.FirstOrDefault() == null) { // LOAD NOW! Utils.SetChannelInfo(ts.TestMetadata, Path.GetDirectoryName(ts.TestMetadata.TestRun.FilePath), DTS.Serialization.SliceRaw.File.PersistentChannel.GetIsoCode); ts.Channels = ts.TestMetadata.TestRun.Channels; ts.Graphs = ts.TestMetadata.TestSetup.TestGraphs; ts.CalculatedChannels = ts.TestMetadata.TestRun.CalculatedChannels; } if (ts.Channels?.Count > 0) { foreach (var c in ts.Channels.Where(ch => null != ch)) { if (inputChannels.TrueForAll(ch => ch.ChannelId != c.ChannelId)) { inputChannels.Add(c); } } } } inputChannels.Sort(new Comparison(CompareDisplayOrders)); } foreach (var channel in inputChannels) { inputChannelObjects.Add(new ChannelHelper(channel)); } ChannelList = new ObservableCollection(inputChannels); ChannelListObjects = new ObservableCollection(inputChannelObjects); _HICAccelerationX = null; OnPropertyChanged("HICAccelerationX"); _HICAccelerationY = null; OnPropertyChanged("HICAccelerationY"); _HICAccelerationZ = null; OnPropertyChanged("HICAccelerationZ"); _availableHICChannels = new List(); foreach (var clo in ChannelListObjects) { var units = clo.MyChannel.Eu.ToLower().Trim(); if (Constants.ACCELERATION_UNITS.Contains(units)) { _availableHICChannels.Add(clo); } } OnPropertyChanged("AvailableHICChannels"); bool serializedStringIsValid(string str) { var lf = new LinearizationFormula(); lf.FromSerializeString(str); return lf.IsValid(); } //itracc IRTraccChannelList = new ObservableCollection(inputChannels.Where(ch => ch.ChannelType == typeof(Test.Module.AnalogInputChannel).ToString() && serializedStringIsValid(ch.LinearizationFormula) && ch.ZeroMethod == ZeroMethodType.None.ToString() && ch.ZeroPoint != 0 && ch.FactoryExcitationVoltage != 0).Select(ch => new ChannelHelper(ch)).ToList()); //pot1 Pot1ChannelList = new ObservableCollection(inputChannels.Where(ch => ch.ChannelType == typeof(Test.Module.AnalogInputChannel).ToString() && (ch.Eu.ToLower().Trim() == "deg" || ch.Eu.ToLower().Trim() == "deg-ang") && ch.ZeroMethod == ZeroMethodType.None.ToString() && ch.FactoryExcitationVoltage != 0).Select(ch => new ChannelHelper(ch)).ToList()); //pot2 Pot2ChannelList = new ObservableCollection(inputChannels.Where(ch => ch.ChannelType == typeof(Test.Module.AnalogInputChannel).ToString() && (ch.Eu.ToLower().Trim() == "deg" || ch.Eu.ToLower().Trim() == "deg-ang") && ch.ZeroMethod == ZeroMethodType.None.ToString() && ch.FactoryExcitationVoltage != 0).Select(ch => new ChannelHelper(ch)).ToList()); } public override void Activated() { SourceChannel = ChannelList.Any() ? ChannelList[0] : null; IsoCode = "NONE"; SelectedCalculation = CalculationList[0]; ChannelName = "New Channel"; _HICAccelerationX = null; OnPropertyChanged("HICAccelerationX"); _HICAccelerationY = null; OnPropertyChanged("HICAccelerationY"); _HICAccelerationZ = null; OnPropertyChanged("HICAccelerationZ"); _HICLength = 16; OnPropertyChanged("HICLength"); } public override void Cleanup() { } #endregion #region command(s) public ICommand AddCalculatedChannelCommand { get; private set; } private void AddCalculatedChannel(object obj) { var errors = new List(); var warnings = new List(); var valid = Validate(ref errors, ref warnings, false); if (errors.Any() || warnings.Any()) { var toDisplay = new List(errors.ToArray()); toDisplay.AddRange(warnings.ToArray()); _eventAggregator.GetEvent().Publish(new PageErrorArg(toDisplay.ToArray(), null)); } if (!valid) { return; } var error = string.Empty; try { if (null == SelectedCalculation) { throw new Exception("No Calculation"); } var inputChannels = new List(); var orderedChannels = new List(); var testId = string.Empty; var channelPath = string.Empty; switch (SelectedCalculation.MyCalculation) { case Calculation.AVE: case Calculation.SUM: case Calculation.Resultant: testId = GetTestIdFromBinaryFileName(ChannelListObjects.First(clo => clo.IsIncluded).MyChannel .BinaryFileName); channelPath = ChannelListObjects.First(clo => clo.IsIncluded).MyChannel.BinaryFilePath; break; case Calculation.HIC: testId = GetTestIdFromBinaryFileName(HICAccelerationX.MyChannel.BinaryFileName); channelPath = HICAccelerationX.MyChannel.BinaryFilePath; break; case Calculation.ThreeDIRTracc: case Calculation.ThreeDIRTraccAbdomen: case Calculation.ThreeDIRTraccLowerThorax: testId = GetTestIdFromBinaryFileName(IRTraccChannel.MyChannel.BinaryFileName); channelPath = IRTraccChannel.MyChannel.BinaryFilePath; break; default: testId = GetTestIdFromBinaryFileName(SourceChannel.BinaryFileName); channelPath = SourceChannel.BinaryFilePath; break; } var dtsFile = Path.Combine(channelPath, $"{testId}.dts"); Serialization.SliceRaw.File.ReadTestSetup(dtsFile, out var test, out var testSetup, false); new Event().FromDtsSerializationTest(test, null); //assigns emc objects to all test channels switch (SelectedCalculation.MyCalculation) { case Calculation.AVE: case Calculation.SUM: case Calculation.Resultant: inputChannels.AddRange((from ch in ChannelListObjects where ch.IsIncluded select GetTestModuleChannelFromChannelId(test.Modules, ch.MyChannel.ChannelId)).ToList()); break; case Calculation.HIC: inputChannels.Add(GetTestModuleChannelFromChannelId(test.Modules, HICAccelerationX.MyChannel.ChannelId)); inputChannels.Add(GetTestModuleChannelFromChannelId(test.Modules, HICAccelerationY.MyChannel.ChannelId)); inputChannels.Add(GetTestModuleChannelFromChannelId(test.Modules, HICAccelerationZ.MyChannel.ChannelId)); break; case Calculation.ThreeDIRTracc: case Calculation.ThreeDIRTraccAbdomen: case Calculation.ThreeDIRTraccLowerThorax: inputChannels.AddRange(new[] { GetTestModuleChannelFromChannelId(test.Modules, IRTraccChannel.MyChannel.ChannelId), GetTestModuleChannelFromChannelId(test.Modules, Pot1Channel.MyChannel.ChannelId), GetTestModuleChannelFromChannelId(test.Modules, Pot2Channel.MyChannel.ChannelId) }); break; default: inputChannels.Add(GetTestModuleChannelFromChannelId(test.Modules, SourceChannel.ChannelId)); break; } foreach (var m in test.Modules) { orderedChannels.AddRange(m.Channels); orderedChannels.AddRange(m.CalculatedChannels); } orderedChannels.Sort(new Comparison(CompareDisplayOrders)); var maxDisplayOrder = 0; try { maxDisplayOrder = (from ch in orderedChannels select ch.AbsoluteDisplayOrder) .Max(); } catch (Exception ex) { APILogger.Log(ex); } var ccs = CalculatedChannelCreator.CreateChannels(testId, channelPath, SelectedCalculation.MyCalculation, inputChannels, ChannelName, maxDisplayOrder + 1, orderedChannels, HICLength, out var errorList, DefaultDTSEncoding); if (ccs == null) { if (errorList?.Count > 0) { throw new Exception(string.Join(Environment.NewLine, errorList)); } else { throw new Exception("Could not create Calculated Channel(s)"); } } foreach (var cc in ccs) { if (null != cc) { //Channel is created. Hook up to Test structure. if (AddCalculatedChannelToTest(cc)) { //Save Test try { //Back up dts file only if a backup file does not exist. This should guarantee that the //original file is the only one that is preserved. var dtsFilePath = Path.Combine(channelPath, testId + ".dts"); var dtsBackupFilePath = dtsFilePath + DTS.Common.Constants.BACKUP_FILE_EXTENSION; var backupExisted = System.IO.File.Exists(dtsBackupFilePath); if (!backupExisted && System.IO.File.Exists(dtsFilePath)) { System.IO.File.Move(dtsFilePath, dtsBackupFilePath); } //Spit out portion var f = new Serialization.SliceRaw.File { DefaultEncoding = DefaultDTSEncoding }; //Write the SLICEWare-compatible info so that SLICEWare can display the data if desired. //UTF-16 f.Exporter.Write(channelPath, testId, test, false, IncludeGroupNameInISOExport, Common.Constants.UNUSED_START_TIME, Common.Constants.UNUSED_DATA_COLLECTION_LENGTH); //Append the DataPRO info to the end of the existing .dts file which already contains SLICEWare-compatible info using (var writer = new StringWriter()) { new System.Xml.Serialization.XmlSerializer(typeof(DTS.Serialization.TestSetup)) .Serialize(writer, testSetup); Encoding encoder; try { encoder = Encoding.GetEncoding(DefaultDTSEncoding); } catch (Exception ex) { APILogger.Log("Problem getting encoder", ex); encoder = Encoding.Default; } using (var fileWriter = new StreamWriter(dtsFilePath, true, encoder)) { fileWriter.Write(fileWriter.NewLine + writer); //FB9374: successful save without error. if we created a backup for this save, remove it if (!backupExisted) System.IO.File.Delete(dtsBackupFilePath); } System.Threading.Thread.Sleep(10); } _eventAggregator?.GetEvent().Publish(dtsFilePath); } catch (Exception) { error = "Error creating Test with Calculated Channel"; } } } } } catch (Exception ex) { error = ex.Message; } finally { //(App.Current as App).SetAppAvailable(); } if (!string.IsNullOrEmpty(error)) { _eventAggregator.GetEvent().Publish(new NotificationContentEventArgs(error)); } } private bool AddCalculatedChannelToTest(Test.Module.CalculatedChannel cchannel) { try { //Remove any duplicates in the list foreach (var c in cchannel.ParentModule.CalculatedChannels) { if (cchannel.ChannelId.Equals(c.ChannelId)) { APILogger.Log("Overwriting existing calculated channel " + c); cchannel.ParentModule.CalculatedChannels.Remove(c); break; } } //Calculated Channels are stored in module. Save test to commit. cchannel.ParentModule.CalculatedChannels.Add(cchannel); return true; } catch (Exception ex) { APILogger.LogException(ex); } return false; } #endregion #region ContextRegion #endregion #region Properties /// ///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 => "AddCalculatedChannelRegion"; public new bool IsBusy { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } public new bool IsDirty => throw new NotImplementedException(); public bool IsAddCalculatedChannelIncluded { get; set; } public bool IncludeGroupNameInISOExport { get; set; } public int DefaultDTSEncoding { get; set; } private string _channelName = string.Empty; public string ChannelName { get => _channelName; set { _channelName = value; OnPropertyChanged(Tags.ChannelName.ToString()); UpdateSaveButtonVisibility(); } } private string _channelDescription = string.Empty; public string ChannelDescription { get => _channelDescription; set { _channelDescription = value; OnPropertyChanged(Tags.ChannelDescription.ToString()); } } private string _isoCode = string.Empty; public string IsoCode { get => _isoCode; set { _isoCode = value; OnPropertyChanged(Tags.IsoCode.ToString()); UpdateSaveButtonVisibility(); } } private bool _singleChannelSelectorVisibility = false; public bool SingleChannelSelectorVisibility { get => _singleChannelSelectorVisibility; set { _singleChannelSelectorVisibility = value; OnPropertyChanged(Tags.SingleChannelSelectorVisibility.ToString()); } } private bool _hicChannelSelectorVisibility = false; /// /// whether HIC is visible or not /// public bool HICChannelSelectorVisibility { get => _hicChannelSelectorVisibility; set { _hicChannelSelectorVisibility = value; OnPropertyChanged("HICChannelSelectorVisibility"); } } private bool _multipleChannelSelectorVisibility = true; public bool MultipleChannelSelectorVisibility { get => _multipleChannelSelectorVisibility; set { _multipleChannelSelectorVisibility = value; OnPropertyChanged(Tags.MultipleChannelSelectorVisibility.ToString()); } } private bool _threeDIRTRACCVisibility = false; public bool ThreeDIRTRACCVisibility { get => _threeDIRTRACCVisibility; set { _threeDIRTRACCVisibility = value; OnPropertyChanged(Tags.ThreeDIRTRACCVisibility.ToString()); } } private CalculationHelper[] _calculations = null; public CalculationHelper[] CalculationList { get { if (null != _calculations) return _calculations; var enums = Enum.GetValues(typeof(Calculation)).Cast().ToArray(); _calculations = enums.Select(e => new CalculationHelper(e)).ToArray(); SelectedCalculation = _calculations[0]; return _calculations; } } private CalculationHelper _selectedCalculation; public CalculationHelper SelectedCalculation { get => _selectedCalculation; set { _selectedCalculation = value; OnPropertyChanged(Tags.SelectedCalculation.ToString()); switch (SelectedCalculation.MyCalculation) { case Calculation.Integral: case Calculation.DoubleIntegral: case Calculation.Derivative: case Calculation.Sin: case Calculation.Cos: SingleChannelSelectorVisibility = true; MultipleChannelSelectorVisibility = false; HICChannelSelectorVisibility = false; ThreeDIRTRACCVisibility = false; break; case Calculation.ThreeDIRTracc: case Calculation.ThreeDIRTraccAbdomen: case Calculation.ThreeDIRTraccLowerThorax: SingleChannelSelectorVisibility = false; MultipleChannelSelectorVisibility = false; HICChannelSelectorVisibility = false; ThreeDIRTRACCVisibility = true; break; case Calculation.SUM: case Calculation.AVE: case Calculation.Resultant: SingleChannelSelectorVisibility = false; MultipleChannelSelectorVisibility = true; HICChannelSelectorVisibility = false; ThreeDIRTRACCVisibility = false; break; case Calculation.HIC: SingleChannelSelectorVisibility = false; MultipleChannelSelectorVisibility = false; HICChannelSelectorVisibility = true; ThreeDIRTRACCVisibility = false; break; } if (ThreeDIRTRACCVisibility) { IRTraccChannel = IRTraccChannelList.Any() ? IRTraccChannelList[0] : null; Pot1Channel = Pot1ChannelList.Any() ? Pot1ChannelList[0] : null; Pot2Channel = Pot2ChannelList.Any() ? Pot2ChannelList[0] : null; } UpdateChannelDescription(); UpdateSaveButtonVisibility(); } } private void UpdateChannelDescription() { if (null != SelectedCalculation) { switch (SelectedCalculation.MyCalculation) { case Calculation.ThreeDIRTracc: case Calculation.ThreeDIRTraccAbdomen: case Calculation.ThreeDIRTraccLowerThorax: ChannelDescription = null != IRTraccChannel ? IRTraccChannel.ChannelName + " : " + SelectedCalculation.ToString().ToUpper() : ""; break; case Calculation.SUM: case Calculation.AVE: ChannelDescription = ""; if (ChannelListObjects.Any(clo => clo.IsIncluded)) { foreach (var clo in ChannelListObjects.Where(clo => clo.IsIncluded)) { if (!string.IsNullOrEmpty(ChannelDescription)) ChannelDescription += ", "; ChannelDescription += clo.MyChannel.ChannelDescriptionString; } ChannelDescription += " : " + SelectedCalculation.ToString().ToUpper(); } break; default: ChannelDescription = null != _sourceChannel ? _sourceChannel + " : " + SelectedCalculation.ToString().ToUpper() : ""; break; } } else { ChannelDescription = ""; } } private void UpdateSaveButtonVisibility() { if ((null != SelectedCalculation) && (false == string.IsNullOrEmpty(ChannelDescription))) { switch (SelectedCalculation.MyCalculation) { case Calculation.ThreeDIRTracc: case Calculation.ThreeDIRTraccAbdomen: case Calculation.ThreeDIRTraccLowerThorax: if (null == IRTraccChannel || null == Pot1Channel || null == Pot2Channel) { _eventAggregator.GetEvent().Publish(new SaveButtonUsability() { IsUsable = false }); } else { _eventAggregator.GetEvent().Publish(new SaveButtonUsability() { IsUsable = true }); } break; case Calculation.SUM: case Calculation.AVE: if (ChannelListObjects.All(clo => !clo.IsIncluded)) { _eventAggregator.GetEvent().Publish(new SaveButtonUsability() { IsUsable = false }); } else { _eventAggregator.GetEvent().Publish(new SaveButtonUsability() { IsUsable = true }); } break; case Calculation.HIC: if (null == HICAccelerationX || null == HICAccelerationY || null == HICAccelerationZ) { _eventAggregator.GetEvent().Publish(new SaveButtonUsability() { IsUsable = true }); } else { _eventAggregator.GetEvent().Publish(new SaveButtonUsability() { IsUsable = false }); } break; default: if ((null != SourceChannel) && (false == string.IsNullOrEmpty(ChannelName)) && (false == string.IsNullOrEmpty(IsoCode))) { _eventAggregator.GetEvent().Publish(new SaveButtonUsability() { IsUsable = true }); } break; } } else { _eventAggregator.GetEvent().Publish(new SaveButtonUsability() { IsUsable = false }); } } private ObservableCollection _channelList = new ObservableCollection(); public ObservableCollection ChannelList { get => _channelList; set { _channelList = value; OnPropertyChanged(Tags.ChannelList.ToString()); } } private List _availableHICChannels = new List(); /// /// all HIC possible channels (g,m/sec,m/sec^2 channels) /// public ChannelHelper[] AvailableHICChannels { get => _availableHICChannels.ToArray(); set { _availableHICChannels.Clear(); _availableHICChannels.AddRange(value); OnPropertyChanged("AvailableHICChannels"); } } private ChannelHelper _HICAccelerationX; /// /// currently selected head acceleration x /// public ChannelHelper HICAccelerationX { get => _HICAccelerationX; set { _HICAccelerationX = value; OnPropertyChanged("HICAccelerationX"); } } private ChannelHelper _HICAccelerationY; /// /// currently selected head acceleration y /// public ChannelHelper HICAccelerationY { get => _HICAccelerationY; set { _HICAccelerationY = value; OnPropertyChanged("HICAccelerationY"); } } private ChannelHelper _HICAccelerationZ; /// /// currently selected head acceleration z /// public ChannelHelper HICAccelerationZ { get => _HICAccelerationZ; set { _HICAccelerationZ = value; OnPropertyChanged("HICAccelerationZ"); } } private ITestChannel _sourceChannel; public ITestChannel SourceChannel { get => _sourceChannel; set { _sourceChannel = value; OnPropertyChanged(Tags.SourceChannel.ToString()); UpdateChannelDescription(); UpdateSaveButtonVisibility(); } } private ObservableCollection _channelListObjects = new ObservableCollection(); public ObservableCollection ChannelListObjects { get => _channelListObjects; set { foreach (var clo in _channelListObjects) { clo.PropertyChanged -= OnChannelListObjectPropertyChanged; } _channelListObjects = value; foreach (var clo in _channelListObjects) { clo.PropertyChanged += OnChannelListObjectPropertyChanged; } OnPropertyChanged(Tags.ChannelListObjects.ToString()); } } private void OnChannelListObjectPropertyChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs) { UpdateChannelDescription(); UpdateSaveButtonVisibility(); } private ObservableCollection _irTraccChannelList = new ObservableCollection(); public ObservableCollection IRTraccChannelList { get => _irTraccChannelList; set { _irTraccChannelList = value; OnPropertyChanged(Tags.IRTraccChannelList.ToString()); } } private ChannelHelper _irTraccChannel; public ChannelHelper IRTraccChannel { get => _irTraccChannel; set { _irTraccChannel = value; OnPropertyChanged(Tags.IRTraccChannel.ToString()); UpdateSaveButtonVisibility(); } } private ObservableCollection _pot1ChannelList = new ObservableCollection(); public ObservableCollection Pot1ChannelList { get => _pot1ChannelList; set { _pot1ChannelList = value; OnPropertyChanged(Tags.Pot1ChannelList.ToString()); } } private int _HICLength = 16; public int HICLength { get => _HICLength; set { _HICLength = value; OnPropertyChanged("HICLength"); } } private ChannelHelper _pot1Channel; public ChannelHelper Pot1Channel { get => _pot1Channel; set { _pot1Channel = value; OnPropertyChanged(Tags.Pot1Channel.ToString()); UpdateSaveButtonVisibility(); } } private ObservableCollection _pot2ChannelList = new ObservableCollection(); public ObservableCollection Pot2ChannelList { get => _pot2ChannelList; set { _pot2ChannelList = value; OnPropertyChanged(Tags.Pot2ChannelList.ToString()); } } private ChannelHelper _pot2Channel; public ChannelHelper Pot2Channel { get => _pot2Channel; set { _pot2Channel = value; OnPropertyChanged(Tags.Pot2Channel.ToString()); UpdateSaveButtonVisibility(); } } #endregion #region validate public bool Validate(ref List errors, ref List warnings, bool displayWindow) { var res = ValidateChannelName(); switch (SelectedCalculation.MyCalculation) { case Calculation.HIC: if (!ValidateHIC(ref errors, ref warnings)) { res = false; } break; case Calculation.Resultant: if (!ValidateResultant(ref errors, ref warnings)) { res = false; } break; } return res; } private bool ValidateHIC(ref List errors, ref List warnings) { //validate 3 channels if (null == HICAccelerationX || null == HICAccelerationY || null == HICAccelerationZ) { errors.Add(Resources.StringResources.HICRequires3Channels); return false; } return true; } private bool ValidateResultant(ref List errors, ref List warnings) { //validate same units across channel var included = from clo in ChannelListObjects where clo.IsIncluded select clo; if (!included.Any()) { errors.Add(Resources.StringResources.NoChannelsIncluded); return false; } string units = null; int sps = -1; foreach (var clo in included) { if (null == units) { units = clo.MyChannel.SensitivityUnits; sps = clo.MyChannel.SampleRateHz; } else { if (units != clo.MyChannel.SensitivityUnits) { errors.Add(Resources.StringResources.ResultantUnitsDontMatch); return false; } if (sps != clo.MyChannel.SampleRateHz) { errors.Add(Resources.StringResources.SampleRatesDontMatch); return false; } } } return true; } public bool ValidateChannelName() { if (!string.IsNullOrEmpty(ChannelName)) return true; return false; } #endregion #region helpers private static Test.Module.Channel GetTestModuleChannelFromChannelId(List modules, string channelID) { foreach (var m in modules.Where(x => x.Channels.Exists(ch => ch.ChannelId == channelID))) { return m.Channels.Find(ch => ch.ChannelId == channelID); } return null; } /// /// returns the test id from a binary filename /// it didn't seem the test id was available from any of the structures I had access to /// but it's the portion of the file name without all the decoration /// the filename is in the form of TestIdChxxx.yyy.chn /// /// /// private static string GetTestIdFromBinaryFileName(string filename) { var index = filename.IndexOf('.'); filename = filename.Substring(0, index); index = filename.LastIndexOf("Ch", StringComparison.Ordinal); //we expect the Ch, but if we don't find it, use the what portion we have return index >= 0 ? filename.Substring(0, index) : filename; } private static int CompareDisplayOrders(ITestChannel a, ITestChannel b) { if (a == b) { return 0; } if (null == a) { return -1; } if (null == b) { return 1; } return a.AbsoluteDisplayOrder.CompareTo(b.AbsoluteDisplayOrder); } private static int CompareDisplayOrders(Test.Module.Channel a, Test.Module.Channel b) { if (a == b) { return 0; } if (null == a) { return -1; } if (null == b) { return 1; } return a.AbsoluteDisplayOrder.CompareTo(b.AbsoluteDisplayOrder); } #endregion #region helper classes public class ChannelHelper : BasePropertyChanged { public ITestChannel MyChannel { get; private set; } public ChannelHelper(ITestChannel c) { MyChannel = c; var channelName = string.Empty; var code = string.Empty; switch (Common.Enums.IsoViewModeStatic.ViewMode) { case Common.Enums.IsoViewMode.ISOOnly: channelName = c.IsoChannelName; code = c.IsoCode; break; case Common.Enums.IsoViewMode.ISOAndUserCode: channelName = $"{c.IsoChannelName}/{c.UserChannelName}"; code = $"{c.IsoCode}/{c.UserCode}"; break; case Common.Enums.IsoViewMode.UserCodeOnly: channelName = c.UserChannelName; code = $"{c.UserCode}"; break; case Common.Enums.IsoViewMode.ChannelNameOnly: channelName = c.UserChannelName; code = string.Empty; break; } DisplayName = $"{channelName}/{code}/[{c.ToString()}]"; } public override string ToString() { return MyChannel.ChannelDescriptionString; } private string _displayName; public string DisplayName { get => _displayName; set { _displayName = value; OnPropertyChanged("DisplayName"); } } public string ChannelName => ToString(); private bool _bIncluded = false; public bool IsIncluded { get => _bIncluded; set => SetProperty(ref _bIncluded, value, "IsIncluded"); } } public class CalculationHelper { public Calculation MyCalculation { get; private set; } public CalculationHelper(Calculation calc) { MyCalculation = calc; } public override string ToString() { return Resources.StringResources.ResourceManager.GetString("CALCULATION_" + MyCalculation) ?? MyCalculation.ToString(); } } #endregion } }