// Copyright (C) Stichting Deltares 2016. 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.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. /// The unique feature on which the items are validated on. public class ObservableUniqueItemCollectionWithSourcePath : Observable, IEnumerable where TObject : class where TFeature : class { private readonly List collection = new List(); private readonly Func getUniqueFeature; private readonly string typeDescriptor; private readonly string featureDescription; /// /// Instantiates a /// /// 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. public 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 TObject 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(TObject 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 (items == null) { throw new ArgumentNullException(nameof(items)); } if (filePath == null) { throw new ArgumentNullException(nameof(filePath)); } if (!IOUtils.IsValidFilePath(filePath)) { throw new ArgumentException($"'{filePath}' is not a valid filepath.", nameof(filePath)); } InternalValidateItems(items); SourcePath = filePath; collection.AddRange(items); } public IEnumerator GetEnumerator() { return collection.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } private void InternalValidateItems(IEnumerable items) { if (items.Contains(null)) { throw new ArgumentException("Collection cannot contain null.", nameof(items)); } ValidateItems(items); } /// /// Perform additional validations over . /// /// The items to validate. /// Throw an exception when validation fails. private void ValidateItems(IEnumerable items) { ValidateListOnDuplicateFeature(items, getUniqueFeature, typeDescriptor, featureDescription); } /// /// Validates the items of an based on their names. /// /// The feautre that needs to be validated on. /// The collection that needs to be validated. /// The feature of the items contained by the collection /// that needs to be validated on. /// The description of the item which was validated. /// The description of the feature which was validated on. /// Thrown when any parameters are null. /// Thrown when a duplicate item was found. private static void ValidateListOnDuplicateFeature(IEnumerable items, Func getUniqueFeature, string typeDescriptor, string featureDescription) { IEnumerable> duplicateItems = items.GroupBy(getUniqueFeature) .Where(group => group.Count() > 1); if (duplicateItems.Any()) { var duplicateFeatures = string.Join(", ", duplicateItems.Select(group => group.First())); string exceptionMessage = $"{typeDescriptor} moeten een unieke {featureDescription} hebben. Gevonden dubbele elementen: {duplicateFeatures}."; throw new ArgumentException(exceptionMessage); } } } }