// Copyright (C) Stichting Deltares 2020. All rights reserved. // // This file is part of the LayerOnSlopeTool // // The LayerOnSlopeTool is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero 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 Affero General Public License for more details. // // You should have received a copy of the GNU Affero 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.IO; using System.Linq; using System.Threading; using LumenWorks.Framework.IO.Csv; namespace Deltares.LayerOnSlopeTool.Data.CsvImporters { /// /// Holds the importer for the surface lines from csv files /// public class CsvImporterSurfaceLines { private readonly List surfaceLineRecords = new List(); private List errorMessages = new List(); private const string LocationColumnName = "LocationId"; private const string ProfileNameColumnName = "Profielnaam"; private const string FirstXColumnName = "X1"; /// /// Record used for importing the items from the surface line csv file. /// public class SurfaceLineRecord { private IList xcoors = new List(); private IList ycoors = new List(); private IList zcoors = new List(); public string SurfaceLineId { get; set; } public int SurfaceLineRecordId { get; set; } public IList Xcoors { get { return xcoors; } set { xcoors = value; } } public IList Ycoors { get { return ycoors; } set { ycoors = value; } } public IList Zcoors { get { return zcoors; } set { zcoors = value; } } } private void CheckColumn(int index, string fileName, string fieldName) { if (index < 0) { var csvHeaderFieldError = "The header misses the field: "; throw new ArgumentException(string.Format("{0} : {1} {2}", fileName, csvHeaderFieldError, fieldName)); } } /// /// Copies to temporary file. /// /// Name of the file. /// the name of the temporary file private string CopyToTemporaryFile(string fileName) { string newFilename = Path.GetTempFileName(); File.Delete(newFilename); File.Copy(fileName, newFilename); return newFilename; } public CsvImporterSurfaceLines(string filename) { errorMessages.Clear(); if (filename == "") { throw new ArgumentException("The file name for the Surface Lines csv is empty."); } if (!File.Exists(filename)) { throw new ArgumentException(string.Format("The Surface Lines csv file with name {0} could not be found..", filename)); } // This is a 'dynamic' csv file, i.e. the number of columns is not known and can vary per row. So make sure of a // proper header (i.e. a header with the maximum number of fields // because the file will be changed we copy it to a temporary file and perform the action on the temporary file string tempFilename = CopyToTemporaryFile(filename); CsvReaderUtilities.EnsureProperHeaderForDynamicRecordLengthInCsvFile(tempFilename); var cultureInfo = Thread.CurrentThread.CurrentCulture; try { Thread.CurrentThread.CurrentCulture = CsvReaderUtilities.DetermineCultureForFile(tempFilename); using (CsvReader csv = new CsvReader(new StreamReader(tempFilename), true, ';') { MissingFieldAction = MissingFieldAction.ReplaceByNull }) { string[] headers = CsvImporterHelper.GetFieldHeaders(this, csv); int colIndexSurfaceLineId = CsvReaderUtilities.GetHeaderIndexByString(headers, LocationColumnName); if (colIndexSurfaceLineId < 0) { // colIndexSurfaceLineId can be defined with 2 identifiers (ProfileNameColumnName is deprecated, LocationColumnName is the new one) colIndexSurfaceLineId = CsvReaderUtilities.GetHeaderIndexByString(headers, LocationColumnName); if (colIndexSurfaceLineId < 0) { colIndexSurfaceLineId = CsvReaderUtilities.GetHeaderIndexByString(headers, ProfileNameColumnName); } } CheckColumn(colIndexSurfaceLineId, tempFilename, LocationColumnName); int colIndexFirstX = CsvReaderUtilities.GetHeaderIndexByString(headers, FirstXColumnName); CheckColumn(colIndexFirstX, tempFilename, FirstXColumnName); int maxColumns = headers.Count(); var end = Math.Floor((maxColumns - colIndexFirstX + 1) / 3.0); var surflineIndex = 1; while (csv.ReadNextRecord()) { var recordReadError = false; SurfaceLineRecord surfaceLine = new SurfaceLineRecord { SurfaceLineRecordId = surflineIndex }; surflineIndex++; surfaceLine.SurfaceLineId = csv[colIndexSurfaceLineId]; var colIndex = colIndexFirstX; for (int i = 0; i < end; i++) { // if the first value = null the end of this surfaceline is reached, so break and it. Checking on null can only be done this way, // a csv[index] == null does not work as that throws an exception itself. try { var dum = csv[colIndex]; if (String.IsNullOrEmpty(dum)) break; } catch (Exception) { break; } // other "errors" are real errors so trap them. try { surfaceLine.Xcoors.Add(Convert.ToDouble(csv[colIndex])); colIndex++; surfaceLine.Ycoors.Add(Convert.ToDouble(csv[colIndex])); colIndex++; surfaceLine.Zcoors.Add(Convert.ToDouble(csv[colIndex])); colIndex++; } catch (Exception e) { var csvSurfaceLineError = String.Format("Next error occured whilst reading surface line {0} column {1} from csv: ", surfaceLine.SurfaceLineRecordId, colIndex + 1); errorMessages.Add(csvSurfaceLineError + e.Message); recordReadError = true; break; } } if (!recordReadError) { surfaceLineRecords.Add(surfaceLine); } } } } finally { File.Delete(tempFilename); Thread.CurrentThread.CurrentCulture = cultureInfo; } } /// /// Gets the imported items. /// /// /// The imported items. /// public List ImportedItems { get { return surfaceLineRecords; } } /// /// Gets the error messages. /// /// /// The error messages. /// public List ErrorMessages { get { return errorMessages; } set { errorMessages = value; } } } }