//FB 32926 Old location of this file is DataPRO\DataPRO\DataModel\Classes\TestTemplate\TestTemplateList.cs using DTS.SensorDB; using System; using System.Collections.Generic; using System.Data; using System.Data.SqlClient; using System.Linq; using DTS.Common.Base; using DTS.Common.Enums; using DTS.Common.Utilities.Logging; using DTS.Common.ISO; using DTS.Common.Storage; using DTS.Slice.Users.UserSettings; using DTS.Common.Enums.Sensors; using DTS.Common.Events; using Prism.Ioc; using DTS.Common.Events.TestSetups.TestSetupsList; using DTS.Common.Classes.Sensors; using System.Threading.Tasks; using DTS.Common.Interface.TestSetups.TestSetupsList; using DTS.Common.SharedResource.Strings; using DTS.Common.DataModel; using DTS.Common.DataModel.Common; using Prism.Events; using System.Windows.Threading; using System.Windows; // ReSharper disable GenericEnumeratorNotDisposed namespace DataPROWin7.DataModel { public class TestTemplateList : BasePropertyChanged { /// /// this property is to hold a template in memory temporarily /// without committing it to the db, but to still act as if it is in the db /// public TestTemplate TemporaryTemplate { get; set; } protected TestTemplateList() { } private IReadOnlyDictionary _cachedCustomerDetails = null; public IReadOnlyDictionary CachedCustomerDetails { get => _cachedCustomerDetails; set => _cachedCustomerDetails = value; } private IReadOnlyDictionary _cachedLaboratoryDetails = null; public IReadOnlyDictionary CachedLaboratoryDetails { get => _cachedLaboratoryDetails; set => _cachedLaboratoryDetails = value; } private IReadOnlyDictionary _cachedTestEngineerDetails = null; public IReadOnlyDictionary CachedTestEngineerDetails { get => _cachedTestEngineerDetails; set => _cachedTestEngineerDetails = value; } public enum Tags { TestTemplates, CurrentTest, SavedCurrentTest } public TestTemplate GetTemplate(string name, bool bLoad = true) { if (name == StringResources.QuickSensorCheck_DefaultTestName) { return TemporaryTemplate; } if (string.IsNullOrWhiteSpace(name)) { return null; } TestTemplate[] templates = GetTemplates(name); TestTemplate testTemplate = templates.Length > 0 ? templates[0] : null; if (null != testTemplate && bLoad) { testTemplate.Load(); } return testTemplate; } public TestTemplate[] GetTemplates(string[] names, bool bLoad = true) { var templates = new List(); foreach (string name in names) { var template = GetTemplate(name, bLoad); if (null != template) { templates.Add(template); } } return templates.ToArray(); } /// /// returns a lookup of customer detail name to customer detail /// 28273 Calspan Centralized db performance needs to be improved /// /// private IReadOnlyDictionary GetCustomerDetailsLookup() { var lookup = new Dictionary(); try { var details = CustomerDetailsList.GetAllCustomers(); foreach (var detail in details) { lookup[detail.Name] = detail; } } catch (Exception ex) { APILogger.Log(ex); } return lookup; } /// /// returns a lookup of lab detail name to lab detail /// 28273 Calspan Centralized db performance needs to be improved /// /// private IReadOnlyDictionary GetLabDetailsLookup() { var lookup = new Dictionary(); try { var details = LabratoryDetailsList.GetAllLabs(); foreach (var detail in details) { lookup[detail.Name] = detail; } } catch (Exception ex) { APILogger.Log(ex); } return lookup; } private IReadOnlyDictionary GetTestEngineerDetailsLookup() { var lookup = new Dictionary(); try { var details = TestEngineerDetailsList.GetAllTestEngineers(); foreach (var detail in details) { lookup[detail.Name] = detail; } } catch (Exception ex) { APILogger.Log(ex); } return lookup; } private TestTemplate[] GetTemplates(string name, TestSetupDefaults settings = null, bool bIgnoreUserTags = false) { if (null == settings) { settings = TestSetupDefaults.GetUserSettings(ApplicationProperties.CurrentUser.Id); } //fixes an error in cmdline import when servicelocator is null IEventAggregator eventAggregator = null; try { if (Application.Current.Dispatcher.CheckAccess()) { eventAggregator = ContainerLocator.Container.Resolve(); } } catch (Exception) { return new TestTemplate[0]; } var testTemplates = new List(1000); IReadOnlyDictionary customerLookup = null; if (RunTestVariables.InRunTest && CachedCustomerDetails != null && CachedCustomerDetails.Count() > 0) { customerLookup = CachedCustomerDetails; } else { customerLookup = GetCustomerDetailsLookup(); if (RunTestVariables.InRunTest) { CachedCustomerDetails = customerLookup; } else { CachedCustomerDetails = null; } } IReadOnlyDictionary labLookup = null; if (RunTestVariables.InRunTest && CachedLaboratoryDetails != null && CachedLaboratoryDetails.Count() > 0) { labLookup = CachedLaboratoryDetails; } else { labLookup = GetLabDetailsLookup(); if (RunTestVariables.InRunTest) { CachedLaboratoryDetails = labLookup; } else { CachedLaboratoryDetails = null; } } IReadOnlyDictionary testEngineerLookup = null; if (RunTestVariables.InRunTest && CachedTestEngineerDetails != null && CachedTestEngineerDetails.Count() > 0) { testEngineerLookup = CachedTestEngineerDetails; } else { testEngineerLookup = GetTestEngineerDetailsLookup(); if (RunTestVariables.InRunTest) { CachedTestEngineerDetails = testEngineerLookup; } else { CachedTestEngineerDetails = null; } } try { var hardware = TestTemplate.GetSimpleHardwares(); var hr = DbOperations.TestSetupsGet(null, name, settings.DefaultROIStart, settings.DefaultROIEnd, settings.DefaultIgnoreShortedStart, settings.DefaultIgnoreShortedTrigger, out var records, out var errors); if (0 == hr && null != records && records.Any()) { foreach (var record in records) { var tt = new TestTemplate(settings, false, hardware, record); tt._bIsLoaded = false; eventAggregator?.GetEvent().Publish(new ProgressBarEventArg() { SetText = true, ProgressBarText = $"{StringResources.GettingTestSetup} {tt.Name}" }); if (customerLookup.ContainsKey(record.CustomerDetails)) { tt.CustomerDetails = customerLookup[record.CustomerDetails]; } else { tt.CustomerDetails = CustomerDetailsList.GetCustomerDetail(record.CustomerDetails); } if (testEngineerLookup.ContainsKey(record.TestEngineerDetails)) { tt.TestEngineerDetails = testEngineerLookup[record.TestEngineerDetails]; } else { tt.TestEngineerDetails = TestEngineerDetailsList.TestEngineerList.GetTestEngineerDetail(record.TestEngineerDetails); } tt.DownloadFolder = DataModelSettings.DownloadFolder; tt.ExportFolder = DataModelSettings.DownloadFolder; if (labLookup.ContainsKey(record.LabDetails)) { tt.LabDetails = labLookup[record.LabDetails]; } else { tt.LabDetails = LabratoryDetailsList.GetLab(record.LabDetails); } switch (ApplicationProperties.CurrentUser.Role) { case DTS.Slice.Users.User.DefaultRoles.Administrator: break; case DTS.Slice.Users.User.DefaultRoles.Guest: case DTS.Slice.Users.User.DefaultRoles.PowerUser: case DTS.Slice.Users.User.DefaultRoles.User: if (!bIgnoreUserTags && !ApplicationProperties.CurrentUser.TagCompatible(tt.GetTagIDs())) { continue; } break; } if (string.IsNullOrEmpty(name) && tt.Name.Equals(DTS.Common.DataModel.Classes.TestTemplate.TSRAIRGoTestSetup.TEST_NAME)) { //only return this template if we request it specifically ... continue; } testTemplates.Add(tt); } } if (null != eventAggregator && null != errors && errors.Any()) { try { eventAggregator.GetEvent().Publish(new PageErrorArg(errors, null)); } catch (Exception) { } } } catch (Exception ex) { APILogger.Log("failed to retrieve test templates", ex); } eventAggregator?.GetEvent().Publish(new ProgressBarEventArg() { SetText = true, ProgressBarText = string.Empty }); return testTemplates.ToArray(); } private async Task GetTemplatesAync(string name, TestSetupDefaults settings = null, bool bIgnoreUserTags = false) { //fixes an error in cmdline import when servicelocator is null IEventAggregator eventAggregator = null; try { if (Application.Current.Dispatcher.CheckAccess()) { eventAggregator = ContainerLocator.Container.Resolve(); } } catch (Exception) { return new TestTemplate[0]; } var testTemplates = new List(100); try { var hardware = TestTemplate.GetSimpleHardwares(); if (null == settings) { settings = TestSetupDefaults.GetUserSettings(ApplicationProperties.CurrentView.Id); } var hr = DbOperations.TestSetupsGet(null, name, settings.DefaultROIStart, settings.DefaultROIEnd, settings.DefaultIgnoreShortedStart, settings.DefaultIgnoreShortedTrigger, out var records, out var errors); if (0 == hr && null != records && records.Any()) { foreach (var record in records) { var tt = new TestTemplate(settings, false, hardware, record); eventAggregator?.GetEvent().Publish(new ProgressBarEventArg() { SetText = true, ProgressBarText = $"{StringResources.GettingTestSetup} {tt.Name}" }); tt.CustomerDetails = CustomerDetailsList.GetCustomerDetail(record.CustomerDetails); tt.TestEngineerDetails = TestEngineerDetailsList.TestEngineerList.GetTestEngineerDetail(record.TestEngineerDetails); tt.DownloadFolder = DataModelSettings.DownloadFolder; tt.ExportFolder = DataModelSettings.DownloadFolder; tt.LabDetails = LabratoryDetailsList.GetLab(record.LabDetails); switch (ApplicationProperties.CurrentUser.Role) { case DTS.Slice.Users.User.DefaultRoles.Administrator: break; case DTS.Slice.Users.User.DefaultRoles.Guest: case DTS.Slice.Users.User.DefaultRoles.PowerUser: case DTS.Slice.Users.User.DefaultRoles.User: if (!bIgnoreUserTags && !ApplicationProperties.CurrentUser.TagCompatible(tt.GetTagIDs())) { continue; } break; } testTemplates.Add(tt); } } if (null != eventAggregator && null != errors && errors.Any()) { try { eventAggregator.GetEvent().Publish(new PageErrorArg(errors, null)); } catch (Exception) { } } } catch (Exception ex) { APILogger.Log("failed to retrieve test templates", ex); } eventAggregator?.GetEvent().Publish(new ProgressBarEventArg() { SetText = true, ProgressBarText = string.Empty }); return testTemplates.ToArray(); } private void Commit(TestTemplate template, string user, bool bNotify, bool bUpdateTestSetupList = true) { TestSetupUpdate(user, template, bNotify); template.MarkIsCompleteUnchecked(); } /// /// FB 15880 Delete multiple tests /// /// the list of the tests which should be deleted /// private void DeleteMultipleTestSetups(List testSetupIds, bool updateTestSetupList = true) { if (!testSetupIds.Any()) { return; } testSetupIds.Sort(); _ = DbOperations.TestSetupsDeleteById(testSetupIds.ToArray()); /// 15877 deleting multiple test setups takes too much time. /// 15880 it should not take much time to delete multiple test setups , we can always pass true now if (updateTestSetupList) { TestSetupCollection.UpdateTestSetupList(); OnPropertyChanged(Tags.TestTemplates.ToString()); } } /// /// FB 15880 Delete multiple tests /// /// the list of the tests which should be deleted /// private void DeleteMultipleTestSetups(List testSetupNames, bool updateTestSetupList = true) { if (!testSetupNames.Any()) { return; } testSetupNames.Sort(); _ = DbOperations.TestSetupsDeleteByName(testSetupNames.ToArray()); /// 15877 deleting multiple test setups takes too much time. /// 15880 it should not take much time to delete multiple test setups , we can always pass true now if (updateTestSetupList) { TestSetupCollection.UpdateTestSetupList(); OnPropertyChanged(Tags.TestTemplates.ToString()); } } /// /// this function directly updates the template name in the database /// this was done during testing of 13563 Copy a test, save (get warning about name). Change the name and save, but get same warning the next time I make a change /// I noticed that renaming a test setup was no longer resulting in a delete and an insert but /// inserting a new test and pointing it to the objects used by the old one /// I'm not sure when this broke, but a solution to this is update the template name in the database, this way you'll be updating /// the existing test setup rather than creating a new one. /// /// private void UpdateTemplateNameIfNeeded(TestTemplate template) { //it was creating new test setups when you renamed a test setup. this is unintentional and changed at some point in the past //to fix this, if we have a positive id we have to update the name first //however we need to make sure the name doesn't already belong to a different test setup if (template.Id > 0) { bool bFound = false; using (var sql = DbOperations.GetSQLCommand(true)) { try { sql.CommandType = CommandType.Text; sql.CommandText = "SELECT [TestSetupId] FROM [TestSetups] WHERE [TestSetupName]=@1"; sql.Parameters.Add(new SqlParameter("@1", SqlDbType.NVarChar) { Value = template.Name }); using (var reader = sql.ExecuteReader()) { while (reader.Read()) { var id = Convert.ToInt32(reader["TestSetupId"]); if (id != template.Id) { throw new Exception("Test setup name already belongs to a different test setup"); } bFound = true; } } } finally { sql.Connection.Dispose(); } } if (!bFound) { using (var sql = DbOperations.GetSQLCommand(true)) { try { sql.CommandType = CommandType.Text; sql.CommandText = "UPDATE [TestSetups] SET [TestSetupName]=@1 WHERE [TestSetupId]=@2"; sql.Parameters.Add(new SqlParameter("@1", SqlDbType.NVarChar, 255) { Value = template.Name }); sql.Parameters.Add(new SqlParameter("@2", SqlDbType.BigInt) { Value = template.Id }); sql.ExecuteNonQuery(); } finally { sql.Connection.Dispose(); } } } } } /// /// Update or insert Test Setup and related records /// /// /// /// public void TestSetupUpdate(string user, TestTemplate template, bool bNotify) { var testSetupId = 0; UpdateTemplateNameIfNeeded(template); #region Insert into TestSetups table template.LastModified = DateTime.Now; template.LastModifiedBy = user; template.IsDirty = false; var record = (ITestSetupRecord)template; if (null != template.CustomerDetails) { record.CustomerDetails = template.CustomerDetails.Name; } if (null != template.TestEngineerDetails) { record.TestEngineerDetails = template.TestEngineerDetails.Name; } if (null != template.LabDetails) { record.LabDetails = template.LabDetails.Name; } record.AlignUDPToPPS = template.AlignUDPToPPS; template.Settings = template.GetSettings(); var hr = DbOperations.TestSetupsUpdateInsert(ref record); if (0 != hr) { APILogger.Log($"TestSetupUpdate failed: {hr}"); return; } testSetupId = record.Id; #endregion Test Setups Table template.SaveHardware(); template.SetTestSetupChannelOrder(); //25620 Exception thrown when TSR AIR with a level trigger is removed from a Test Setup //SaveGroups can cause channels to be deleted, but level trigger has a constraint on channel id //so those have to be removed before channels are saved //note that level triggers were ordinarily deleted and inserted as needed later on DeleteLevelTriggers(template.Name); template.SaveGroups(); #region Graphs table //14796 Cannot remove graph from test setup //ALWAYS update graphs, there may be existing graphs we need to remove template.Id = testSetupId; UpdateGraphs(template); #endregion Graphs table UpdateCalculatedChannels(testSetupId, template); #region Insert object meta data DeleteTestObjectMetaData(testSetupId, template.Name); UpdateTestObjectMetaData(testSetupId, template); #endregion Meta data #region Test meta data //DeleteTestMetaData(testSetupId, template.Name); var testMetaData = UpdateTestMetaData(testSetupId, template); #endregion Test meta data #region Insert Level Triggers UpdateLevelTriggers(testSetupId, template); #endregion LevelTriggers #region UpdateROIs var dbVersion = DbOperations.GetConnectionDbVersion(); if (dbVersion >= DTS.Common.Constants.ROITables_DB_VERSION) { UpdateROIs(testSetupId, template); } #endregion UpdateROIs } #region TestSetupUpdate related functions private void UpdateROIs(int testSetupId, TestTemplate template) { var hresult = DbOperations.RegionsOfInterestDelete(testSetupId); foreach (var regionOfInterest in template.RegionsOfInterest) { hresult = DbOperations.RegionsOfInterestInsert(testSetupId, regionOfInterest); } } private void DeleteLevelTriggers(string testSetupName) { using (var cmd = DbOperations.GetSQLCommand(true)) { try { cmd.CommandType = CommandType.StoredProcedure; cmd.CommandText = DbOperationsEnum.StoredProcedure.sp_LevelTriggersDelete.ToString(); #region params cmd.Parameters.Add( new SqlParameter("@TestSetupName", SqlDbType.NVarChar, 255) { Value = testSetupName }); cmd.Parameters.Add( new SqlParameter("@Id", SqlDbType.Int) { Value = DBNull.Value }); cmd.Parameters.Add( new SqlParameter("@ChannelId", SqlDbType.Int) { Value = DBNull.Value }); cmd.Parameters.Add( new SqlParameter("@TestSetupId", SqlDbType.Int) { Value = DBNull.Value }); var errorNumberParam = new SqlParameter("@errorNumber", SqlDbType.Int) { Direction = ParameterDirection.Output }; cmd.Parameters.Add(errorNumberParam); var errorMessageParam = new SqlParameter("@errorMessage", SqlDbType.NVarChar, 250) { Direction = ParameterDirection.Output }; cmd.Parameters.Add(errorMessageParam); #endregion params cmd.ExecuteNonQuery(); if (int.Parse(errorNumberParam.Value.ToString()) != 0) { APILogger.Log(errorMessageParam.Value.ToString()); } } finally { cmd.Connection.Dispose(); } } } /// /// Update Level Triggers /// /// /// private void UpdateLevelTriggers(int testSetupId, TestTemplate template) { //eliminate any invalid level triggers template.RemoveImpossibleLevelTriggers(); DeleteLevelTriggers(template.Name); try { if (template.LevelTriggerChannels.Count <= 0) return; var e = template.LevelTriggerChannels.GetEnumerator(); while (e.MoveNext()) { var lt = e.Current.Value; using (var cmd = DbOperations.GetSQLCommand(true)) { try { cmd.CommandType = CommandType.StoredProcedure; cmd.CommandText = DbOperationsEnum.StoredProcedure.sp_LevelTriggersInsert.ToString(); #region params cmd.Parameters.Add( new SqlParameter("@TestSetupId", SqlDbType.Int) { Value = DBNull.Value }); cmd.Parameters.Add( new SqlParameter("@TestSetupName", SqlDbType.NVarChar, 255) { Value = template.Name }); cmd.Parameters.Add( new SqlParameter("@ChannelId", SqlDbType.BigInt) { Value = lt.GroupChannel.Id }); //cmd.Parameters.Add( // new SqlParameter("@GroupSerialNumber", SqlDbType.NVarChar, 255) // { // Value = lt.GroupSerialNumber // }); //cmd.Parameters.Add( // new SqlParameter("@TestObjectChannelId", SqlDbType.NVarChar, 255) // { // Value = lt.TestObjectChannelId // }); //cmd.Parameters.Add( // new SqlParameter("@HardwareChannelId", SqlDbType.NVarChar, 255) // { // Value = lt.HardwareChannelId // }); //cmd.Parameters.Add( // new SqlParameter("@SensorSerialNumber", SqlDbType.NVarChar, 255) // { // Value = lt.SensorSerialNumber // }); /* TODO: remove later*/ cmd.Parameters.Add( new SqlParameter("@GreaterThanEnabled", SqlDbType.Bit) { Value = lt.GreaterThanEnabled }); cmd.Parameters.Add( new SqlParameter("@GreaterThanEU", SqlDbType.Float) { Value = lt.GreaterThanThresholdEU }); cmd.Parameters.Add( new SqlParameter("@LessThanEnabled", SqlDbType.Bit) { Value = lt.LessThanEnabled }); cmd.Parameters.Add( new SqlParameter("@LessThanEU", SqlDbType.Float) { Value = lt.LessThanThresholdEU }); cmd.Parameters.Add( new SqlParameter("@InsideUpperEU", SqlDbType.Float) { Value = lt.InsideUpperLevelEU }); cmd.Parameters.Add( new SqlParameter("@InsideLowerEU", SqlDbType.Float) { Value = lt.InsideLowerLevelEU }); cmd.Parameters.Add( new SqlParameter("@OutsideUpperEU", SqlDbType.Float) { Value = lt.OutsideUpperLevelEU }); cmd.Parameters.Add( new SqlParameter("@OutsideLowerEU", SqlDbType.Float) { Value = lt.OutsideLowerLevelEU }); cmd.Parameters.Add( new SqlParameter("@InsideEnabled", SqlDbType.Bit) { Value = lt.TriggerBetweenBounds }); cmd.Parameters.Add( new SqlParameter("@OutsideEnabled", SqlDbType.Bit) { Value = lt.TriggerOutsideBounds }); //cmd.Parameters.Add( // new SqlParameter("@TriggerInside", SqlDbType.Bit) { Value = lt.TriggerBetweenBounds }); //cmd.Parameters.Add( // new SqlParameter("@TriggerOutside", SqlDbType.Bit) { Value = lt.TriggerOutsideBounds }); var newIdParam = new SqlParameter("@new_id", SqlDbType.Int) { Direction = ParameterDirection.Output }; cmd.Parameters.Add(newIdParam); var errorNumberParam = new SqlParameter("@errorNumber", SqlDbType.Int) { Direction = ParameterDirection.Output }; cmd.Parameters.Add(errorNumberParam); var errorMessageParam = new SqlParameter("@errorMessage", SqlDbType.NVarChar, 250) { Direction = ParameterDirection.Output }; cmd.Parameters.Add(errorMessageParam); #endregion params cmd.ExecuteNonQuery(); if (int.Parse(errorNumberParam.Value.ToString()) != 0) { APILogger.Log(errorMessageParam.Value.ToString()); } } finally { cmd.Connection.Dispose(); } } } } catch (Exception ex) { APILogger.Log(ex); } //throw new Exception(""); } /// /// Update Test Setup Calculated Channels /// /// /// private void UpdateCalculatedChannels(int testSetupId, TestTemplate template) { //remap the -1 in input channel id for any input channels which were new (but are now in the db and have a valid id) template.UpdateCalculatedChannelInputIds(); //step 1, get all existing calcualted channels var presentIds = new HashSet(); foreach (var cc in template.CalculatedChannels) { if (cc.Id > 0) { presentIds.Add(cc.Id); } } var existingCalculatedChannelIds = GetExistingCalculatedChannelIds(template.Name); //step 2, remove no longer needed channels var toRemove = new List(); foreach (var id in existingCalculatedChannelIds) { if (!presentIds.Contains(id)) { toRemove.Add(id); } } foreach (var id in toRemove) { DeleteCalculatedChannel(id); } //step 3, update existing channels foreach (var cc in template.CalculatedChannels) { if (cc.Id > 0) { //if the Calculated channel has an id, but that's not an id in the db for the test, well //updating it won't work, insert it instead if (!existingCalculatedChannelIds.Contains(cc.Id)) { cc.Id = -1; } else { UpdateCalculatedChannel(cc, template.Name); } } } //step 4, add new calculated channels foreach (var cc in template.CalculatedChannels) { if (cc.Id <= 0) { InsertCalculatedChannel(cc, template.Name); } } } private void InsertCalculatedChannel(CalculatedValueClass cc, string testSetupName) { cc.TestSetupName = testSetupName; _ = DbOperations.CalculatedChannelsInsert(cc); } private void UpdateCalculatedChannel(CalculatedValueClass cc, string testSetupName) { cc.TestSetupName = testSetupName; _ = DbOperations.CalculatedChannelsUpdate(cc); } private void DeleteCalculatedChannel(int id) { _ = DbOperations.CalculatedChannelsDelete(id); } private int[] GetExistingCalculatedChannelIds(string testName) { var list = new List(); var hr = DbOperations.CalculatedChannelsGet(null, testName, out var records); if (0 == hr && null != records && records.Any()) { foreach (var record in records) { if (!list.Contains(record.Id)) { list.Add(record.Id); } } } return list.ToArray(); } /// /// Update Test Meta Data /// /// /// /// private TestSetupMetaData UpdateTestMetaData(int testSetupId, TestTemplate template) { var testMeta = template.GetTestMetaData(); // FB 17951 Prevent empty TestObject entry if (string.IsNullOrWhiteSpace(testMeta.TestObject.ToString())) { return testMeta; } foreach (var prop in testMeta.Properties) { using (var cmd = DbOperations.GetSQLCommand(true)) { try { cmd.CommandType = CommandType.StoredProcedure; cmd.CommandText = DbOperationsEnum.StoredProcedure.sp_TestSetupObjectMetaDataInsert.ToString(); #region params cmd.Parameters.Add(new SqlParameter("@TestSetupId", SqlDbType.Int) { Value = testSetupId }); cmd.Parameters.Add( new SqlParameter("@TestSetupName", SqlDbType.NVarChar, 50) { Value = template.Name }); cmd.Parameters.Add( new SqlParameter("@ISOTestObject", SqlDbType.NVarChar, 1) { Value = testMeta.TestObject }); cmd.Parameters.Add(new SqlParameter("@PropName", SqlDbType.NVarChar, 255) { Value = prop.Name }); cmd.Parameters.Add( new SqlParameter("@PropValue", SqlDbType.NVarChar, 255) { Value = prop.Value ?? "" }); cmd.Parameters.Add(new SqlParameter("@Optional", SqlDbType.Bit) { Value = prop.IsOptional }); cmd.Parameters.Add(new SqlParameter("@Version", SqlDbType.Float) { Value = prop.Version }); var newIdParam = new SqlParameter("@new_id", SqlDbType.Int) { Direction = ParameterDirection.Output }; cmd.Parameters.Add(newIdParam); var errorNumberParam = new SqlParameter("@errorNumber", SqlDbType.Int) { Direction = ParameterDirection.Output }; cmd.Parameters.Add(errorNumberParam); var errorMessageParam = new SqlParameter("@errorMessage", SqlDbType.NVarChar, 250) { Direction = ParameterDirection.Output }; cmd.Parameters.Add(errorMessageParam); #endregion params cmd.ExecuteNonQuery(); if (int.Parse(errorNumberParam.Value.ToString()) != 0) { APILogger.Log(errorMessageParam.Value.ToString()); } } finally { cmd.Connection.Dispose(); } } } return testMeta; } private void DeleteTestObjectMetaData(int testSetupId, string testSetupName) { using (var cmd = DbOperations.GetSQLCommand(true)) { try { cmd.CommandType = CommandType.StoredProcedure; cmd.CommandText = DbOperationsEnum.StoredProcedure.sp_TestSetupObjectMetaDataDelete.ToString(); #region params cmd.Parameters.Add(new SqlParameter("@TestSetupId", SqlDbType.Int) { Value = testSetupId }); cmd.Parameters.Add( new SqlParameter("@TestSetupName", SqlDbType.NVarChar, 50) { Value = testSetupName }); var errorNumberParam = new SqlParameter("@errorNumber", SqlDbType.Int) { Direction = ParameterDirection.Output }; cmd.Parameters.Add(errorNumberParam); var errorMessageParam = new SqlParameter("@errorMessage", SqlDbType.NVarChar, 250) { Direction = ParameterDirection.Output }; cmd.Parameters.Add(errorMessageParam); #endregion params cmd.ExecuteNonQuery(); if (int.Parse(errorNumberParam.Value.ToString()) != 0) { APILogger.Log(errorMessageParam.Value.ToString()); } } finally { cmd.Connection.Dispose(); } } } /// /// Update Test Object Meta Data /// /// /// private void UpdateTestObjectMetaData(int testSetupId, TestTemplate template) { foreach (var metadata in template.GetMetaData()) { // FB 17951 Prevent empty TestObject entry if (string.IsNullOrWhiteSpace(metadata.TestObject.ToString())) { continue; } foreach (var prop in metadata.Properties) { using (var cmd = DbOperations.GetSQLCommand(true)) { try { cmd.CommandType = CommandType.StoredProcedure; cmd.CommandText = DbOperationsEnum.StoredProcedure.sp_TestSetupObjectMetaDataInsert.ToString(); #region params cmd.Parameters.Add(new SqlParameter("@TestSetupId", SqlDbType.Int) { Value = testSetupId }); cmd.Parameters.Add( new SqlParameter("@TestSetupName", SqlDbType.NVarChar, 50) { Value = template.Name }); cmd.Parameters.Add( new SqlParameter("@ISOTestObject", SqlDbType.NVarChar, 1) { Value = metadata.TestObject }); cmd.Parameters.Add( new SqlParameter("@PropName", SqlDbType.NVarChar, 255) { Value = prop.Name }); cmd.Parameters.Add( new SqlParameter("@PropValue", SqlDbType.NVarChar, 255) { Value = prop.Value }); cmd.Parameters.Add(new SqlParameter("@Optional", SqlDbType.Bit) { Value = prop.IsOptional }); cmd.Parameters.Add(new SqlParameter("@Version", SqlDbType.Float) { Value = prop.Version }); var newIdParam = new SqlParameter("@new_id", SqlDbType.Int) { Direction = ParameterDirection.Output }; cmd.Parameters.Add(newIdParam); var errorNumberParam = new SqlParameter("@errorNumber", SqlDbType.Int) { Direction = ParameterDirection.Output }; cmd.Parameters.Add(errorNumberParam); var errorMessageParam = new SqlParameter("@errorMessage", SqlDbType.NVarChar, 250) { Direction = ParameterDirection.Output }; cmd.Parameters.Add(errorMessageParam); #endregion params cmd.ExecuteNonQuery(); if (int.Parse(errorNumberParam.Value.ToString()) != 0) { APILogger.Log(errorMessageParam.Value.ToString()); } } finally { cmd.Connection.Dispose(); } } } } } private void UpdateGraphs(TestTemplate test) { //1, get list of existing graphs for test setup var existingIds = GetExistingGraphIds(test.Id); //2, delete any graphs no longer needed var existing = new HashSet(); foreach (var graph in test.TestGraphs) { existing.Add(graph.GraphId); } var toDelete = new List(); foreach (var id in existingIds) { if (!existing.Contains(id)) { toDelete.Add(id); } } foreach (var id in toDelete) { DeleteGraph(id); } //3, update foreach (var graph in test.TestGraphs) { if (graph.GraphId > 0) { graph.TestSetupId = test.Id; UpdateGraph(graph); } } //4, add any new ones foreach (var graph in test.TestGraphs) { if (graph.GraphId <= 0) { graph.TestSetupId = test.Id; InsertGraph(graph); } } } private void UpdateGraph(TestGraph graph) { graph.UpdateChannelAndThresholdStrings(); _ = DbOperations.TestGraphsUpdate(graph); } private void InsertGraph(TestGraph graph) { graph.UpdateChannelAndThresholdStrings(); _ = DbOperations.TestGraphsInsert(graph); } private void DeleteGraph(int id) { _ = DbOperations.TestGraphsDelete(id); } private int[] GetExistingGraphIds(int testSetupId) { var list = new List(); var hr = DbOperations.TestGraphsGet(null, testSetupId, out var records); if (0 == hr && null != records && records.Any()) { foreach (var record in records) { list.Add(record.GraphId); } } return list.ToArray(); } #endregion TestSetupUpdate related functions public static SensorData GetSensorFromSettings(string settings, string serial, Dictionary lookup) { SensorData sd = null; if (null != lookup && lookup.ContainsKey(serial)) { sd = lookup[serial]; } if (null == sd) { sd = SensorsCollection.SensorsList.GetSensorBySerialNumber(serial); } if (string.IsNullOrWhiteSpace(serial)) { sd = new SensorData { SerialNumber = "" }; } if (null == sd) { return null; } sd = new SensorData(sd); var tokens = settings.Split(','); foreach (var token in tokens) { var subtokens = token.Split('='); var setting = (SensorConstants.SensorSettings)int.Parse(subtokens[0]); switch (setting) { case SensorConstants.SensorSettings.CFC: sd.FilterClassIso = subtokens[1]; break; //FB 13120 filter class setting; case SensorConstants.SensorSettings.FilterClass: sd.FilterClass = FilterClass.GetFilterClassFromFilterClassSetting(subtokens[1]); break; case SensorConstants.SensorSettings.Position: sd.Position = subtokens[1]; break; case SensorConstants.SensorSettings.Polarity: sd.Invert = subtokens[1] == "-"; break; case SensorConstants.SensorSettings.Range: sd.Capacity = double.Parse(subtokens[1], System.Globalization.CultureInfo.InvariantCulture); break; case SensorConstants.SensorSettings.Delay: if (!string.IsNullOrWhiteSpace(subtokens[1])) { sd.DelayMS = double.Parse(subtokens[1], System.Globalization.CultureInfo.InvariantCulture); sd.DigitalOutputDelayMS = sd.DelayMS; } break; case SensorConstants.SensorSettings.Duration: if (!string.IsNullOrWhiteSpace(subtokens[1])) { sd.DurationMS = double.Parse(subtokens[1], System.Globalization.CultureInfo.InvariantCulture); sd.DigitalOutputDurationMS = sd.DurationMS; } break; case SensorConstants.SensorSettings.OutputMode: if (!string.IsNullOrWhiteSpace(subtokens[1])) { sd.DigitalOutputMode = (DigitalOutputModes)Convert.ToInt32(subtokens[1]); } break; case SensorConstants.SensorSettings.SQMode: if (!string.IsNullOrWhiteSpace(subtokens[1])) { sd.SquibFireMode = (SquibFireMode)Convert.ToInt32(subtokens[1]); } break; case SensorConstants.SensorSettings.DIMode: if (!string.IsNullOrWhiteSpace(subtokens[1])) { sd.InputMode = (DigitalInputModes)Convert.ToInt32(subtokens[1]); } break; case SensorConstants.SensorSettings.LimitDuration: if (!string.IsNullOrWhiteSpace(subtokens[1])) { sd.LimitDuration = bool.Parse(subtokens[1]); } break; case SensorConstants.SensorSettings.ActiveValue: if (!string.IsNullOrWhiteSpace(subtokens[1])) { sd.ScaleMultiplier.ActiveValue = Convert.ToDouble(subtokens[1]); } break; case SensorConstants.SensorSettings.DefaultValue: if (!string.IsNullOrWhiteSpace(subtokens[1])) { sd.ScaleMultiplier.DefaultValue = Convert.ToDouble(subtokens[1]); } break; case SensorConstants.SensorSettings.DigitalOutDelay: if (!string.IsNullOrWhiteSpace(subtokens[1])) { sd.DigitalOutputDelayMS = Convert.ToDouble(subtokens[1], System.Globalization.CultureInfo.InvariantCulture); } break; case SensorConstants.SensorSettings.DigitalOutDuration: if (!string.IsNullOrWhiteSpace(subtokens[1])) { sd.DigitalOutputDurationMS = Convert.ToDouble(subtokens[1], System.Globalization.CultureInfo.InvariantCulture); } break; case SensorConstants.SensorSettings.DigitalOutLimitDuration: if (!string.IsNullOrWhiteSpace(subtokens[1])) { sd.DigitalOutputLimitDuration = Convert.ToBoolean(subtokens[1]); } break; case SensorConstants.SensorSettings.SquibDelay: if (!string.IsNullOrWhiteSpace(subtokens[1])) { sd.SquibFireDelayMS = Convert.ToDouble(subtokens[1], System.Globalization.CultureInfo.InvariantCulture); } break; case SensorConstants.SensorSettings.SquibDuration: if (!string.IsNullOrWhiteSpace(subtokens[1])) { sd.SquibFireDurationMS = Convert.ToDouble(subtokens[1], System.Globalization.CultureInfo.InvariantCulture); } break; case SensorConstants.SensorSettings.SquibLimitDuration: if (!string.IsNullOrWhiteSpace(subtokens[1])) { sd.LimitSquibFireDuration = Convert.ToBoolean(subtokens[1]); } break; } } return sd; } public static SensorData GetSensorFromSettings(string settings, string serial) { return GetSensorFromSettings(settings, serial, null); } public static string GetSensorSettings(SensorData sd) { var list = new List(); switch (sd.Bridge) { case SensorConstants.BridgeType.RTC: case SensorConstants.BridgeType.IEPE: case SensorConstants.BridgeType.QuarterBridge: case SensorConstants.BridgeType.HalfBridge: case SensorConstants.BridgeType.FullBridge: case SensorConstants.BridgeType.HalfBridge_SigPlus: list.Add($"{(int)SensorConstants.SensorSettings.CFC}={sd.FilterClassIso}"); //FB 13120 filter class setting list.Add($"{(int)SensorConstants.SensorSettings.FilterClass}={$"{sd.FilterClass.FClass},{sd.FilterClass.Frequency}"}"); list.Add($"{(int)SensorConstants.SensorSettings.Polarity}={(sd.Invert ? "-" : "+")}"); list.Add($"{(int)SensorConstants.SensorSettings.Position}={sd.Position}"); list.Add($"{(int)SensorConstants.SensorSettings.Range}={sd.Capacity.ToString(System.Globalization.CultureInfo.InvariantCulture)}"); break; case SensorConstants.BridgeType.DigitalInput: list.Add($"{(int)SensorConstants.SensorSettings.DIMode}={(int)sd.InputMode}"); list.Add($"{(int)SensorConstants.SensorSettings.ActiveValue}={sd.ScaleMultiplier.ActiveValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}"); list.Add($"{(int)SensorConstants.SensorSettings.DefaultValue}={sd.ScaleMultiplier.DefaultValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}"); break; case SensorConstants.BridgeType.SQUIB: list.Add($"{(int)SensorConstants.SensorSettings.SQMode}={(int)sd.SquibFireMode}"); list.Add($"{(int)SensorConstants.SensorSettings.SquibDelay}={sd.SquibFireDelayMS.ToString(System.Globalization.CultureInfo.InvariantCulture)}"); list.Add($"{(int)SensorConstants.SensorSettings.SquibDuration}={sd.SquibFireDurationMS.ToString(System.Globalization.CultureInfo.InvariantCulture)}"); list.Add($"{(int)SensorConstants.SensorSettings.SquibLimitDuration}={sd.LimitSquibFireDuration.ToString()}"); break; case SensorConstants.BridgeType.TOMDigital: list.Add($"{(int)SensorConstants.SensorSettings.OutputMode}={(int)sd.DigitalOutputMode}"); list.Add($"{(int)SensorConstants.SensorSettings.DigitalOutDelay}={sd.DigitalOutputDelayMS.ToString(System.Globalization.CultureInfo.InvariantCulture)}"); list.Add($"{(int)SensorConstants.SensorSettings.DigitalOutDuration}={sd.DigitalOutputDurationMS.ToString(System.Globalization.CultureInfo.InvariantCulture)}"); list.Add($"{(int)SensorConstants.SensorSettings.DigitalOutLimitDuration}={sd.DigitalOutputLimitDuration.ToString()}"); break; } return string.Join(",", list.ToArray()); } public void CommitGroupOfTemplates(TestTemplate[] templates, bool bNotify) { foreach (var template in templates) { Commit(template, ApplicationProperties.CurrentUser.UserName, bNotify, false); template.MarkIsCompleteUnchecked(); } if (1 == templates.Length) { TestSetupCollection.UpdateTestSetupList(templates.FirstOrDefault()); } else { TestSetupCollection.UpdateTestSetupList(); } OnPropertyChanged(Tags.TestTemplates.ToString()); } public void Commit(TestTemplate template) { Commit(template, true); } public void Commit(TestTemplate template, bool bNotify) { CommitGroupOfTemplates(new[] { template }, bNotify); } private TestTemplate _currentTest; public TestTemplate CurrentTest { get => _currentTest; set { SetProperty(ref _currentTest, value, Tags.CurrentTest.ToString()); //FB14483 "Should not include calculated channel when running test if Calculated Channel UI is not enabled either" if (!Common.SerializedSettings.AllowCalculatedChannels) CurrentTest?.CalculatedChannels.Clear(); var eventAggregator = ContainerLocator.Container.Resolve(); eventAggregator.GetEvent().Publish(value?.Name ?? string.Empty); } } private TestTemplate _savedCurrentTest; public TestTemplate SavedCurrentTest { get => _savedCurrentTest; set => SetProperty(ref _savedCurrentTest, value, Tags.SavedCurrentTest.ToString()); } private static TestTemplateList _list; private static readonly object ObjectLock = new object(); public static TestTemplateList TestTemplatesList { get { lock (ObjectLock) { if (null == _list) { _list = new TestTemplateList(); } } return _list; } } /// /// delete templates from the db and remove them from the list of templates /// /// test id of templates to delete /// public void DeleteTestSetups(List testSetupIds, string user) { DeleteMultipleTestSetups(testSetupIds); OnPropertyChanged(Tags.TestTemplates.ToString()); } /// /// delete templates from the db and remove them from the list of templates /// /// test id of templates to delete /// public void DeleteTestSetups(List testSetupNames, string user) { DeleteMultipleTestSetups(testSetupNames); OnPropertyChanged(Tags.TestTemplates.ToString()); } public TestTemplate[] TestTemplates { get { var templates = new List(GetAllTemplates()); for (var i = templates.Count - 1; i >= 0; i--) { if (!templates[i].IsComplete) { templates.RemoveAt(i); } } templates.Sort(); return templates.ToArray(); } } public TestTemplate[] AllTemplates { get { var templates = new List(GetAllTemplates()); templates.Sort(); return templates.ToArray(); } } public async Task GetAllTemplatesAync() { var unsortedTemplates = await GetAllTemplatesForUserAsync(false); var templates = new List(unsortedTemplates); templates.Sort(); return templates.ToArray(); } private TestTemplate[] GetAllTemplates() { return GetAllTemplatesForUser(false); } public TestTemplate[] GetAllTemplatesForUser(bool bIgnoreUserTags = false) { var settings = TestSetupDefaults.GetUserSettings(ApplicationProperties.CurrentUser.Id); return GetTemplates(null, settings, bIgnoreUserTags); } public async Task GetAllTemplatesForUserAsync(bool bIgnoreUserTags = false) { var settings = TestSetupDefaults.GetUserSettings(ApplicationProperties.CurrentUser.Id); return await GetTemplatesAync(null, settings, bIgnoreUserTags); } public static void ConvertToDictionary(IDataReader reader, ref Dictionary>> lookup, string key) { var count = reader.FieldCount; var names = new string[count]; for (var i = 0; i < names.Length; i++) { names[i] = reader.GetName(i); } while (reader.Read()) { var thiskey = Convert.ToString(reader[key]); if (!lookup.ContainsKey(thiskey)) { lookup.Add(thiskey, new List>()); } var properties = new Dictionary(count); foreach (var column in names) { properties[column] = reader[column]; } lookup[thiskey].Add(properties); } } } }