using System; using System.Collections.Generic; using System.Data; using System.Linq; using System.Windows; using DTS.Common.Base; using DTS.Common.Storage; using DTS.Common.ISO; using DTS.Common.DataModel; namespace DataPROWin7.DataModel { /// /// a custom channel is a wrapper for MMEPossibleChannels that are defined by the user rather than ISO13499 /// they have mirror tables to the actual db and let us define new channels without disrupting the existing 1so13499 db /// public class CustomChannel : BasePropertyChanged, IComparable { private const string defaultDefaultFilterClass = "P"; #region Properties public MMEPossibleChannels Channel { get; private set; } public string TypeString { get => Channel.Type; set { Channel.SetType(value); OnPropertyChanged("TypeString"); } } private MMETestObjects _testObject; public MMETestObjects TestObject { get => _testObject; set { SetProperty(ref _testObject, value, "TestObject"); if (null != Channel && null != value) { Channel.Set_Test_Object(value.Test_Object); } } } private MMEPositions _position; public MMEPositions Position { get => _position; set { SetProperty(ref _position, value, "Position"); if (null != Channel && null != value) { Channel.Set_Position(value.Position); } } } private MMETransducerMainLocation _mainLocation; public MMETransducerMainLocation MainLocation { get => _mainLocation; set { SetProperty(ref _mainLocation, value, "MainLocation"); if (null != Channel && null != value) { Channel.Set_Main_Loc(value.Trans_Main_Loc); } } } private MMEFineLocations1 _finLoc1; public MMEFineLocations1 FinLoc1 { get => _finLoc1; set { SetProperty(ref _finLoc1, value, "FinLoc1"); if (null != Channel && null != value) { Channel.Set_Fine_Loc_1(value.Fine_Loc_1); } } } private MMEFineLocations2 _finLoc2; public MMEFineLocations2 FinLoc2 { get => _finLoc2; set { SetProperty(ref _finLoc2, value, "FinLoc2"); if (null != Channel && null != value) { Channel.Set_Fine_Loc_2(value.FINE_LOC_2); } } } private MMEFineLocations3 _finLoc3; public MMEFineLocations3 FinLoc3 { get => _finLoc3; set { SetProperty(ref _finLoc3, value, "FinLoc3"); if (null != Channel && null != value) { Channel.Set_Fine_Loc_3(value.FINE_LOC_3); } } } private MMEPhysicalDimensions _physicalDimension; public MMEPhysicalDimensions PhysicalDimension { get => _physicalDimension; set { SetProperty(ref _physicalDimension, value, "PhysicalDimension"); if (null != Channel && null != value) { Channel.Set_Physical_Dimension(value.Physical_Dimension); } } } private MMEDirections _direction; public MMEDirections Direction { get => _direction; set { SetProperty(ref _direction, value, "Direction"); if (null != Channel && null != value) { Channel.Set_Direction(value.Direction); } } } private MMEFilterClasses _filterClass; public MMEFilterClasses FilterClass { get => _filterClass; set { SetProperty(ref _filterClass, value, "FilterClass"); if (null != Channel && null != value) { Channel.Set_Default_Filter_Class(value.Filter_Class); } } } #endregion Properties public string Text1 { get => Channel.Text_L1; set { var name = value; System.Diagnostics.Trace.Assert(name?.Length < 250, "Channel text is too long"); Channel.SetText1(name); OnPropertyChanged("Text1"); } } public string Remarks { get => Channel.Remarks; set { Channel.SetRemarks(value); OnPropertyChanged("Remarks"); } } public CustomChannel() { Channel = new MMEPossibleChannels(-1, "", "", "", "", "", "", "", "", "", "", "", "", 0, DateTime.Now, "", false, "", "", DateTime.MinValue, "", "", (int)MMEPossibleChannels.MMEChannelTypes.SQL); _filterClass = ApplicationProperties.IsoDb.GetFilterClassByIso("A"); } private readonly List _expiredErrors = new List(); /// /// these are any errors detected during loading of the custom channel /// as custom channels are reliant on the ISO13499 mdb, it is possible for it to have been updated and for things to have been removed or expired /// public ISO13499FileDb.ExpiredISOFieldException[] ExpiredErrors => _expiredErrors.ToArray(); public CustomChannel(MMEPossibleChannels channel, bool newChannel = true) { Channel = newChannel ? new MMEPossibleChannels(channel) : channel; _direction = ApplicationProperties.IsoDb.GetDirectionByIso(channel.Direction); _filterClass = ApplicationProperties.IsoDb.GetFilterClassByIso(channel.Default_Filter_Class) ?? ApplicationProperties.IsoDb.GetFilterClassByIso(defaultDefaultFilterClass); _finLoc1 = ApplicationProperties.IsoDb.GetFineLocation1ByIso(channel.Fine_Loc_1); _finLoc2 = ApplicationProperties.IsoDb.GetFineLocation2ByIso(channel.Fine_Loc_2); _finLoc3 = ApplicationProperties.IsoDb.GetFineLocation3ByIso(channel.Fine_Loc_3); try { _mainLocation = ApplicationProperties.IsoDb.GetMainLocationByIso(channel.Trans_Main_Loc); } catch (ISO13499FileDb.ExpiredISOFieldException ex) { _expiredErrors.Add(ex); } _physicalDimension = ApplicationProperties.IsoDb.GetPhysicalDimensionByIso(channel.Physical_Dimension); _position = ApplicationProperties.IsoDb.GetPositionByISO(channel.Position); _testObject = ApplicationProperties.IsoDb.GetTestObjectByIso(channel.Test_Object); } public void Commit(bool bNotify) { if (null == Channel) { Channel = new MMEPossibleChannels(-1, TypeString, TestObject.Test_Object, Position.Position, MainLocation?.Trans_Main_Loc, FinLoc1.Fine_Loc_1, FinLoc2.FINE_LOC_2, FinLoc3.FINE_LOC_3, PhysicalDimension.Physical_Dimension, Direction?.Direction, FilterClass?.Filter_Class, Text1, Text1, 1, DateTime.Now, Remarks, false, "", "", DateTime.Now, string.Format("created in DataPRO by {0}", ApplicationProperties.CurrentUser.UserName), "", (int)MMEPossibleChannels.MMEChannelTypes.SQL); } else { Channel = new MMEPossibleChannels(Channel.Id, TypeString, TestObject.Test_Object, Position.Position, MainLocation?.Trans_Main_Loc, FinLoc1.Fine_Loc_1, FinLoc2.FINE_LOC_2, FinLoc3.FINE_LOC_3, PhysicalDimension.Physical_Dimension, Direction?.Direction, FilterClass?.Filter_Class, Text1, Text1, 1, DateTime.Now, Remarks, false, "", "", DateTime.Now, string.Format("updated in DataPRO by {0}", ApplicationProperties.CurrentUser.UserName), "", (int)MMEPossibleChannels.MMEChannelTypes.SQL); } ApplicationProperties.IsoDb.Commit(Channel, bNotify); } public MMEPossibleChannels GetISOChannelForCommit() { if (null == Channel) { Channel = new MMEPossibleChannels(-1, TypeString, TestObject.Test_Object, Position.Position, MainLocation.Trans_Main_Loc, FinLoc1.Fine_Loc_1, FinLoc2.FINE_LOC_2, FinLoc3.FINE_LOC_3, PhysicalDimension.Physical_Dimension, Direction.Direction, FilterClass.Filter_Class, Text1, Text1, 1, DateTime.Now, Remarks, false, "", "", DateTime.Now, string.Format("created in DataPRO by {0}", ApplicationProperties.CurrentUser.UserName), "", (int)MMEPossibleChannels.MMEChannelTypes.SQL); } else { Channel = new MMEPossibleChannels(Channel.Id, TypeString, TestObject.Test_Object, Position.Position, MainLocation.Trans_Main_Loc, FinLoc1.Fine_Loc_1, FinLoc2.FINE_LOC_2, FinLoc3.FINE_LOC_3, PhysicalDimension.Physical_Dimension, Direction.Direction, FilterClass.Filter_Class, Text1, Text1, 1, DateTime.Now, Remarks, false, "", "", DateTime.Now, string.Format("updated in DataPRO by {0}", ApplicationProperties.CurrentUser.UserName), "", (int)MMEPossibleChannels.MMEChannelTypes.SQL); } return Channel; } public int CompareTo(CustomChannel other) { return Equals(this, other) ? 0 : string.Compare(Text1, other.Text1, StringComparison.Ordinal); } public string ISOCode => TestObject.Test_Object + Position.Position + MainLocation.Trans_Main_Loc + FinLoc1.Fine_Loc_1 + FinLoc2.FINE_LOC_2 + FinLoc3.FINE_LOC_3 + PhysicalDimension.Physical_Dimension + Direction.Direction + FilterClass.Filter_Class; } public class CustomChannelList : BasePropertyChanged { public enum Tags { AllChannels } private static readonly object LockObject = new object(); private static CustomChannelList _list; public static CustomChannelList List { get { lock (LockObject) { if (null == _list) { _list = new CustomChannelList(); } } return _list; } } public void ReloadAll() { lock (LockObject) { List._listChannels = null; //var app = Application.Current as App; //if (app == null){ return; } ApplicationProperties.IsoDb?.RefreshAllData(); List.PopulateChannelsIfNecessary(false); } } /// /// returns true if found, for a given isocode and/or channel id /// returns false otherwise /// /// /// public bool IsChannelExists(string isocode) { lock (LockObject) { PopulateChannelsIfNecessary(false); return ApplicationProperties.IsoDb.ContainsPossibleChannelWithISOCode(isocode); } } public bool IsChannelExists(string isocode, long id) { if (id == -1) { return IsChannelExists(isocode); } lock (LockObject) { PopulateChannelsIfNecessary(false); if (_dictChannels.ContainsKey(isocode)) { return _dictChannels[isocode].Channel.Id != id; } //still need to check isocode isn't in regular iso channels. return ApplicationProperties.IsoDb.ContainsPossibleChannelWithISOCode(isocode); } } /// /// returns a custom channel if found, for a given isocode /// returns null otherwise /// /// /// public CustomChannel GetChannelByISOCode(string isocode, bool careAboutTestTimeFields) { lock (LockObject) { PopulateChannelsIfNecessary(careAboutTestTimeFields); return _dictChannels.ContainsKey(isocode) ? _dictChannels[isocode] : null; } } public CustomChannel GetChannelByFullISOCode(string isocode) { lock (LockObject) { PopulateChannelsIfNecessary(false); if (_dictChannels.ContainsKey(isocode)) { return _dictChannels[isocode]; } var isocodeWithQuestionMarks = isocode.Substring(0, 15) + "?"; return DictChannelsContainsChannel(isocode, isocodeWithQuestionMarks) ? _dictChannels[isocodeWithQuestionMarks] : null; } } private bool DictChannelsContainsChannel(string isocode, string isocodeWithQuestionMarks) { if (!_dictChannels.ContainsKey(isocodeWithQuestionMarks)) return false; var temp = _dictChannels[isocodeWithQuestionMarks]; return temp.FilterClass.Filter_Class == isocode.Substring(15, 1); } /// /// returns a channel given a name, this should _ONLY_ be used in /// NON-ISO mode, as in other modes the name may not unique /// /// /// public CustomChannel GetChannelByName(string name) { lock (LockObject) { var ch = from c in AllChannels.AsParallel() where c.Channel.Text_L1 == name select c; return ch.Any() ? ch.First() : null; } } public CustomChannel GetChannel(long id) { lock (LockObject) { PopulateChannelsIfNecessary(false); var ch = from c in AllChannels where c.Channel.Id == id select c; var customChannels = ch as CustomChannel[] ?? ch.ToArray(); return customChannels.Any() ? customChannels[0] : null; } } private CustomChannelList() { } private Dictionary _dictChannels; private List _listChannels; public CustomChannel[] AllChannels { get { PopulateChannelsIfNecessary(false); return _listChannels.ToArray(); } } /// /// loads all calculated channels, if necessary /// private void PopulateChannelsIfNecessary(bool careAboutTestTimeFields) { lock (LockObject) { if (null != _listChannels) return; _listChannels = new List(); _dictChannels = new Dictionary(); foreach (var channel in ApplicationProperties.IsoDb.GetSQLPossibleChannels()) { var ch = new CustomChannel(channel); var iso = IsoCodeStatics.GetString(ch.Channel, careAboutTestTimeFields); if (_dictChannels.ContainsKey(iso)) continue; _listChannels.Add(ch); _dictChannels[iso] = ch; } _listChannels.Sort(); } } public void Delete(CustomChannel[] channels) { lock (LockObject) { var idx = 0; IDbCommand iCmd = null; try { foreach (var channel in channels) { for (var i = _listChannels.Count - 1; i >= 0; i--) { if (_listChannels[i].Channel.Id == channel.Channel.Id) { _listChannels.RemoveAt(i); if (null == iCmd) { iCmd = DbOperations.GetSQLCommand(true); iCmd.CommandText = DbOperations.BEGIN_STATEMENT; } iCmd.CommandText += $"DELETE FROM [{DbOperations.MMETables.MMEPossibleChannelsTable}] WHERE [{DbOperations.MMETables.MMEPossibleChannelsFields.ID}]=@{idx}_1;"; DbOperations.CreateParam(iCmd, $"@{idx}_1", SqlDbType.NVarChar, channel.Channel.Id); idx++; if (0 == idx % 2000) { iCmd.CommandText += DbOperations.COMMIT_STATEMENT; DbOperations.Connection.ExecuteCommand(iCmd); iCmd.Connection.Dispose(); iCmd.Dispose(); iCmd = null; } break; } } if (_dictChannels.ContainsKey(channel.Text1)) { _dictChannels.Remove(channel.ISOCode); } } } finally { if (null != iCmd) { iCmd.CommandText += DbOperations.COMMIT_STATEMENT; DbOperations.Connection.ExecuteCommand(iCmd); iCmd.Connection.Dispose(); iCmd.Dispose(); } } } } public void UpdateAll() { lock (LockObject) { _listChannels = null; _dictChannels = null; ApplicationProperties.IsoDb.RefreshAllData(); } OnPropertyChanged("AllChannels"); } /// /// this is a custom bulk insert of channels /// it doesn't do the validation (make sure channels don't already exist) /// and the clean the ordinary commit does (get the new id #) /// so ... it's good for bulk, but make sure to call updateall so the ids are updated /// /// public void Commit(CustomChannel[] channels) { MMEPossibleChannels.Commit(channels.Select(ch => ch.GetISOChannelForCommit()).ToArray()); } public void Commit(CustomChannel channel) { Commit(channel, true, true); } public void Commit(CustomChannel channel, bool bDoLookForExistingNameCheck, bool bNotify) { PopulateChannelsIfNecessary(false); var bFound = false; //don't consider the test fields when getting isocode (filter, position, test object) var key = IsoCodeStatics.GetString(channel.Channel, false); if (bDoLookForExistingNameCheck) { if (_dictChannels.ContainsKey(key)) { bFound = true; channel.Channel.SetId(_dictChannels[key].Channel.Id); } } if (bFound && !bNotify) { //bypass the ordinary commit as it will attempt to do an insert //and we just want to do an update. //I'm abusing the bNotify flag above to limit the scope of my changes as I know it's //false in batch updates where we aren't updating the list with every commit which is where the problem exists. //see http://fogbugz/fogbugz/default.asp?6713 2016-03-14 channel.Channel.Commit(); } else { channel.Commit(bNotify); } if (bNotify) { lock (LockObject) { _listChannels = null; _dictChannels = null; } OnPropertyChanged("AllChannels"); } else { if (!bFound) { lock (LockObject) { _listChannels.Add(channel); _dictChannels[key] = channel; } } } } } }