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; } } }