// 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);
}
}
}
}