1191 lines
46 KiB
C#
1191 lines
46 KiB
C#
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>, 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<Notification> NotificationRequest { get; private set; }
|
|
public new InteractionRequest<Confirmation> ConfirmationRequest { get; private set; }
|
|
|
|
/// <summary>
|
|
/// Creates a new instance of the AddCalculatedChannelViewModel.
|
|
/// </summary>
|
|
/// <param name="view">The AddCalculatedChannelView interface.</param>
|
|
/// <param name="regionManager">The logical placeholder defined within the application's UI (in the shell or within views) into which views are displayed.</param>
|
|
/// <param name="eventAggregator">The EventAggregator which allows different components to publish/subscribe to events without being coupled to each other.</param>
|
|
/// <param name="unityContainer">The unityContainer.</param>
|
|
public AddCalculatedChannelViewModel(IAddCalculatedChannelView view, IRegionManager regionManager, IEventAggregator eventAggregator,
|
|
IUnityContainer unityContainer)
|
|
: base(regionManager, eventAggregator, unityContainer)
|
|
{
|
|
View = view;
|
|
View.DataContext = this;
|
|
NotificationRequest = new InteractionRequest<Notification>();
|
|
ConfirmationRequest = new InteractionRequest<Confirmation>();
|
|
|
|
_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();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Subscribe for events
|
|
/// </summary>
|
|
private void Subscribe()
|
|
{
|
|
_eventAggregator.GetEvent<RaiseNotification>().Subscribe(OnRaiseNotification);
|
|
_eventAggregator.GetEvent<TestSummaryChangeNotification>().Subscribe(OnTestSummaryChanged);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Private Event handler for RaiseNotification event.
|
|
/// </summary>
|
|
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
|
|
});
|
|
}
|
|
|
|
/// <summary>
|
|
/// Read all graphs, calculated channels and channels for the selected test
|
|
/// and select and display first group or channel
|
|
/// </summary>
|
|
/// <param name="list"></param>
|
|
private void OnTestSummaryChanged(TestSummaryChangeNotificationArg arg)
|
|
{
|
|
if (Parent != arg?.ParentVM) return;
|
|
var list = arg.SummaryList;
|
|
var inputChannels = new List<ITestChannel>();
|
|
var inputChannelObjects = new List<ChannelHelper>();
|
|
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<ITestChannel>(CompareDisplayOrders));
|
|
}
|
|
|
|
foreach (var channel in inputChannels)
|
|
{
|
|
inputChannelObjects.Add(new ChannelHelper(channel));
|
|
}
|
|
|
|
ChannelList = new ObservableCollection<ITestChannel>(inputChannels);
|
|
ChannelListObjects = new ObservableCollection<ChannelHelper>(inputChannelObjects);
|
|
|
|
_HICAccelerationX = null;
|
|
OnPropertyChanged("HICAccelerationX");
|
|
_HICAccelerationY = null;
|
|
OnPropertyChanged("HICAccelerationY");
|
|
_HICAccelerationZ = null;
|
|
OnPropertyChanged("HICAccelerationZ");
|
|
|
|
_availableHICChannels = new List<ChannelHelper>();
|
|
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<ChannelHelper>(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<ChannelHelper>(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<ChannelHelper>(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<string>();
|
|
var warnings = new List<string>();
|
|
|
|
var valid = Validate(ref errors, ref warnings, false);
|
|
|
|
if (errors.Any() || warnings.Any())
|
|
{
|
|
var toDisplay = new List<string>(errors.ToArray());
|
|
toDisplay.AddRange(warnings.ToArray());
|
|
_eventAggregator.GetEvent<PageErrorEvent>().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<Test.Module.Channel>();
|
|
var orderedChannels = new List<Test.Module.Channel>();
|
|
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<Test.Module.Channel>(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 <Test> 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 <TestSetup> 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<RefreshTestRequestEvent>().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<RaiseNotification>().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
|
|
|
|
///<summary>
|
|
///Occurs when a property value changes.
|
|
///</summary>
|
|
public new event PropertyChangedEventHandler PropertyChanged;
|
|
|
|
private new void OnPropertyChanged(string propertyName)
|
|
{
|
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the HeaderInfo.
|
|
/// </summary>
|
|
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;
|
|
/// <summary>
|
|
/// whether HIC is visible or not
|
|
/// </summary>
|
|
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<Calculation>().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<SetSaveButton>().Publish(new SaveButtonUsability() { IsUsable = false }); }
|
|
else { _eventAggregator.GetEvent<SetSaveButton>().Publish(new SaveButtonUsability() { IsUsable = true }); }
|
|
break;
|
|
case Calculation.SUM:
|
|
case Calculation.AVE:
|
|
if (ChannelListObjects.All(clo => !clo.IsIncluded)) { _eventAggregator.GetEvent<SetSaveButton>().Publish(new SaveButtonUsability() { IsUsable = false }); }
|
|
else { _eventAggregator.GetEvent<SetSaveButton>().Publish(new SaveButtonUsability() { IsUsable = true }); }
|
|
break;
|
|
case Calculation.HIC:
|
|
if (null == HICAccelerationX || null == HICAccelerationY || null == HICAccelerationZ)
|
|
{
|
|
_eventAggregator.GetEvent<SetSaveButton>().Publish(new SaveButtonUsability() { IsUsable = true });
|
|
}
|
|
else
|
|
{
|
|
_eventAggregator.GetEvent<SetSaveButton>().Publish(new SaveButtonUsability() { IsUsable = false });
|
|
}
|
|
break;
|
|
default:
|
|
if ((null != SourceChannel) && (false == string.IsNullOrEmpty(ChannelName)) && (false == string.IsNullOrEmpty(IsoCode)))
|
|
{ _eventAggregator.GetEvent<SetSaveButton>().Publish(new SaveButtonUsability() { IsUsable = true }); }
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_eventAggregator.GetEvent<SetSaveButton>().Publish(new SaveButtonUsability() { IsUsable = false });
|
|
}
|
|
}
|
|
|
|
private ObservableCollection<ITestChannel> _channelList = new ObservableCollection<ITestChannel>();
|
|
public ObservableCollection<ITestChannel> ChannelList
|
|
{
|
|
get => _channelList;
|
|
set
|
|
{
|
|
_channelList = value;
|
|
OnPropertyChanged(Tags.ChannelList.ToString());
|
|
}
|
|
}
|
|
|
|
private List<ChannelHelper> _availableHICChannels = new List<ChannelHelper>();
|
|
/// <summary>
|
|
/// all HIC possible channels (g,m/sec,m/sec^2 channels)
|
|
/// </summary>
|
|
public ChannelHelper[] AvailableHICChannels
|
|
{
|
|
get => _availableHICChannels.ToArray();
|
|
set
|
|
{
|
|
_availableHICChannels.Clear();
|
|
_availableHICChannels.AddRange(value);
|
|
OnPropertyChanged("AvailableHICChannels");
|
|
}
|
|
}
|
|
|
|
private ChannelHelper _HICAccelerationX;
|
|
/// <summary>
|
|
/// currently selected head acceleration x
|
|
/// </summary>
|
|
public ChannelHelper HICAccelerationX
|
|
{
|
|
get => _HICAccelerationX;
|
|
set
|
|
{
|
|
_HICAccelerationX = value;
|
|
OnPropertyChanged("HICAccelerationX");
|
|
}
|
|
}
|
|
|
|
private ChannelHelper _HICAccelerationY;
|
|
/// <summary>
|
|
/// currently selected head acceleration y
|
|
/// </summary>
|
|
public ChannelHelper HICAccelerationY
|
|
{
|
|
get => _HICAccelerationY;
|
|
set
|
|
{
|
|
_HICAccelerationY = value;
|
|
OnPropertyChanged("HICAccelerationY");
|
|
}
|
|
}
|
|
|
|
private ChannelHelper _HICAccelerationZ;
|
|
/// <summary>
|
|
/// currently selected head acceleration z
|
|
/// </summary>
|
|
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<ChannelHelper> _channelListObjects = new ObservableCollection<ChannelHelper>();
|
|
public ObservableCollection<ChannelHelper> 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<ChannelHelper> _irTraccChannelList = new ObservableCollection<ChannelHelper>();
|
|
public ObservableCollection<ChannelHelper> 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<ChannelHelper> _pot1ChannelList = new ObservableCollection<ChannelHelper>();
|
|
public ObservableCollection<ChannelHelper> 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<ChannelHelper> _pot2ChannelList = new ObservableCollection<ChannelHelper>();
|
|
public ObservableCollection<ChannelHelper> 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<string> errors, ref List<string> 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<string> errors, ref List<string> 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<string> errors, ref List<string> 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<Test.Module> 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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 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
|
|
/// </summary>
|
|
/// <param name="filename"></param>
|
|
/// <returns></returns>
|
|
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
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|