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