using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data;
using System.Data.SQLite;
using System.IO;
using System.Linq;
using System.Xml;
using Ringtoets.Piping.Data;
using Ringtoets.Piping.IO.Builders;
using Ringtoets.Piping.IO.Exceptions;
using Ringtoets.Piping.IO.Properties;
namespace Ringtoets.Piping.IO
{
///
/// This class reads a SqLite database file and constructs from this database.
/// The database is created with the DSoilModel application.
///
public class PipingSoilProfileReader : IDisposable
{
private const int pipingMechanismId = 4;
private SQLiteConnection connection;
private SQLiteDataReader dataReader;
private const string profileNameColumn = "ProfileName";
private const string intersectionXColumn = "IntersectionX";
private const string bottomColumn = "Bottom";
private const string layerGeometryColumn = "LayerGeometry";
private const string abovePhreaticLevelColumn = "AbovePhreaticLevel";
private const string belowPhreaticLevelColumn = "BelowPhreaticLevel";
private const string permeabKxColumn = "PermeabKx";
private const string diameterD70Column = "DiameterD70";
private const string whitesConstantColumn = "WhitesConstant";
private const string beddingAngleColumn = "BeddingAngle";
private const string dimensionsColumn = "Dimensions";
///
/// Creates a new instance of which will use the
/// as its source.
///
///
public PipingSoilProfileReader(string dbFile)
{
if (String.IsNullOrEmpty(dbFile))
{
throw new ArgumentException(Resources.Error_PathMustBeSpecified);
}
if (!File.Exists(dbFile))
{
throw new FileNotFoundException(String.Format(Resources.Error_File_0_does_not_exist, dbFile));
}
PrepareConnection(dbFile);
Connect();
}
///
/// Creates instances of based on the database file of the .
///
///
/// Thrown when reading soil profile entries from the database failed.
/// Thrown when parsing the geometry of a soil layer failed.
public IEnumerable Read()
{
var pipingSoilProfileBuilders = new Dictionary();
CreateDataReader();
while (dataReader.Read())
{
var profileName = (string)dataReader[profileNameColumn];
var dimensions = (long) dataReader[dimensionsColumn];
if (dimensions == 2)
{
var intersectionX = (double) dataReader[intersectionXColumn];
if (!pipingSoilProfileBuilders.ContainsKey(profileName))
{
pipingSoilProfileBuilders.Add(profileName, new SoilProfileBuilder2D(profileName, intersectionX));
}
var soilProfile2DBuilder = pipingSoilProfileBuilders[profileName] as SoilProfileBuilder2D;
if(soilProfile2DBuilder == null)
{
throw new PipingSoilProfileReadException(Resources.Error_CannotCombine2DAnd1DLayersInProfile);
}
soilProfile2DBuilder.Add(ReadPiping2DSoilLayer());
}
else
{
var bottom = (double)dataReader[bottomColumn];
if (!pipingSoilProfileBuilders.ContainsKey(profileName))
{
pipingSoilProfileBuilders.Add(profileName, new SoilProfileBuilder1D(profileName, bottom));
}
var soilProfile1DBuilder = pipingSoilProfileBuilders[profileName] as SoilProfileBuilder1D;
if (soilProfile1DBuilder == null)
{
throw new PipingSoilProfileReadException(Resources.Error_CannotCombine2DAnd1DLayersInProfile);
}
soilProfile1DBuilder.Add(ReadPipingSoilLayer());
}
}
return pipingSoilProfileBuilders.Select(keyValue => keyValue.Value.Build());
}
private PipingSoilLayer ReadPipingSoilLayer()
{
var columnValue = (double) dataReader[bottomColumn];
return new PipingSoilLayer(columnValue);
}
public void Dispose()
{
if (dataReader != null)
{
dataReader.Close();
dataReader.Dispose();
}
connection.Close();
connection.Dispose();
}
private void PrepareConnection(string dbFile)
{
var connectionStringBuilder = new SQLiteConnectionStringBuilder
{
FailIfMissing = true,
DataSource = dbFile,
ReadOnly = true,
ForeignKeys = true
};
connection = new SQLiteConnection(connectionStringBuilder.ConnectionString);
}
private void Connect()
{
try
{
connection.Open();
}
catch (SQLiteException)
{
connection.Dispose();
}
}
private SoilLayer2D ReadPiping2DSoilLayer()
{
var columnValue = dataReader[layerGeometryColumn];
var geometry = (byte[]) columnValue;
return new PipingSoilLayer2DReader(geometry).Read();
}
///
/// Creates a new data reader to use in this class, based on a query which returns all the known soil layers for which its profile has a X coordinate defined for piping.
///
private void CreateDataReader()
{
var mechanismParameterName = "mechanism";
var query = new SQLiteCommand(connection)
{
CommandText = string.Format(string.Join(" ",
"SELECT",
"p.SP2D_Name as {0},",
"l.GeometrySurface as {1},",
"mpl.X as {2},",
"null as {3},",
"sum(case when mat.PN_Name = 'AbovePhreaticLevel' then mat.PV_Value end) {4},",
"sum(case when mat.PN_Name = 'BelowPhreaticLevel' then mat.PV_Value end) {5},",
"sum(case when mat.PN_Name = 'PermeabKx' then mat.PV_Value end) {6},",
"sum(case when mat.PN_Name = 'DiameterD70' then mat.PV_Value end) {7},",
"sum(case when mat.PN_Name = 'WhitesConstant' then mat.PV_Value end) {8},",
"sum(case when mat.PN_Name = 'BeddingAngle' then mat.PV_Value end) {9},",
"2 as {10}",
"FROM MechanismPointLocation as m",
"JOIN MechanismPointLocation as mpl ON p.SP2D_ID = mpl.SP2D_ID",
"JOIN SoilProfile2D as p ON m.SP2D_ID = p.SP2D_ID",
"JOIN SoilLayer2D as l ON l.SP2D_ID = p.SP2D_ID",
"JOIN (",
"SELECT m.MA_ID, pn.PN_Name, pv.PV_Value",
"FROM ParameterNames as pn",
"JOIN ParameterValues as pv ON pn.PN_ID = pv.PN_ID",
"JOIN Materials as m ON m.MA_ID = pv.MA_ID) as mat ON l.MA_ID = mat.MA_ID",
"WHERE m.ME_ID = @{11}",
"GROUP BY l.SL2D_ID",
"UNION",
"SELECT",
"p.SP1D_Name as {0},",
"null as {1},",
"null as {2},",
"p.BottomLevel as {3},",
"sum(case when mat.PN_Name = 'AbovePhreaticLevel' then mat.PV_Value end) {4},",
"sum(case when mat.PN_Name = 'BelowPhreaticLevel' then mat.PV_Value end) {5},",
"sum(case when mat.PN_Name = 'PermeabKx' then mat.PV_Value end) {6},",
"sum(case when mat.PN_Name = 'DiameterD70' then mat.PV_Value end) {7},",
"sum(case when mat.PN_Name = 'WhitesConstant' then mat.PV_Value end) {8},",
"sum(case when mat.PN_Name = 'BeddingAngle' then mat.PV_Value end) {9},",
"1 as {10}",
"FROM SoilProfile1D as p",
"JOIN SoilLayer1D as l ON l.SP1D_ID = p.SP1D_ID",
"JOIN (",
"SELECT m.MA_ID, pn.PN_Name, pv.PV_Value",
"FROM ParameterNames as pn",
"JOIN ParameterValues as pv ON pn.PN_ID = pv.PN_ID",
"JOIN Materials as m ON m.MA_ID = pv.MA_ID) as mat ON l.MA_ID = mat.MA_ID",
"GROUP BY l.SL1D_ID",
"ORDER BY ProfileName"
),
profileNameColumn,
layerGeometryColumn,
intersectionXColumn,
bottomColumn,
abovePhreaticLevelColumn,
belowPhreaticLevelColumn,
permeabKxColumn,
diameterD70Column,
whitesConstantColumn,
beddingAngleColumn,
dimensionsColumn,
mechanismParameterName)
};
query.Parameters.Add(new SQLiteParameter
{
DbType = DbType.Int32,
Value = pipingMechanismId,
ParameterName = mechanismParameterName
});
try
{
dataReader = query.ExecuteReader();
}
catch (SQLiteException e)
{
throw new PipingSoilProfileReadException(string.Format(Resources.Error_SoilProfileReadFromDatabase, connection.DataSource), e);
}
}
}
}