// Copyright (C) Stichting Deltares 2017. All rights reserved. // // This file is part of Ringtoets. // // Ringtoets is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this program. If not, see . // // All names, logos, and references to "Deltares" are registered trademarks of // Stichting Deltares and remain full property of Stichting Deltares at all times. // All rights reserved. using System; using System.Collections; using System.Collections.Generic; using System.Linq; using Core.Common.Base.Properties; using Core.Common.Utils; namespace Core.Common.Base { /// /// A collection to store unique elements based on their feature and the source path /// they were imported from. /// /// The type of elements in the collection. public abstract class ObservableUniqueItemCollectionWithSourcePath : Observable, IEnumerable where TElement : class { private readonly List collection = new List(); private readonly Func getUniqueFeature; private readonly string typeDescriptor; private readonly string featureDescription; /// /// Creates a new instance of . /// /// A function to retrieve the unique feature of the items it stores. /// The description of the item that is validated. /// The description of the feature of the item to be validated on. protected ObservableUniqueItemCollectionWithSourcePath(Func getUniqueFeature, string typeDescriptor, string featureDescription) { if (getUniqueFeature == null) { throw new ArgumentNullException(nameof(getUniqueFeature)); } if (typeDescriptor == null) { throw new ArgumentNullException(nameof(typeDescriptor)); } if (featureDescription == null) { throw new ArgumentNullException(nameof(featureDescription)); } this.getUniqueFeature = getUniqueFeature; this.typeDescriptor = typeDescriptor; this.featureDescription = featureDescription; } /// /// Gets the element at index in the collection. /// /// The index. /// The element at index in the collection. /// Thrown when is not /// between [0, ) public TElement this[int i] { get { return collection[i]; } } /// /// Gets the amount of items stored in the collection. /// public int Count { get { return collection.Count; } } /// /// Gets the last known file path from which the elements were imported. /// /// The path where the elements originate /// from, or null if the collection is cleared. public string SourcePath { get; private set; } /// /// Removes the first occurrence of in the collection. /// /// The item of type to be removed. /// True if the was successfully removed from the collection; /// False if otherwise or if the was not found in the collection. public bool Remove(TElement item) { bool remove = collection.Remove(item); if (remove && Count == 0) { SourcePath = null; } return remove; } /// /// Clears the imported items in the collection and the . /// public void Clear() { SourcePath = null; collection.Clear(); } /// /// Adds all elements originating from a source file. /// /// The elements to add /// The path to the source file. /// Thrown when any input argument is null. /// Thrown when: /// /// contains null. /// is not a valid file path. /// an element in is invalid. /// /// public void AddRange(IEnumerable items, string filePath) { if (filePath == null) { throw new ArgumentNullException(nameof(filePath)); } if (!IOUtils.IsValidFilePath(filePath) && filePath.Length > 0) { throw new ArgumentException($@"'{filePath}' is not a valid file path.", nameof(filePath)); } InternalValidateItems(items); SourcePath = filePath; collection.AddRange(items); } public IEnumerator GetEnumerator() { return collection.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } /// /// Validates the items of based on their feature. /// /// The items to validate. /// Thrown when is /// null. /// Thrown when /// /// one of the items is null /// when a duplicate item was found. /// /// private void InternalValidateItems(IEnumerable items) { if (items == null) { throw new ArgumentNullException(nameof(items)); } if (items.Contains(null)) { throw new ArgumentException(@"Collection cannot contain null.", nameof(items)); } IEnumerable> duplicateItems = items.Concat(collection).GroupBy(getUniqueFeature) .Where(group => group.Count() > 1); if (duplicateItems.Any()) { string duplicateFeatures = string.Join(", ", duplicateItems.Select(group => getUniqueFeature(group.First()))); string exceptionMessage = string.Format( Resources.ObservableUniqueItemCollectionWithSourcePath_ValidateItems_TypeDescriptor_0_must_have_unique_FeatureDescription_1_Found_duplicate_items_DuplicateFeatures_2, typeDescriptor, featureDescription, duplicateFeatures); throw new ArgumentException(exceptionMessage); } } } }