using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.ComponentModel.Composition; using System.Linq; using System.Threading.Tasks; using System.Windows; using ChannelCodes.Model; using DTS.Common.Enums; using DTS.Common.Enums.Channels; using DTS.Common.Events; using DTS.Common.Events.ChannelCodes; using DTS.Common.Interface.Channels.ChannelCodes; using DTS.Common.Utilities.Logging; using Prism.Events; using Prism.Regions; using Unity; using DTS.Common.Interactivity; // ReSharper disable CheckNamespace // ReSharper disable MemberCanBePrivate.Global // ReSharper disable InconsistentNaming namespace ChannelCodes { /// /// /// this class handles ChannelCodesList functionality /// [PartCreationPolicy(CreationPolicy.Shared)] public class ChannelCodesListViewModel : IChannelCodesListViewModel { /// /// The ChannelCodeList view /// public IChannelCodesListView View { get; set; } private IEventAggregator _eventAggregator { get; } private IUnityContainer UnityContainer { get; } public InteractionRequest NotificationRequest { get; } public InteractionRequest ConfirmationRequest { get; } /// /// /// Occurs when a property value changes. /// public event PropertyChangedEventHandler PropertyChanged; public void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } #region constructors and initializers private static bool _bAddListeners = false; /// /// Creates a new instance of the ChannelCodesListViewModel /// /// /// 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 ChannelCodesListViewModel(IChannelCodesListView view, IRegionManager regionManager, IEventAggregator eventAggregator, IUnityContainer unityContainer) { ChannelCodesFunc = new Func>(GetAllChannels); View = view; View.DataContext = this; NotificationRequest = new InteractionRequest(); ConfirmationRequest = new InteractionRequest(); _eventAggregator = eventAggregator; UnityContainer = unityContainer; _eventAggregator.GetEvent().Subscribe(OnRaiseNotification); _eventAggregator.GetEvent() .Subscribe(OnBusyIndicatorNotification, ThreadOption.PublisherThread, true); //this is a hack, the app startup is calling this, then the app itself, we only want the //app itself to be handling the listeners if (_bAddListeners) { _eventAggregator.GetEvent().Subscribe(OnTextPasted); _eventAggregator.GetEvent() .Subscribe(OnChannelCodesCommitted, ThreadOption.PublisherThread, true); } _bAddListeners = true; } #endregion #region Methods private void OnChannelCodesCommitted(ChannelCodeCommittedEventArgs[] args) { //if there are no can args that the user can commit anyhow, we are done if (!Array.Exists(args, a => a.CanUserCommitChannelCodes)) { return; } var lookup = ChannelCodeType.GetChannelCodeTypeLookup(); var lookup2 = new Dictionary(); using (var e = lookup.GetEnumerator()) { while (e.MoveNext()) { switch (e.Current.Value) { case ChannelEnumsAndConstants.IsoCodeTypeString: lookup2[ChannelEnumsAndConstants.ChannelCodeType.ISO] = e.Current.Key; break; case ChannelEnumsAndConstants.UserCodeTypeString: lookup2[ChannelEnumsAndConstants.ChannelCodeType.User] = e.Current.Key; break; } } } var codes = ChannelCode.ChannelCodes; var isoLookup = new Dictionary>(); var userLookup = new Dictionary>(); foreach (var code in codes) { switch (code.CodeType) { case ChannelEnumsAndConstants.ChannelCodeType.ISO: if (!isoLookup.ContainsKey(code.Code)) { isoLookup[code.Code] = new HashSet(); } isoLookup[code.Code].Add(code.Name); break; case ChannelEnumsAndConstants.ChannelCodeType.User: if (!userLookup.ContainsKey(code.Code)) { userLookup[code.Code] = new HashSet(); } userLookup[code.Code].Add(code.Name); break; } } foreach (var arg in args) { if (!arg.CanUserCommitChannelCodes) { continue; } if (string.IsNullOrWhiteSpace(arg.Code) || string.IsNullOrWhiteSpace(arg.Name)) { continue; } var newCode = new ChannelCode() { Code = arg.Code, CodeType = arg.ChannelCodeType, Name = arg.Name }; switch (arg.ChannelCodeType) { case ChannelEnumsAndConstants.ChannelCodeType.ISO: if (!isoLookup.ContainsKey(arg.Code)) { isoLookup[arg.Code] = new HashSet(); } if (!isoLookup[arg.Code].Contains(arg.Name)) { newCode.Insert(lookup2); isoLookup[arg.Code].Add(arg.Name); } break; case ChannelEnumsAndConstants.ChannelCodeType.User: if (!userLookup.ContainsKey(arg.Code)) { userLookup[arg.Code] = new HashSet(); } if (!userLookup[arg.Code].Contains(arg.Name)) { newCode.Insert(lookup2); userLookup[arg.Code].Add(arg.Name); } break; } } } private void OnTextPasted(ITextPastedEventArgs args) { if (args.Id != ChannelCode.PASTE_ID) { return; } if (!(args.Sender is IChannelCode channelCode)) { return; } switch (ViewMode) { case ViewModes.ISO: { PasteIso(channelCode, args.Text, args.Tag); var last = ISOChannelCodes.Last(); if (!string.IsNullOrWhiteSpace(last.Code) || !string.IsNullOrWhiteSpace(last.Name)) { MarkModifiedISO(last); } } break; case ViewModes.User: { PasteUser(channelCode, args.Text, args.Tag); var last = UserChannelCodes.Last(); if (!string.IsNullOrWhiteSpace(last.Code) || !string.IsNullOrWhiteSpace(last.Name)) { MarkModifiedUser(last); } } break; default: throw new ArgumentOutOfRangeException(); } _eventAggregator.GetEvent() .Publish(new PageModifiedArg(PageModifiedArg.Status.Modified, Page)); } private void PasteIso(IChannelCode channelCode, string text, object tag) { bool bCode = tag.Equals("ISOCode"); var channelCodes = ParseText(text, true, bCode, out var oneColumn); var index = ISOChannelCodes.IndexOf(channelCode); foreach (var code in channelCodes) { if (index > (ISOChannelCodes.Count - 1)) { AllISOChannelCodes.Add(code); index++; } else { var ch = ISOChannelCodes[index++]; if (oneColumn) { ch.Code = bCode ? code.Code : ch.Code; ch.Name = bCode ? ch.Name : code.Name; } else { ch.Code = code.Code; ch.Name = code.Name; } } } SortIso(_isoSortField, false); FilterIso(); } private void FilterIso() { ISOChannelCodes.Clear(); foreach (var channel in AllISOChannelCodes) { if (string.IsNullOrWhiteSpace(channel.Code) && string.IsNullOrWhiteSpace(channel.Name)) { ISOChannelCodes.Add(channel); continue; } if (_searchTermForField.ContainsKey(Fields.IsoChannelName)) { var term = _searchTermForField[Fields.IsoChannelName]; if (!string.IsNullOrEmpty(term)) { if (channel.Name.IndexOf(term, StringComparison.CurrentCultureIgnoreCase) < 0) { continue; } } } if (_searchTermForField.ContainsKey(Fields.IsoCode)) { var term = _searchTermForField[Fields.IsoCode]; if (!string.IsNullOrWhiteSpace(term)) { if (channel.Code.IndexOf(term, StringComparison.CurrentCultureIgnoreCase) < 0) { continue; } } } ISOChannelCodes.Add(channel); } } private void FilterUser() { UserChannelCodes.Clear(); foreach (var channel in AllUserChannelCodes) { if (string.IsNullOrWhiteSpace(channel.Code) && string.IsNullOrWhiteSpace(channel.Name)) { UserChannelCodes.Add(channel); continue; } if (_searchTermForField.ContainsKey(Fields.UserChannelName)) { var term = _searchTermForField[Fields.UserChannelName]; if (!string.IsNullOrEmpty(term)) { if (channel.Name.IndexOf(term, StringComparison.CurrentCultureIgnoreCase) < 0) { continue; } } } if (_searchTermForField.ContainsKey(Fields.UserCode)) { var term = _searchTermForField[Fields.UserCode]; if (!string.IsNullOrWhiteSpace(term)) { if (channel.Code.IndexOf(term, StringComparison.CurrentCultureIgnoreCase) < 0) { continue; } } } UserChannelCodes.Add(channel); } } public class ChannelComparer : IComparer { public Fields SortField { get; set; } public bool SortAscending { get; set; } public int Compare(IChannelCode left, IChannelCode right) { if (left == right) { return 0; } var a = left; var b = right; if (string.IsNullOrWhiteSpace(a.Code) && string.IsNullOrWhiteSpace(a.Name)) { return 1; } if (string.IsNullOrWhiteSpace(b.Code) && string.IsNullOrWhiteSpace(b.Name)) { return -1; } if (!SortAscending) { a = right; b = left; } if (null == a) { return -1; } if (null == b) { return 1; } switch (SortField) { case Fields.IsoCode: case Fields.UserCode: return DTS.Common.Utilities.NaturalStringComparer.StaticCompare(a.Code.ToUpper(), b.Code.ToUpper()); case Fields.IsoChannelName: case Fields.UserChannelName: return DTS.Common.Utilities.NaturalStringComparer.StaticCompare(a.Name.ToUpper(), b.Name.ToUpper()); default: throw new ArgumentOutOfRangeException(); } } } private void SortIso(Fields field, bool bColumnClick) { if (bColumnClick) { if (field != _isoSortField) { _isoSortField = field; _isoSortAscending = true; } else { _isoSortAscending = !_isoSortAscending; } } var comparer = new ChannelComparer(); comparer.SortField = _isoSortField; comparer.SortAscending = _isoSortAscending; AllISOChannelCodes.Sort(comparer); } private void SortUser(Fields field, bool bColumnClick) { if (bColumnClick) { if (field != _userSortField) { _userSortField = field; _userSortAscending = true; } else { _userSortAscending = !_userSortAscending; } } var comparer = new ChannelComparer(); comparer.SortField = _userSortField; comparer.SortAscending = _userSortAscending; AllUserChannelCodes.Sort(comparer); } private void PasteUser(IChannelCode channelCode, string text, object tag) { bool bCode = tag.Equals("UserCode"); var channelCodes = ParseText(text, true, bCode, out var oneColumn); int index = UserChannelCodes.IndexOf(channelCode); foreach (var code in channelCodes) { if (index > (UserChannelCodes.Count - 1)) { AllUserChannelCodes.Add(code); index++; } else { var ch = UserChannelCodes[index++]; if (oneColumn) { ch.Code = bCode ? code.Code : ch.Code; ch.Name = bCode ? ch.Name : code.Name; } else { ch.Code = code.Code; ch.Name = code.Name; } } } SortUser(_userSortField, false); FilterUser(); } private IChannelCode[] ParseText(string text, bool bIso, bool bCode, out bool oneColumn) { oneColumn = false; var list = new List(); var errors = new List(); var lines = text.Split(new[] { Environment.NewLine }, StringSplitOptions.None); for (var i = 0; i < lines.Length; i++) { var line = lines[i]; if (string.IsNullOrWhiteSpace(line)) { continue; } var tokens = line.Split(','); if (tokens.Length != 2) { tokens = line.Split('\t'); } if (tokens.Length != 2) { tokens = line.Split(';'); } var newCode = new ChannelCode(); newCode.CodeType = bIso ? ChannelEnumsAndConstants.ChannelCodeType.ISO : ChannelEnumsAndConstants.ChannelCodeType.User; if (tokens.Length == 1) { oneColumn = true; if (bCode) { newCode.Code = tokens[0]; newCode.Name = ""; } else { newCode.Name = tokens[0]; newCode.Code = ""; } } else if (tokens.Length == 2) { newCode.Code = tokens[0]; newCode.Name = tokens[1]; } else { errors.Add(string.Format(Resources.StringResources.InvalidLine, 1 + i)); continue; } if (bIso) { if (newCode.Code.Length > 16) { newCode.Code = newCode.Code.Substring(0, 16); } } list.Add(newCode); } return list.ToArray(); } public void Remove(IChannelCode channel) { if (channel.CodeType == ChannelEnumsAndConstants.ChannelCodeType.ISO) { RemoveISOChannel(channel); } else { RemoveUserChannel(channel); } _eventAggregator.GetEvent() .Publish(new PageModifiedArg(PageModifiedArg.Status.Modified, Page)); } private void RemoveUserChannel(IChannelCode channel) { if (UserChannelCodes.ToList().Last() == channel) { var newCh = new ChannelCode { CodeType = ChannelEnumsAndConstants.ChannelCodeType.User }; UserChannelCodes.Add(newCh); AllUserChannelCodes.Add(newCh); } AllUserChannelCodes.Remove(channel); UserChannelCodes.Remove(channel); OnPropertyChanged("UserChannelCodes"); } private void RemoveISOChannel(IChannelCode channel) { if (ISOChannelCodes.ToList().Last() == channel) { var newCh = new ChannelCode { CodeType = ChannelEnumsAndConstants.ChannelCodeType.ISO }; AllISOChannelCodes.Add(newCh); ISOChannelCodes.Add(newCh); } ISOChannelCodes.Remove(channel); AllISOChannelCodes.Remove(channel); OnPropertyChanged("ISOChannelCodes"); } public void MarkModified(IChannelCode channel) { if (channel.CodeType == ChannelEnumsAndConstants.ChannelCodeType.ISO) { MarkModifiedISO(channel); } else { MarkModifiedUser(channel); } _eventAggregator.GetEvent() .Publish(new PageModifiedArg(PageModifiedArg.Status.Modified, Page)); } private void MarkModifiedISO(IChannelCode channel) { if (ISOChannelCodes.ToList().Last() == channel) { var newCh = new ChannelCode { CodeType = ChannelEnumsAndConstants.ChannelCodeType.ISO }; ISOChannelCodes.Add(newCh); AllISOChannelCodes.Add(newCh); OnPropertyChanged("ISOChannelCodes"); } } private void MarkModifiedUser(IChannelCode channel) { if (UserChannelCodes.ToList().Last() == channel) { var newCh = new ChannelCode { CodeType = ChannelEnumsAndConstants.ChannelCodeType.User }; UserChannelCodes.Add(newCh); AllUserChannelCodes.Add(newCh); OnPropertyChanged("UserChannelCodes"); } } public void Unset() { AllISOChannelCodes.Clear(); AllUserChannelCodes.Clear(); UserChannelCodes.Clear(); ISOChannelCodes.Clear(); OnPropertyChanged("UserChannelCodes"); OnPropertyChanged("ISOChannelCodes"); } /// /// sets the page this vm is in, this is used in some notifications to identify to consumers /// which consumer should process the event /// /// public void SetPage(object page) { Page = page; } public void OnSetActive() { AllUserChannelCodes.Clear(); AllISOChannelCodes.Clear(); try { var lookup = ChannelCodeType.GetChannelCodeTypeLookup(); var existingChannelCodes = ChannelCode.GetExistingChannelCodes(lookup); foreach (var existingChannelCode in existingChannelCodes) { if (existingChannelCode.CodeType == ChannelEnumsAndConstants.ChannelCodeType.ISO) { AllISOChannelCodes.Add(existingChannelCode); } else { AllUserChannelCodes.Add(existingChannelCode); } } AllISOChannelCodes.Add(new ChannelCode { CodeType = ChannelEnumsAndConstants.ChannelCodeType.ISO }); AllUserChannelCodes.Add(new ChannelCode { CodeType = ChannelEnumsAndConstants.ChannelCodeType.User }); SortIso(_isoSortField, false); SortUser(_userSortField, false); FilterIso(); FilterUser(); } catch (Exception ex) { APILogger.Log(ex); ReportErrors(new[] { ex.Message }); } } public void Cleanup() { } public Task CleanupAsync() { return Task.CompletedTask; } public void Initialize() { } public void Initialize(object parameter) { } public void Initialize(object parameter, object model) { } public Task InitializeAsync() { return Task.CompletedTask; } public Task InitializeAsync(object parameter) { return Task.CompletedTask; } public void Activated() { } /// /// Private Event handler for RaiseNotification event. /// private void OnBusyIndicatorNotification(bool eventArg) { IsBusy = eventArg; } /// /// Private Event handler for RaiseNotification event. /// private void OnRaiseNotification(NotificationContentEventArgs eventArgsWithTitle) { // The NotificationRequest.Raise triggers the Invoke() method of the PopupWindowAction object to show the NotificationWindow window // Notification object expects a NotificationContentEventArgsWithoutTitle object and a Title string. var eventArgsWithoutTitle = new NotificationContentEventArgs(eventArgsWithTitle.Message, "", eventArgsWithTitle.Image, string.Empty); NotificationRequest.Raise(new Notification { Content = eventArgsWithoutTitle, Title = eventArgsWithTitle.Title }); } public void ReportErrors(string[] errors) { _eventAggregator.GetEvent().Publish(new PageErrorArg(errors, Page)); } public bool Save() { try { //note we use multiple steps here to avoid name conflicts between existing/new/deleted channel codes //step 1, delete any channels not needed anymore var lookup = ChannelCodeType.GetChannelCodeTypeLookup(); var lookup2 = new Dictionary(); using (var e = lookup.GetEnumerator()) { while (e.MoveNext()) { switch (e.Current.Value) { case ChannelEnumsAndConstants.IsoCodeTypeString: lookup2[ChannelEnumsAndConstants.ChannelCodeType.ISO] = e.Current.Key; break; case ChannelEnumsAndConstants.UserCodeTypeString: lookup2[ChannelEnumsAndConstants.ChannelCodeType.User] = e.Current.Key; break; } } } var channelCodes = new List(); channelCodes.AddRange(AllISOChannelCodes); channelCodes.AddRange(AllUserChannelCodes); var existingChannelCodes = ChannelCode.GetExistingChannelCodes(lookup); var keptIds = new HashSet(); foreach (var channelCode in channelCodes) { if (!(channelCode is ChannelCode cc)) { continue; } if (cc.HasValidId()) { keptIds.Add(cc.Id); } } var toDelete = (from channelCode in existingChannelCodes where !keptIds.Contains(channelCode.Id) select channelCode).ToList(); if (toDelete.Any()) { foreach (var cc in toDelete) { if (cc.HasValidId()) { cc.Delete(); } } } //step 2, update any existing new channels foreach (var channelCode in channelCodes) { if (!(channelCode is ChannelCode cc)) { continue; } if (cc.HasValidId()) { cc.Save(lookup2); } } //step 3, add new channels foreach (var channelCode in channelCodes) { if (!(channelCode is ChannelCode cc)) { continue; } if (!cc.HasValidId() && !cc.IsBlank()) { cc.Insert(lookup2); } } //step 4, update list ? not really necessary since we've updated the ids already in the insert function above. } catch (Exception ex) { _eventAggregator.GetEvent().Publish(new PageErrorArg(new[] { ex.Message }, Page)); return false; } _eventAggregator.GetEvent() .Publish(new PageModifiedArg(PageModifiedArg.Status.Saved, Page)); return true; } #endregion #region Properties public List AllISOChannelCodes { get; set; } = new List(); public List AllUserChannelCodes { get; set; } = new List(); public ObservableCollection ISOChannelCodes { get; set; } = new ObservableCollection(); public ObservableCollection UserChannelCodes { get; set; } = new ObservableCollection(); private IReadOnlyDictionary> GetDictionary(IChannelCode[] channels) { var dictionary = new Dictionary>(); foreach (var channelCode in channels) { var code = channelCode.Code; var name = channelCode.Name; if (string.IsNullOrWhiteSpace(code) || string.IsNullOrWhiteSpace(name)) { continue; } if (!dictionary.ContainsKey(code)) { dictionary[code] = new List(); } dictionary[code].Add(channelCode); } return dictionary; } public void ValidateISO(ref List errors, ref List warnings) { var codeToChannels = GetDictionary(AllISOChannelCodes.ToArray()); if (!codeToChannels.Any()) return; foreach (var channelCode in AllISOChannelCodes) { CheckChannelCode(ref errors, ref warnings, channelCode, true, codeToChannels); } } public void ValidateUser(ref List errors, ref List warnings) { var codeToChannels = GetDictionary(AllUserChannelCodes.ToArray()); foreach (var channelCode in AllUserChannelCodes) { CheckChannelCode(ref errors, ref warnings, channelCode, false, codeToChannels); } } public bool Validate(bool bDisplayWindow) { var errors = new List(); var warnings = new List(); ValidateISO(ref errors, ref warnings); ValidateUser(ref errors, ref warnings); if (bDisplayWindow && (errors.Any() || warnings.Any())) { var list = new List(errors.ToArray()); list.AddRange(warnings.ToArray()); _eventAggregator.GetEvent().Publish(new PageErrorArg(list.ToArray(), Page)); } return 0 == errors.Count; } public void CopySelected() { switch (ViewMode) { case ViewModes.ISO: CopySelectedISOCodes(); break; case ViewModes.User: CopySelectedUserCodes(); break; default: throw new ArgumentOutOfRangeException(); } _eventAggregator.GetEvent() .Publish(new PageModifiedArg(PageModifiedArg.Status.Modified, Page)); } private void CopySelectedUserCodes() { if (null == _selectedUserItems) { return; } foreach (var item in _selectedUserItems) { AllUserChannelCodes.Insert(AllUserChannelCodes.Count - 1, new ChannelCode(item)); } SortUser(_userSortField, false); FilterUser(); } private void CopySelectedISOCodes() { if (null == _selectedISOItems) { return; } foreach (var item in _selectedISOItems) { var newCh = new ChannelCode(item); AllISOChannelCodes.Insert(AllISOChannelCodes.Count - 1, newCh); } SortIso(_isoSortField, false); FilterIso(); } public IChannelCode[] SelectedCodes { get { switch (ViewMode) { case ViewModes.ISO: return GetSelectedISOCodes(); case ViewModes.User: return GetSelectedUserCodes(); default: throw new InvalidEnumArgumentException($"Unknown viewmode: SelectedCodes-{ViewMode}"); } } } private IChannelCode[] GetSelectedISOCodes() { //FB 18906 Prevent exception when there is no selection return _selectedISOItems?.ToArray(); } private IChannelCode[] GetSelectedUserCodes() { return _selectedUserItems?.ToArray(); } public void DeleteSelected() { switch (ViewMode) { case ViewModes.ISO: DeleteSelectedISOCodes(); break; case ViewModes.User: DeleteSelectedUserCodes(); break; default: throw new ArgumentOutOfRangeException(); } _eventAggregator.GetEvent() .Publish(new PageModifiedArg(PageModifiedArg.Status.Modified, Page)); } private void DeleteSelectedUserCodes() { if (null == _selectedUserItems) { return; } bool bAddLast = false; foreach (var code in _selectedUserItems) { if (UserChannelCodes.Last() == code) { bAddLast = true; } UserChannelCodes.Remove(code); AllUserChannelCodes.Remove(code); } if (bAddLast) { var newCh = new ChannelCode { CodeType = ChannelEnumsAndConstants.ChannelCodeType.User }; UserChannelCodes.Add(newCh); AllUserChannelCodes.Add(newCh); } _selectedUserItems = null; OnPropertyChanged("UserChannelCodes"); } private void DeleteSelectedISOCodes() { if (null == _selectedISOItems) { return; } bool bAddLast = false; foreach (var code in _selectedISOItems) { if (ISOChannelCodes.Last() == code) { bAddLast = true; } ISOChannelCodes.Remove(code); AllISOChannelCodes.Remove(code); } if (bAddLast) { var newCh = new ChannelCode { CodeType = ChannelEnumsAndConstants.ChannelCodeType.ISO }; ISOChannelCodes.Add(newCh); AllISOChannelCodes.Add(newCh); } _selectedISOItems = null; OnPropertyChanged("ISOChannelCodes"); } public void SetISOSelection(IChannelCode[] channelCodes) { //FB 18906 if the the list is empty, do not set _selectedISOItems if (!channelCodes.Any()) { return; } _selectedISOItems = channelCodes; if (ViewMode == ViewModes.ISO) { var count = 0; if (null != channelCodes) { count = channelCodes.Length; } NotifySelectionChanged(count); } } private void NotifySelectionChanged(int count) { _eventAggregator.GetEvent().Publish(new PageSelectionChangedArg(count, Page)); } public void SetUserSelection(IChannelCode[] channelCodes) { //FB 18906 if the the list is empty, do not set _selectedISOItems if (!channelCodes.Any()) { return; } _selectedUserItems = channelCodes; if (ViewMode == ViewModes.User) { var count = 0; if (null != channelCodes) { count = channelCodes.Length; } NotifySelectionChanged(count); } } private static void CheckChannelCode(ref List errors, ref List warnings, IChannelCode channelCode, bool iso, IReadOnlyDictionary> channelCodeToChannels) { var channelCodeEmpty = string.IsNullOrWhiteSpace(channelCode.Code); var channelNameEmpty = string.IsNullOrWhiteSpace(channelCode.Name); var itemStatus = UIItemStatus.None; if (channelCodeEmpty && channelNameEmpty) { channelCode.ItemStatus = UIItemStatus.None; return; } if (channelCodeEmpty) { var msg = iso ? Resources.StringResources.MissingISOCode : Resources.StringResources.MissingUserCode; msg = string.Format(msg, channelCode.Name); if (!errors.Contains(msg)) { errors.Add(msg); itemStatus = UIItemStatus.Error; } } else if (channelNameEmpty) { var msg = iso ? Resources.StringResources.MissingISOChannelName : Resources.StringResources.MissingUserChannelName; msg = string.Format(msg, channelCode.Code); if (!errors.Contains(msg)) { itemStatus = UIItemStatus.Error; errors.Add(msg); } } else { var list = channelCodeToChannels[channelCode.Code]; if (list.Count > 1) { //either duplicated code or duplicated everything var matches = from ch in list where ch.Name == channelCode.Name && ch != channelCode select ch; if (matches.Any()) { var msg = iso ? Resources.StringResources.DuplicateISOChannelCode : Resources.StringResources.DuplicateUserChannelCode; if (!string.IsNullOrWhiteSpace(channelCode.Name)) { msg = string.Format(msg, channelCode.Name); } else { msg = string.Format(msg, channelCode.Code); } if (!errors.Contains(msg)) { errors.Add(msg); } itemStatus = UIItemStatus.Error; } } } channelCode.ItemStatus = itemStatus; } public void Filter(object columnTag, string searchTerm) { if (!(columnTag is string s)) { return; } switch (s) { case "ISOCode": _searchTermForField[Fields.IsoCode] = searchTerm; FilterIso(); break; case "ISOChannelName": _searchTermForField[Fields.IsoChannelName] = searchTerm; FilterIso(); break; case "UserCode": _searchTermForField[Fields.UserCode] = searchTerm; FilterUser(); break; case "UserChannelName": _searchTermForField[Fields.UserChannelName] = searchTerm; FilterUser(); break; } } public void Sort(object columnTag, bool bColumnClick) { if (!(columnTag is string s)) { return; } switch (s) { case "ISOCode": SortIso(Fields.IsoCode, true); FilterIso(); break; case "ISOChannelName": SortIso(Fields.IsoChannelName, true); FilterIso(); break; case "UserCode": SortUser(Fields.UserCode, true); FilterUser(); break; case "UserChannelName": SortUser(Fields.UserChannelName, true); FilterUser(); break; } } public enum Fields { IsoCode, IsoChannelName, UserCode, UserChannelName } private Fields _isoSortField = Fields.IsoCode; private bool _isoSortAscending = true; private Fields _userSortField = Fields.UserCode; private bool _userSortAscending = true; private readonly Dictionary _searchTermForField = new Dictionary(); private IChannelCode[] _selectedISOItems = null; private IChannelCode[] _selectedUserItems = null; public object Page { get; private set; } public bool IsDirty { get; private set; } private bool _isBusy = false; public bool IsBusy { get => _isBusy; set { _isBusy = value; OnPropertyChanged("IsBusy"); } } private bool _isMenuIncluded; public bool IsMenuIncluded { get => _isMenuIncluded; set { _isMenuIncluded = value; OnPropertyChanged("IsMenuIncluded"); } } private bool _isNavigationIncluded; public bool IsNavigationIncluded { get => _isNavigationIncluded; set { _isNavigationIncluded = value; OnPropertyChanged("IsNavigationIncluded"); } } //FB14098: Ability to disable editing View if user doesn't have the permissions, but still view current data private bool _isReadOnly; public bool IsReadOnly { get => _isReadOnly; set { _isReadOnly = value; OnPropertyChanged("IsReadOnly"); } } #endregion Properties public enum ViewModes { ISO, User } private ViewModes _viewMode = ViewModes.ISO; public ViewModes ViewMode { get => _viewMode; set { _viewMode = value; OnPropertyChanged("ISOVisibility"); OnPropertyChanged("UserVisibility"); var count = 0; switch (value) { case ViewModes.ISO: if (null != _selectedISOItems) { count = _selectedISOItems.Length; } NotifySelectionChanged(count); break; case ViewModes.User: if (null != _selectedUserItems) { count = _selectedUserItems.Length; } NotifySelectionChanged(count); break; default: throw new ArgumentOutOfRangeException(nameof(value), value, null); } } } public Visibility ISOVisibility => ViewMode == ViewModes.ISO ? Visibility.Visible : Visibility.Collapsed; public Visibility UserVisibility => ViewMode == ViewModes.User ? Visibility.Visible : Visibility.Collapsed; private IList GetAllChannels() { return ChannelCode.ChannelCodes; } public Func> ChannelCodesFunc { get; } private bool _showISOStringBuilder = true; public bool ShowISOStringBuilder { get => _showISOStringBuilder; set { _showISOStringBuilder = value; OnPropertyChanged("ShowISOStringBuilder"); } } private bool _uniqueISOCodesRequired; public bool UniqueISOCodesRequired { get => _uniqueISOCodesRequired; set { _uniqueISOCodesRequired = value; OnPropertyChanged("UniqueISOCodesRequired"); } } private bool _showChannelCodeLookupHelper = true; public bool ShowChannelCodeLookupHelper { get => _showChannelCodeLookupHelper; set { _showChannelCodeLookupHelper = value; OnPropertyChanged("ShowChannelCodeLookupHelper"); } } #region Commands #endregion } }