// 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.Data.SQLite;
using Core.Common.IO.Readers;
using Core.Common.Utils.Builders;
using Ringtoets.Piping.IO.Builders;
using Ringtoets.Piping.IO.Exceptions;
using Ringtoets.Piping.IO.Properties;
using Ringtoets.Piping.Primitives;
namespace Ringtoets.Piping.IO.SoilProfile
{
///
/// This class is responsible for reading 2d profile definitions from the Soil database using a constructed reader
/// and transform the definitions to a .
///
internal static class SoilProfile2DReader
{
///
/// Reads information for a profile from the database and creates a based on the information.
///
/// A which is used to read row values from.
/// A new , which is based on the information from the database.
/// Thrown when reading the profile encountered an unrecoverable error.
/// Thrown when
///
/// - a layer's geometry could not be parsed as XML;
/// - the parsed geometry did not contain loops;
/// - after reading the layers, no layers were added to be build;
/// - unexpected values were encountered for layer properties
///
///
internal static PipingSoilProfile ReadFrom(IRowBasedDatabaseReader reader)
{
var criticalProperties = new CriticalProfileProperties(reader);
var requiredProperties = new RequiredProfileProperties(reader, criticalProperties.ProfileName);
try
{
var soilProfileBuilder = new SoilProfileBuilder2D(criticalProperties.ProfileName, requiredProperties.IntersectionX, criticalProperties.ProfileId);
for (int i = 1; i <= criticalProperties.LayerCount; i++)
{
var pipingSoilLayer2D = ReadPiping2DSoilLayer(reader, criticalProperties.ProfileName);
soilProfileBuilder.Add(pipingSoilLayer2D);
reader.MoveNext();
}
return soilProfileBuilder.Build();
}
catch (SoilProfileBuilderException e)
{
throw CreatePipingSoilProfileReadException(reader.Path, criticalProperties.ProfileName, e);
}
catch (ArgumentException e)
{
throw CreatePipingSoilProfileReadException(reader.Path, criticalProperties.ProfileName, e);
}
}
///
/// Reads a soil layer from a 2d profile in the database.
///
/// The to read the layer property values from.
/// The profile name used in generating exceptions messages if casting failed.
/// A new instance, based on the information read from the database.
/// Thrown when:
///
/// - A column for a layer property did not contain a value of the expected type.
/// - The database contains an invalid XML definition for geometry.
/// - The read geometry does not contain segments that form form a loop for either the inner or outer loop.
///
private static SoilLayer2D ReadPiping2DSoilLayer(IRowBasedDatabaseReader reader, string profileName)
{
var properties = new LayerProperties(reader, profileName);
SoilLayer2D pipingSoilLayer;
try
{
var geometryValue = ReadGeometryFrom(reader, profileName);
pipingSoilLayer = new SoilLayer2DReader().Read(geometryValue);
}
catch (SoilLayerConversionException e)
{
throw CreatePipingSoilProfileReadException(reader.Path, profileName, e);
}
if (pipingSoilLayer != null)
{
pipingSoilLayer.IsAquifer = properties.IsAquifer;
pipingSoilLayer.MaterialName = properties.MaterialName;
pipingSoilLayer.Color = properties.Color;
pipingSoilLayer.BelowPhreaticLevelDistribution = properties.BelowPhreaticLevelDistribution;
pipingSoilLayer.BelowPhreaticLevelShift = properties.BelowPhreaticLevelShift;
pipingSoilLayer.BelowPhreaticLevelMean = properties.BelowPhreaticLevelMean;
pipingSoilLayer.BelowPhreaticLevelDeviation = properties.BelowPhreaticLevelDeviation;
pipingSoilLayer.DiameterD70Distribution = properties.DiameterD70Distribution;
pipingSoilLayer.DiameterD70Shift = properties.DiameterD70Shift;
pipingSoilLayer.DiameterD70Mean = properties.DiameterD70Mean;
pipingSoilLayer.DiameterD70Deviation = properties.DiameterD70Deviation;
pipingSoilLayer.PermeabilityDistribution = properties.PermeabilityDistribution;
pipingSoilLayer.PermeabilityShift = properties.PermeabilityShift;
pipingSoilLayer.PermeabilityMean = properties.PermeabilityMean;
pipingSoilLayer.PermeabilityDeviation = properties.PermeabilityDeviation;
}
return pipingSoilLayer;
}
///
/// Reads the geometry for a layer from the current
///
/// The to read the geometry value from.
/// The profile name used in generating exceptions messages if casting failed.
///
private static byte[] ReadGeometryFrom(IRowBasedDatabaseReader reader, string profileName)
{
try
{
return reader.Read(SoilProfileDatabaseColumns.LayerGeometry);
}
catch (InvalidCastException e)
{
throw CreatePipingSoilProfileReadException(reader.Path, profileName, e);
}
}
private static PipingSoilProfileReadException CreatePipingSoilProfileReadException(string filePath, string profileName, string errorMessage, Exception innerException)
{
var message = new FileReaderErrorMessageBuilder(filePath)
.WithSubject(string.Format(Resources.PipingSoilProfileReader_SoilProfileName_0_, profileName))
.Build(errorMessage);
return new PipingSoilProfileReadException(profileName, message, innerException);
}
private static PipingSoilProfileReadException CreatePipingSoilProfileReadException(string filePath, string profileName, Exception innerException)
{
var message = new FileReaderErrorMessageBuilder(filePath)
.WithSubject(string.Format(Resources.PipingSoilProfileReader_SoilProfileName_0_, profileName))
.Build(innerException.Message);
return new PipingSoilProfileReadException(profileName, message, innerException);
}
private class RequiredProfileProperties
{
internal readonly double IntersectionX;
///
/// Creates a new instance of , which contains properties
/// that are required to create a complete . If these properties
/// cannot be read, then the reader can proceed to the next profile.
///
/// The to read the required profile property values from.
/// The profile name used in generating exceptions messages if casting failed.
/// Thrown when the values in the database could not be
/// casted to the expected column types.
internal RequiredProfileProperties(IRowBasedDatabaseReader reader, string profileName)
{
string readColumn = SoilProfileDatabaseColumns.IntersectionX;
try
{
IntersectionX = reader.Read(readColumn);
}
catch (InvalidCastException e)
{
var message = string.Format(Resources.PipingSoilProfileReader_Profile_has_invalid_value_on_Column_0_, readColumn);
throw CreatePipingSoilProfileReadException(reader.Path, profileName, message, e);
}
}
}
}
}