// Copyright (C) Stichting Deltares 2024. All rights reserved. // // This file is part of the application DAM - UI. // // DAM - UI 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.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; using System.Threading; using Deltares.Standard.IO; using Deltares.Standard.Language; using LumenWorks.Framework.IO.Csv; namespace Deltares.Dam.Data.CsvImporters; public class CsvImporterSurfaceLinesException : Exception { public CsvImporterSurfaceLinesException(string message) : base(message) {} } public class CsvImporterSurfaceLines { public CsvImporterSurfaceLines(string filename) { ErrorMessages.Clear(); ThrowHelper.ThrowIfStringArgumentNullOrEmpty(filename, StringResourceNames.CsvFileNotValid); ThrowHelper.ThrowIfFileNotExist(filename, StringResourceNames.CsvFileNotFound); // 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); CultureInfo oldcur = Thread.CurrentThread.CurrentCulture; try { Thread.CurrentThread.CurrentCulture = CsvReaderUtilities.DetermineCultureForFile(tempFilename); using (var csv = new CsvReader(new StreamReader(tempFilename), true, ';')) { csv.MissingFieldAction = MissingFieldAction.ReplaceByNull; string[] headers = CsvImporterHelper.GetFieldHeaders(this, csv); int colIndexSurfaceLineId = FetchSurfaceLineId(headers); CheckColumn(colIndexSurfaceLineId, tempFilename, SurfaceLineCsvColumnNames.LocationColumnName); int colIndexFirstX = CsvReaderUtilities.GetHeaderIndexByString(headers, SurfaceLineCsvColumnNames.FirstXColumnName); CheckColumn(colIndexFirstX, tempFilename, SurfaceLineCsvColumnNames.FirstXColumnName); int maxColumns = headers.Count(); double end = Math.Floor((maxColumns - colIndexFirstX + 1) / 3.0); var surflineIndex = 1; while (csv.ReadNextRecord()) { var recordReadError = false; var surfaceLine = new SurfaceLineRecord { SurfaceLineRecordId = surflineIndex }; surflineIndex++; surfaceLine.SurfaceLineId = csv[colIndexSurfaceLineId]; int colIndex = colIndexFirstX; for (var 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 { string 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) { string csvSurfaceLineError = String.Format(LocalizationManager.GetTranslatedText(GetType(), "csvSurfaceLineError"), surfaceLine.SurfaceLineRecordId, colIndex + 1); ErrorMessages.Add(csvSurfaceLineError + e.Message); recordReadError = true; break; } } if (!recordReadError) { ImportedItems.Add(surfaceLine); } } } } finally { File.Delete(tempFilename); Thread.CurrentThread.CurrentCulture = oldcur; } } public List ImportedItems { get; } = new(); public List ErrorMessages { get; set; } = new(); private void CheckColumn(int index, string fileName, string fieldName) { if (index < 0) { string csvHeaderFieldError = LocalizationManager.GetTranslatedText(GetType(), "csvHeaderFieldError"); throw new CsvImporterSurfaceLinesException($"{fileName} : {csvHeaderFieldError} {fieldName}"); } } private int FetchSurfaceLineId(string[] headers) { int colIndexSurfaceLineId = CsvReaderUtilities.GetHeaderIndexByString(headers, SurfaceLineCsvColumnNames.LocationColumnName); if (colIndexSurfaceLineId < 0) { // colIndexSurfaceLineId can be defined with 2 identifiers (ProfileNameColumnName is deprecated, LocationColumnName is the new one) colIndexSurfaceLineId = CsvReaderUtilities.GetHeaderIndexByString(headers, SurfaceLineCsvColumnNames.LocationColumnName); if (colIndexSurfaceLineId < 0) { colIndexSurfaceLineId = CsvReaderUtilities.GetHeaderIndexByString(headers, SurfaceLineCsvColumnNames.ProfileNameColumnName); } } return colIndexSurfaceLineId; } /// /// Copies to temporary file. /// /// Name of the file. /// the name of the temporary file private string CopyToTemporaryFile(string fileName) { string tempPath = Path.GetTempPath(); string tempFileName = Path.Combine(tempPath, Path.GetRandomFileName()); File.Delete(tempFileName); File.Copy(fileName, tempFileName); return tempFileName; } public class SurfaceLineRecord { public string SurfaceLineId { get; set; } public int SurfaceLineRecordId { get; set; } public IList Xcoors { get; set; } = new List(); public IList Ycoors { get; set; } = new List(); public IList Zcoors { get; set; } = new List(); } }