// 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.Data; using Core.Common.Base.IO; using Core.Common.IO.Readers; using log4net; using Ringtoets.Common.Data; using Ringtoets.Common.Data.Calculation; using Ringtoets.Common.Data.DikeProfiles; using Ringtoets.Common.Data.Hydraulics; using Ringtoets.Common.Data.Probabilistics; using Ringtoets.Common.IO.Configurations; using Ringtoets.Common.IO.Configurations.Helpers; using Ringtoets.Common.IO.Properties; using Ringtoets.Common.IO.Readers; namespace Ringtoets.Common.IO.FileImporters { /// /// Base class for importing a calculation configuration from an XML file and storing it on a . /// /// The type of the reader to use for reading the XML file. /// The type of the data read from the XML file by the reader. public abstract class CalculationConfigurationImporter : FileImporterBase where TCalculationConfigurationReader : CalculationConfigurationReader where TReadCalculation : class, IConfigurationItem { protected readonly ILog Log = LogManager.GetLogger(typeof(CalculationConfigurationImporter)); /// /// Creates a new instance of . /// /// The path to the XML file to import from. /// The calculation group to update. /// Thrown when any parameter is null. protected CalculationConfigurationImporter(string xmlFilePath, CalculationGroup importTarget) : base(xmlFilePath, importTarget) {} protected override void LogImportCanceledMessage() { Log.Info(Resources.CalculationConfigurationImporter_LogImportCanceledMessage_Import_canceled_no_data_read); } protected override bool OnImport() { NotifyProgress(Resources.CalculationConfigurationImporter_ProgressText_Reading_configuration, 1, 3); ReadResult readResult = ReadConfiguration(); if (readResult.CriticalErrorOccurred || Canceled) { return false; } NotifyProgress(Resources.CalculationConfigurationImporter_ProgressText_Validating_imported_data, 2, 3); var parsedCalculationItems = new List(); foreach (IConfigurationItem readItem in readResult.Items) { if (Canceled) { return false; } ICalculationBase parsedItem = ParseReadConfigurationItem(readItem); if (parsedItem != null) { parsedCalculationItems.Add(parsedItem); } } NotifyProgress(Resources.Importer_ProgressText_Adding_imported_data_to_data_model, 3, 3); AddItemsToModel(parsedCalculationItems); return true; } /// /// Creates the reader used for reading the calculation configuration from the provided . /// /// The path to the XML file to import from. /// A reader for reading the calculation configuration. /// Thrown when is invalid. /// Thrown when: /// /// points to a file that does not exist. /// points to a file that does not contain valid XML. /// points to a file that does not pass the schema validation. /// points to a file that does not contain configuration elements. /// /// protected abstract TCalculationConfigurationReader CreateCalculationConfigurationReader(string xmlFilePath); /// /// Parses a calculation from the provided . /// /// The calculation read from XML. /// A parsed calculation instance, or null when something goes wrong while parsing. protected abstract ICalculation ParseReadCalculation(TReadCalculation readCalculation); /// /// Tries to find the hydraulic boundary location with the given /// in the . /// /// The name of the location to find. /// Name of the calculation to assign the location to. /// The collection of /// to search in. /// The location with the name equal to /// if there was any. /// true if no is given, or when a location with /// the name was found, false otherwise. /// Thrown when /// or is null. protected bool TryReadHydraulicBoundaryLocation( string locationName, string calculationName, IEnumerable hydraulicBoundaryLocations, out HydraulicBoundaryLocation foundLocation) { if (calculationName == null) { throw new ArgumentNullException(nameof(calculationName)); } if (hydraulicBoundaryLocations == null) { throw new ArgumentNullException(nameof(hydraulicBoundaryLocations)); } foundLocation = null; if (locationName != null) { HydraulicBoundaryLocation location = hydraulicBoundaryLocations.FirstOrDefault(l => l.Name == locationName); if (location == null) { Log.LogCalculationConversionError(string.Format( Resources.CalculationConfigurationImporter_ReadHydraulicBoundaryLocation_HydraulicBoundaryLocation_0_does_not_exist, locationName), calculationName); return false; } foundLocation = location; } return true; } /// /// Tries to find the structure with the given /// in the . /// /// The type of the to read. /// The name of the structure to find. /// Name of the calculation to assign the structure to. /// The collection of to search in. /// The structure with the name equal to /// if there was any. /// true if no is given, or when a structure with /// the name was found, false otherwise. /// Thrown when /// or is null. protected bool TryReadStructure( string structureName, string calculationName, IEnumerable structures, out T foundStructure) where T : StructureBase { if (calculationName == null) { throw new ArgumentNullException(nameof(calculationName)); } if (structures == null) { throw new ArgumentNullException(nameof(structures)); } foundStructure = null; if (structureName != null) { T structure = structures.FirstOrDefault(l => l.Name == structureName); if (structure == null) { Log.LogCalculationConversionError(string.Format( Resources.CalculationConfigurationImporter_ReadStructure_Structure_0_does_not_exist, structureName), calculationName); return false; } foundStructure = structure; } return true; } /// /// Tries to find the foreshore profile with the given /// in the . /// /// The name of the foreshore profile to find. /// Name of the calculation to assign the foreshore profile to. /// The collection of to search in. /// The foreshore profile with the name equal to /// if there was any. /// true if no is given, or when a foreshore profile with /// the name was found, false otherwise. /// Thrown when /// or is null. protected bool TryReadForeshoreProfile( string foreshoreProfileName, string calculationName, IEnumerable foreshoreProfiles, out ForeshoreProfile foundForeshoreProfile) { if (calculationName == null) { throw new ArgumentNullException(nameof(calculationName)); } if (foreshoreProfiles == null) { throw new ArgumentNullException(nameof(foreshoreProfiles)); } foundForeshoreProfile = null; if (foreshoreProfileName != null) { ForeshoreProfile foreshoreProfile = foreshoreProfiles.FirstOrDefault(fp => fp.Name == foreshoreProfileName); if (foreshoreProfile == null) { Log.LogCalculationConversionError(string.Format( Resources.CalculationConfigurationImporter_ReadForeshoreProfile_ForeshoreProfile_0_does_not_exist, foreshoreProfileName), calculationName); return false; } foundForeshoreProfile = foreshoreProfile; } return true; } /// /// Assigns the parameters to the . /// /// Type of the input for which values are assigned from the configuration. /// The wave reduction configuration containing values for the parameters. /// The input to assign the values to. protected static void ReadWaveReductionParameters(WaveReductionConfiguration waveReduction, T input) where T : IUseBreakWater, IUseForeshore { if (waveReduction != null) { if (waveReduction.UseForeshoreProfile.HasValue) { input.UseForeshore = waveReduction.UseForeshoreProfile.Value; } if (waveReduction.UseBreakWater.HasValue) { input.UseBreakWater = waveReduction.UseBreakWater.Value; } if (waveReduction.BreakWaterType.HasValue) { input.BreakWater.Type = (BreakWaterType) new ConfigurationBreakWaterTypeConverter().ConvertTo(waveReduction.BreakWaterType.Value, typeof(BreakWaterType)); } if (waveReduction.BreakWaterHeight.HasValue) { input.BreakWater.Height = (RoundedDouble) waveReduction.BreakWaterHeight.Value; } } } /// /// Reads the stochast parameters. /// /// The type of the distribution to read. /// The type of the calculation input. /// The name of the calculation to configure. /// The stochast's name. /// The input for which to assign the read stochast. /// The configuration of the stochast. /// The function for obtaining the stochast to read. /// The function to set the stochast with the read parameters. /// true if reading all required stochast parameters was successful, /// false otherwise. protected bool TryReadStandardDeviationStochast( string calculationName, string stochastName, TCalculationInput input, StochastConfiguration stochastConfiguration, Func getStochast, Action setStochast) where TDistribution : IDistribution where TCalculationInput : ICalculationInput { if (stochastConfiguration == null) { return true; } var distribution = (TDistribution) getStochast(input).Clone(); if (!distribution.TrySetDistributionProperties(stochastConfiguration, stochastName, calculationName)) { return false; } setStochast(input, distribution); return true; } /// /// Reads the stochast parameters. /// /// The type of the distribution to read. /// The type of the calculation input. /// The name of the calculation to configure. /// The stochast's name. /// The input for which to assign the read stochast. /// The configuration of the stochast. /// The function for obtaining the stochast to read. /// The function to set the stochast with the read parameters. /// true if reading all required stochast parameters was successful, /// false otherwise. protected bool TryReadVariationCoefficientStochast( string calculationName, string stochastName, TCalculationInput input, StochastConfiguration stochastConfiguration, Func getStochast, Action setStochast) where TDistribution : IVariationCoefficientDistribution where TCalculationInput : ICalculationInput { if (stochastConfiguration == null) { return true; } var distribution = (TDistribution) getStochast(input).Clone(); if (!distribution.TrySetDistributionProperties(stochastConfiguration, stochastName, calculationName)) { return false; } setStochast(input, distribution); return true; } private ReadResult ReadConfiguration() { try { return new ReadResult(false) { Items = CreateCalculationConfigurationReader(FilePath).Read().ToList() }; } catch (Exception exception) when (exception is ArgumentException || exception is CriticalFileReadException) { string errorMessage = string.Format(Resources.CalculationConfigurationImporter_HandleCriticalFileReadError_Error_0_no_configuration_imported, exception.Message); Log.Error(errorMessage, exception); return new ReadResult(true); } } /// /// Parses the read configuration item. /// /// The read item to parse. /// A parsed calculation item. /// Thrown when the item to parse is not valid. private ICalculationBase ParseReadConfigurationItem(IConfigurationItem readConfigurationItem) { var readCalculationGroup = readConfigurationItem as CalculationGroupConfiguration; if (readCalculationGroup != null) { return ParseReadCalculationGroup(readCalculationGroup); } var readCalculation = readConfigurationItem as TReadCalculation; if (readCalculation != null) { return ParseReadCalculation(readCalculation); } throw new InvalidOperationException("Can't parse item that is not a calculation or calculation group."); } /// /// Parses the read calculation group and it's children. /// /// The calculation group to parse. /// A parsed calculation group. /// Thrown when the one of the children /// to parse is not valid. private CalculationGroup ParseReadCalculationGroup(CalculationGroupConfiguration readCalculationGroup) { var calculationGroup = new CalculationGroup(readCalculationGroup.Name, true); foreach (IConfigurationItem item in readCalculationGroup.Items) { ICalculationBase parsedItem = ParseReadConfigurationItem(item); if (parsedItem != null) { calculationGroup.Children.Add(parsedItem); } } return calculationGroup; } private void AddItemsToModel(IEnumerable parsedCalculationItems) { foreach (ICalculationBase parsedCalculationItem in parsedCalculationItems) { ImportTarget.Children.Add(parsedCalculationItem); } } } }