// 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 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 General Public License for more details. // // You should have received a copy of the GNU 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.Generic; using System.Linq; using Core.Common.Base; using Core.Common.Utils; using Ringtoets.Common.Data.FailureMechanism; namespace Ringtoets.Common.Data.UpdateDataStrategies { /// /// Strategy for updating the current collection and dependent data with imported data: /// /// Adds imported items that are not part of the current collection. /// Removes items that are part of the current collection, but are not part of the imported item collection. /// Updates the items that are part of the current collection and are part of the imported item collection. /// /// /// The target data type. /// The feature of the target data that should be validated on for the uniqueness of elements. /// The failure mechanism in which the target collection should be updated. public abstract class UpdateDataStrategyBase where TTargetData : class where TFeature : class where TFailureMechanism : IFailureMechanism { protected TFailureMechanism failureMechanism; private readonly IEqualityComparer equalityComparer; /// /// Instantiates a object. /// /// The failure mechanism which needs to be updated. /// The comparer which should be used to determine when two objects are equal /// Thrown when any input parameter is null. protected UpdateDataStrategyBase(TFailureMechanism failureMechanism, IEqualityComparer equalityComparer) { if (failureMechanism == null) { throw new ArgumentNullException(nameof(failureMechanism)); } if (equalityComparer == null) { throw new ArgumentNullException(nameof(equalityComparer)); } this.equalityComparer = equalityComparer; this.failureMechanism = failureMechanism; } /// /// Updates the (dependent) objects with new data from the imported data. /// /// Objects that need to be updated. /// The data that was imported. /// An with affected objects. /// Thrown when duplicate items are found. protected abstract IEnumerable UpdateData(IEnumerable objectsToUpdate, IEnumerable importedDataCollection); /// /// Removes the objects and their dependent data. /// /// The objects that are removed. /// An with affected objects. protected abstract IEnumerable RemoveData(IEnumerable removedObjects); /// /// Updates the items and their associated data within the target collection with the data contained /// in the imported data collection. /// /// The target collection that needs to be updated. /// The imported data collection that is used to update /// the . /// The source file path. /// A of affected objects. /// Thrown when any of the input parameters are null. /// Thrown when duplicate items are being added to the /// . /// Thrown when duplicate items are found during the /// update of the items to be updatd in the . protected IEnumerable UpdateTargetCollectionData(ObservableUniqueItemCollectionWithSourcePath targetDataCollection, IEnumerable importedDataCollection, string sourceFilePath) { if (targetDataCollection == null) { throw new ArgumentNullException(nameof(targetDataCollection)); } if (importedDataCollection == null) { throw new ArgumentNullException(nameof(importedDataCollection)); } if (sourceFilePath == null) { throw new ArgumentNullException(nameof(sourceFilePath)); } return ModifyDataCollection(targetDataCollection, importedDataCollection, sourceFilePath); } /// /// Identifies which models were changed, removed and added to the target collection /// when compared with the imported data and performs the necessary operations for /// the dependent data of the affected elements. /// /// The target data collection which needs to be updated. /// The imported data collection which is used to update /// the /// The source file path. /// A with affected objects. /// Thrown when duplicate items are being added to the /// . /// Thrown when duplicate items are found during the /// update of the items to be updatd in the . private IEnumerable ModifyDataCollection(ObservableUniqueItemCollectionWithSourcePath targetDataCollection, IEnumerable importedDataCollection, string sourceFilePath) { TTargetData[] importedObjects = importedDataCollection.ToArray(); TTargetData[] addedObjects = GetAddedObjects(targetDataCollection, importedObjects).ToArray(); TTargetData[] removedObjects = GetRemovedObjects(targetDataCollection, importedObjects).ToArray(); TTargetData[] updatedObjects = GetUpdatedObjects(targetDataCollection, importedObjects).ToArray(); var affectedObjects = new List(); if (addedObjects.Any()) { affectedObjects.Add(targetDataCollection); } affectedObjects.AddRange(UpdateData(targetDataCollection, importedObjects)); affectedObjects.AddRange(RemoveData(removedObjects)); targetDataCollection.Clear(); targetDataCollection.AddRange(addedObjects.Union(updatedObjects), sourceFilePath); return affectedObjects.Distinct(new ReferenceEqualityComparer()); } private IEnumerable GetRemovedObjects(IEnumerable existingCollection, IEnumerable importedDataOjects) { return existingCollection.Except(importedDataOjects, equalityComparer); } private IEnumerable GetUpdatedObjects(IEnumerable existingCollection, IEnumerable importedDataObjects) { return existingCollection.Intersect(importedDataObjects, equalityComparer); } private IEnumerable GetAddedObjects(IEnumerable existingCollection, IEnumerable importedDataObjects) { return importedDataObjects.Where(source => !existingCollection.Contains(source, equalityComparer)); } } }