// 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 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.Collections.ObjectModel;
using System.Linq;
using Core.Common.Base;
using Core.Common.Base.IO;
using Core.Common.IO.Readers;
using Ringtoets.Common.Data;
using Ringtoets.Common.Data.Exceptions;
using Ringtoets.Common.IO.Exceptions;
using Ringtoets.Common.IO.FileImporters.MessageProviders;
using Ringtoets.Common.IO.Properties;
using RingtoetsCommonDataResources = Ringtoets.Common.Data.Properties.Resources;
namespace Ringtoets.Common.IO.SoilProfile
{
///
/// Imports .soil files (SqlLite database files) created with the D-Soil Model application.
///
/// The type of stochastic soil models to import.
public class StochasticSoilModelImporter
: FileImporterBase> where T
: class, IMechanismStochasticSoilModel
{
private readonly IImporterMessageProvider messageProvider;
private readonly IStochasticSoilModelUpdateModelStrategy updateStrategy;
private readonly IStochasticSoilModelTransformer transformer;
private readonly IStochasticSoilModelMechanismFilter filter;
private IEnumerable updatedInstances;
///
/// Creates a new instance of .
///
/// The import target.
/// The path to the file to import from.
/// The message provider to provide messages during importer
/// actions.
/// The mechanism specific configuration containing all
/// necessary stochastic soil model components.
/// Thrown when any of the input parameters is null.
public StochasticSoilModelImporter(
ObservableUniqueItemCollectionWithSourcePath importTarget,
string filePath,
IImporterMessageProvider messageProvider,
StochasticSoilModelImporterConfiguration configuration)
: base(filePath, importTarget)
{
if (messageProvider == null)
{
throw new ArgumentNullException(nameof(messageProvider));
}
if (configuration == null)
{
throw new ArgumentNullException(nameof(configuration));
}
this.messageProvider = messageProvider;
updateStrategy = configuration.UpdateStrategy;
transformer = configuration.Transformer;
filter = configuration.MechanismFilter;
updatedInstances = Enumerable.Empty();
}
protected override void LogImportCanceledMessage()
{
string message = messageProvider.GetCancelledLogMessageText(RingtoetsCommonDataResources.StochasticSoilModelCollection_TypeDescriptor);
Log.Info(message);
}
protected override void DoPostImportUpdates()
{
foreach (IObservable observable in updatedInstances)
{
observable.NotifyObservers();
}
}
protected override bool OnImport()
{
ReadResult importStochasticSoilModelResult = ReadStochasticSoilModels();
if (importStochasticSoilModelResult.CriticalErrorOccurred || Canceled)
{
return false;
}
ReadResult transformedStochasticSoilModels;
try
{
transformedStochasticSoilModels = GetTransformedStochasticSoilModels(importStochasticSoilModelResult.Items);
}
catch (ImportedDataTransformException e)
{
Log.ErrorFormat(Resources.StochasticSoilModelImporter_CriticalErrorMessage_0_File_Skipped,
e.Message);
return false;
}
if (transformedStochasticSoilModels.CriticalErrorOccurred || Canceled)
{
return false;
}
if (!transformedStochasticSoilModels.Items.Any())
{
Log.WarnFormat(Resources.StochasticSoilModelImporter_No_stochastic_soil_models_found_for_failure_mechanism);
return true;
}
NotifyProgress(messageProvider.GetAddDataToModelProgressText(), 1, 1);
try
{
updatedInstances = updateStrategy.UpdateModelWithImportedData(transformedStochasticSoilModels.Items, FilePath);
}
catch (UpdateDataException e)
{
string message = string.Format(messageProvider.GetUpdateDataFailedLogMessageText(
RingtoetsCommonDataResources.StochasticSoilModelCollection_TypeDescriptor),
e.Message);
Log.Error(message, e);
return false;
}
return true;
}
private void HandleException(Exception e)
{
string message = string.Format(Resources.StochasticSoilModelImporter_CriticalErrorMessage_0_File_Skipped,
e.Message);
Log.Error(message, e);
}
#region Read stochastic soil models
private ReadResult ReadStochasticSoilModels()
{
NotifyProgress(Resources.StochasticSoilModelImporter_Reading_database, 1, 1);
try
{
using (var stochasticSoilModelReader = new StochasticSoilModelReader(FilePath))
{
stochasticSoilModelReader.Validate();
return GetStochasticSoilModelReadResult(stochasticSoilModelReader);
}
}
catch (Exception e) when (e is StochasticSoilModelException
|| e is CriticalFileReadException)
{
HandleException(e);
}
return new ReadResult(true);
}
///
/// Reads all stochastic soil models from the .
///
/// The .
/// Returns a collection of read stochastic soil models.
/// Thrown when the database returned incorrect
/// values for required properties.
/// Thrown when:
///
/// - no stochastic soil profiles could be read;
/// - the read failure mechanism type is not supported.
///
///
private ReadResult GetStochasticSoilModelReadResult(StochasticSoilModelReader stochasticSoilModelReader)
{
int totalNumberOfSteps = stochasticSoilModelReader.StochasticSoilModelCount;
var currentStep = 1;
var soilModels = new Collection();
while (stochasticSoilModelReader.HasNext)
{
if (Canceled)
{
return new ReadResult(false);
}
NotifyProgress(Resources.StochasticSoilModelImporter_GetStochasticSoilModelReadResult_Reading_stochastic_soil_models_from_database,
currentStep++,
totalNumberOfSteps);
soilModels.Add(stochasticSoilModelReader.ReadStochasticSoilModel());
}
return new ReadResult(false)
{
Items = soilModels
};
}
#endregion
#region Validate stochastic soil models
///
/// Transforms the stochastic soil models into mechanism specific stochastic soil models.
///
/// The stochastic soil models to transform.
/// Returns a collection of mechanism specific stochastic
/// soil models, or an empty when any of the
/// is not valid to be transformed.
/// Thrown when transforming a stochastic
/// soil model failed.
private ReadResult GetTransformedStochasticSoilModels(IEnumerable stochasticSoilModels)
{
var transformedStochasticSoilModels = new List();
var stochasticSoilModelNumber = 1;
StochasticSoilModel[] importedModels = stochasticSoilModels.Where(ssm => filter.IsValidForFailureMechanism(ssm))
.ToArray();
foreach (StochasticSoilModel stochasticSoilModel in importedModels)
{
NotifyProgress(Resources.Importer_ProgressText_Validating_imported_data, stochasticSoilModelNumber++, importedModels.Length);
if (Canceled)
{
return new ReadResult(false);
}
ValidateStochasticSoilModel(stochasticSoilModel);
transformedStochasticSoilModels.Add(transformer.Transform(stochasticSoilModel));
}
return new ReadResult(false)
{
Items = transformedStochasticSoilModels
};
}
private void ValidateStochasticSoilModel(StochasticSoilModel stochasticSoilModel)
{
if (!IsSumOfAllProbabilitiesEqualToOne(stochasticSoilModel))
{
Log.WarnFormat(Resources.StochasticSoilModelImporter_ValidateStochasticSoilModel_Sum_of_probabilities_of_stochastic_soil_model_0_is_not_correct,
stochasticSoilModel.Name);
}
}
private static bool IsSumOfAllProbabilitiesEqualToOne(StochasticSoilModel stochasticSoilModel)
{
double sumOfAllScenarioProbabilities = stochasticSoilModel.StochasticSoilProfiles
.Sum(s => s.Probability);
return Math.Abs(sumOfAllScenarioProbabilities - 1.0) < 1e-6;
}
#endregion
}
}