using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Drawing;
using Deltares.Geotechnics;
using Deltares.Geotechnics.IO.Exception;
using Deltares.Geotechnics.IO.Importers;
using Deltares.Standard.EventPublisher;
using Deltares.Standard.Extensions;
using Deltares.Standard.IO;
using Deltares.Standard.Language;
using Deltares.Standard.Logging;
using LumenWorks.Framework.IO.Csv;
namespace Deltares.DSoilModel.Data
{
public class SosSoilProfilesImporter : SoilProfilesImporter
{
///
/// Read soil profiles using SOSSoilLayer1D instead of SoilLayer1D, referencing soils in the provided list or
/// using a factory to get the referenced soils.
///
/// path of the file to import
/// list of available soil materials to reference
///
/// List of SoilProfile1D objects
public override List ReadSoilProfiles(string fileName, SoilList soils)
{
var soilProfiles = new List();
var errorProfiles = new List();
var oldcur = Thread.CurrentThread.CurrentCulture;
ErrorMessages.Clear();
DataEventPublisher.InvokeWithoutPublishingEvents(() =>
{
try
{
Thread.CurrentThread.CurrentCulture = CsvReaderUtilities.DetermineCultureForFile(fileName);
using (var csv = new CsvReader(new StreamReader(fileName), true, ';'))
{
string[] headers = csv.GetFieldHeaders();
string[] validHeaders = new string[]
{
"soilprofile_id",
"top_level",
"soil_name",
"soil_color",
"soil_type",
"max-d",
"min-d",
"remark",
"extra"
};
string[] requiredHeaders = new string[]
{
"soilprofile_id",
"top_level",
"soil_name"
};
// The definition of the csv contains one extra column (soil_type) which is now optional.
// Next to that 5 extra optional columns are added for the SOS-import of which one (named extra) is unused for now
// So number of columns may vary from 3 to 9.
if ((headers.Count() < 3) || (headers.Count() > 9))
{
string csvHeaderError = LocalizationManager.GetTranslatedText(this, "csvHeaderError");
throw new CsvImporterSoilProfilesException(String.Format("{0} : {1}", fileName, csvHeaderError));
}
//Check that all required column names are present
var missingNames = GetMissingSoilProfileHeaders(headers, requiredHeaders);
if (missingNames != "")
{
string csvHeaderError = LocalizationManager.GetTranslatedText(this, "csvHeaderMissingColumns");
string csvNotImported = LocalizationManager.GetTranslatedText(this, "csvNotImported");
LogManager.Messages.Add(new LogMessage(LogMessageType.Error, this, String.Format("{0} : {1} -- {2}", fileName, csvHeaderError, missingNames)));
LogManager.Messages.Add(new LogMessage(LogMessageType.Warning, this, String.Format("{0} : {1}", fileName, csvNotImported)));
return;
}
//Check that all column names are known
var invalidNames = GetInvalidSoilProfileHeaders(headers, validHeaders);
if (invalidNames != "")
{
string csvHeaderError = LocalizationManager.GetTranslatedText(this, "csvHeaderInvalidColumns");
LogManager.Messages.Add(new LogMessage(LogMessageType.Warning, this, String.Format("{0} : {1} -- {2}", fileName, csvHeaderError, invalidNames)));
}
const string fieldsoilprofile_id = "soilprofile_id";
int colIndexSoilProfileId = CsvReaderUtilities.GetHeaderIndexByString(headers, fieldsoilprofile_id);
CheckColumn(colIndexSoilProfileId, fileName, fieldsoilprofile_id);
const string fieldtop_level = "top_level";
int colIndexTopLevel = CsvReaderUtilities.GetHeaderIndexByString(headers, fieldtop_level);
CheckColumn(colIndexTopLevel, fileName, fieldtop_level);
const string fieldsoil_name = "soil_name";
int colIndexSoilName = CsvReaderUtilities.GetHeaderIndexByString(headers, fieldsoil_name);
CheckColumn(colIndexSoilName, fileName, fieldsoil_name);
// Optional soil color field
const string fieldsoilColor = "soil_color";
int colIndexSoilColor = CsvReaderUtilities.GetHeaderIndexByString(headers, fieldsoilColor);
// Optional soil type field
const string fieldsoilType = "soil_type";
int colIndexSoilType = CsvReaderUtilities.GetHeaderIndexByString(headers, fieldsoilType);
const string fieldMaxd = "max-d";
int colIndexMaxd = CsvReaderUtilities.GetHeaderIndexByString(headers, fieldMaxd);
const string fieldMind = "min-d";
int colIndexMind = CsvReaderUtilities.GetHeaderIndexByString(headers, fieldMind);
const string fieldRemark = "remark";
int colIndexRemark = CsvReaderUtilities.GetHeaderIndexByString(headers, fieldRemark);
int index = 0;
string currentName = "";
SoilProfile1D soilProfile = null;
while (csv.ReadNextRecord())
{
try
{
index++;
string name = csv[colIndexSoilProfileId];
if (!name.Equals(currentName))
{
soilProfile = soilProfiles.FirstOrDefault(p => p.Name == name);
}
if (soilProfile == null)
{
soilProfile = new SoilProfile1D();
soilProfile.Name = csv[colIndexSoilProfileId];
soilProfile.Layers.Clear();
soilProfiles.Add(soilProfile);
}
currentName = name;
var layer = new SosSoilLayer1D();
var isLayerCheckNeeded = false;
layer.TopLevel = Convert.ToDouble(csv[colIndexTopLevel]);
if (colIndexMaxd >= 0)
{
layer.MaximumTopLevel = Convert.ToDouble(csv[colIndexMaxd]);
isLayerCheckNeeded = true;
}
if (colIndexMind >= 0)
{
layer.MinimumTopLevel = Convert.ToDouble(csv[colIndexMind]);
isLayerCheckNeeded = true;
}
if (colIndexRemark >= 0)
{
layer.RemarkTopLevel = csv[colIndexRemark];
}
var color = Color.Bisque;
if (colIndexSoilColor >= 0)
{
var colorAsString = csv[colIndexSoilColor];
color = GetColorFromString(colorAsString);
}
SoilType type = SoilType.Sand;
if (colIndexSoilType >= 0)
{
var typeAsString = csv[colIndexSoilType];
type = GetSoilTypeFromString(typeAsString);
}
layer.Soil = GetSoil(soils.Soils, csv[colIndexSoilName], color, type);
if (soils.AquiferDictionary.ContainsKey(layer.Soil))
{
layer.IsAquifer = soils.AquiferDictionary[layer.Soil];
}
if (isLayerCheckNeeded)
{
CheckValiditySosLayerData(layer);
}
soilProfile.Layers.Add(layer);
}
catch (Exception e)
{
string csvSoilProfileError =
String.Format(LocalizationManager.GetTranslatedText(typeof(SoilProfilesImporter), "csvSoilProfileError"),
currentName);
ErrorMessages.Add(new LogMessage(LogMessageType.Error, FileName, String.Format("Record {0} : {1}", index, csvSoilProfileError + e.Message)));
if (errorProfiles.FirstOrDefault(p => p.Name == soilProfile.Name) == null)
{
errorProfiles.Add(soilProfile);
string csvSoilProfileRefused = String.Format(
LocalizationManager.GetTranslatedText(typeof(SosSoilProfilesImporter), "CsvSoilProfileRefused"),
currentName);
ErrorMessages.Add(new LogMessage(LogMessageType.Error, FileName, String.Format("{0} : {1}", soilProfile.Name, csvSoilProfileRefused)));
}
}
}
}
RemoveProfilesWithErrors(soilProfiles, errorProfiles);
foreach (var profile in soilProfiles)
{
if (!profile.AreLayersOrderedByDescending())
{
profile.Layers.Sort();
}
}
if (soilProfiles.Count == 0)
{
var msg = String.Format(LocalizationManager.GetTranslatedText(typeof(SoilProfilesImporter), "SoilprofilesCsvFileEmptyWarning"), fileName);
ErrorMessages.Add(new LogMessage(LogMessageType.Warning, FileName, msg));
}
}
finally
{
Thread.CurrentThread.CurrentCulture = oldcur;
}
});
return soilProfiles;
}
private void CheckValiditySosLayerData(SosSoilLayer1D layer)
{
if (!(layer.MaximumTopLevel >= layer.TopLevel && layer.TopLevel >= layer.MinimumTopLevel))
{
string sosLayerDataError = LocalizationManager.GetTranslatedText(typeof(SosSoilProfilesImporter),
"SosLayerDataError");
throw new CsvImporterSoilProfilesException(String.Format("{0} : {1} ", layer.Id, sosLayerDataError));
}
}
private void RemoveProfilesWithErrors(List soilProfiles, List errorProfiles)
{
foreach (var errorProfile in errorProfiles)
{
soilProfiles.Remove(errorProfile);
}
}
private Soil GetSoil(List soils, string name, Color color, SoilType type)
{
foreach (var soil in soils)
{
if (soil.Name.ToUpper().Trim().Equals(name.ToUpper().Trim()))
{
return soil;
}
}
var newSoil = new Soil();
newSoil.Name = name;
newSoil.Color = color;
newSoil.SoilType = type;
soils.Add(newSoil);
string msg = String.Format(LocalizationManager.GetTranslatedText(typeof(SoilProfilesImporter), "SoilProfileUndefinedSoil"), name);
ErrorMessages.Add(new LogMessage(LogMessageType.Warning, FileName, msg));
return newSoil;
}
private Color GetColorFromString(string colorAsString)
{
Color color;
try
{
color = Color.FromName(colorAsString);
if (color.Name != Color.Black.Name && color.R == 0 && color.G == 0 && color.B == 0)
{
color = Color.Bisque;
}
}
catch (Exception)
{
color = Color.Bisque;
}
return color;
}
private SoilType GetSoilTypeFromString(string typeAsString)
{
SoilType type;
if (SoilType.TryParse(typeAsString, true, out type))
return type;
return SoilType.Sand;
}
private string GetInvalidSoilProfileHeaders(string[] headers, string[] validHeaders)
{
string invalidHeaders = "";
foreach (var name in headers)
{
bool found = false;
foreach (var validName in validHeaders)
{
if (name.Equals(validName))
{
found = true;
break;
}
}
if (!found)
{
if (invalidHeaders == "")
{
invalidHeaders = name;
}
else
{
invalidHeaders = invalidHeaders + ", " + name;
}
}
}
return invalidHeaders;
}
private string GetMissingSoilProfileHeaders(string[] headers, string[] requiredHeaders)
{
string missingHeaders = "";
foreach (var name in requiredHeaders)
{
bool found = false;
foreach (var header in headers)
{
if (name.Equals(header))
{
found = true;
break;
}
}
if (!found)
{
if (missingHeaders == "")
{
missingHeaders = name;
}
else
{
missingHeaders = missingHeaders + ", " + name;
}
}
}
return missingHeaders;
}
}
}