using Aspose.Gis;
using GitConverter.Lib.Logging;
using GitConverter.Lib.Models;
using System;
namespace GitConverter.Lib.Converters
{
///
/// Universal converter implementation that orchestrates a conversion run using Aspose.GIS drivers.
///
///
///
/// UniversalGisConverter is a lightweight orchestrator that performs common conversion
/// workflow steps: validate inputs, prepare output/temp folders, extract archives when
/// necessary, resolve Aspose drivers and invoke VectorLayer.Convert with format-specific
/// options constructed by ConverterUtils.BuildConversionOptions.
///
///
/// Logging behavior (messages produced by Convert):
/// - Debug: detailed parameter trace including the incoming arguments (path values and
/// option strings). Emitted immediately when the conversion starts to help diagnose caller
/// behavior and argument repair logic.
/// - Info: high-level lifecycle events such as "starting conversion", "Conversion succeeded",
/// and conversion attempt boundaries (begin/end). Success messages include the resolved output
/// file path.
/// - Error: validation errors, archive extraction failures, mapping errors (invalid drivers),
/// and unexpected exceptions include error-level logs with exception details where available.
/// - Warn: used for non-fatal issues that merit attention (for example when cleanup fails
/// or when falling back behavior is used elsewhere in helpers).
///
///
/// Callers (including tests) can assert on the presence of key log messages to diagnose failures.
/// Typical messages to look for in logs during troubleshooting:
/// - "CsvConverter.Convert params:" — parameter tracing (note: the message text currently references
/// CsvConverter for historical reasons; it contains the actual parameters passed).
/// - "starting conversion (option='...')" — marks the beginning of the conversion attempt.
/// - "Conversion succeeded: " — emitted on successful completion and includes output path.
/// - "Conversion failed: " — emitted when exceptions occur and includes the exception message.
/// - "Cleaning up temp folder." / "Temp folder '' deleted." — cleanup actions after extraction.
///
///
public class UniversalGisConverter : IConverter
{
///
/// Execute a conversion run from a source GIS artifact to a target format.
///
/// Path to the GIS input (file or archive).
/// Canonical source format option (e.g. "Shapefile").
/// Canonical target format option (e.g. "GeoJson").
/// Destination folder for output files.
/// Temporary folder for archive extraction and intermediates.
/// A indicating success or a detailed failure.
///
///
/// The method logs diagnostic information at multiple levels to aid debugging and test
/// assertions. It performs the following high-level steps:
/// 1. Validate inputs via .
/// 2. Prepare output and temp folders via .
/// 3. Prepare the source file (extract archives if necessary) via
/// .
/// 4. Resolve Aspose drivers using .
/// 5. Build an output path and format-specific options.
/// 6. Invoke VectorLayer.Convert and return the corresponding .
///
///
/// Important logging touch-points (emitted by this method and helpers):
/// - Parameter trace at Debug including all incoming arguments.
/// - Start/finish markers at Info level surrounding the conversion attempt.
/// - Validation and preparation failures logged at Error or Warn depending on severity.
/// - Success and failure of the conversion itself logged at Info and Error respectively.
/// - Cleanup actions logged at Debug/Info and cleanup failures at Warn or Debug.
///
///
/// Note: some log messages currently reference "CsvConverter" in their text due to historical
/// naming; the content of those messages still provides accurate parameter and lifecycle data.
///
///
public ConversionResult Convert(
string gisInputFilePath,
string gisSourceFormatOption,
string gisTargetFormatOption,
string outputFolderPath,
string tempFolderPath)
{
// Parameter trace for diagnostics
Log.Debug($"CsvConverter.Convert params: gisInputFilePath='{gisInputFilePath}', gisSourceFormatOption='{gisSourceFormatOption}', gisTargetFormatOption='{gisTargetFormatOption}',outputFolderPath='{outputFolderPath}', tempFolderPath='{tempFolderPath}'"); Log.Info($"CsvConverter: starting conversion (option='{gisTargetFormatOption}', input='{gisInputFilePath}').");
Log.Info($"CsvConverter: starting conversion (option='{gisTargetFormatOption}', input='{gisInputFilePath}').");
// Step 1: Validate inputs
var validation = ConverterUtils.ValidateInputs(gisInputFilePath, outputFolderPath, tempFolderPath);
if (validation != null) return validation;
// Step 2: Prepare directories
var preparation = ConverterUtils.PreparePaths(outputFolderPath, tempFolderPath);
if (preparation != null) return preparation;
bool extractedToTemp = false;
try
{
// Step 3: Handle archive extraction or single file
var (sourcePath, wasExtracted, results) = ConverterUtils.PrepareSourceFile(
gisInputFilePath,
gisSourceFormatOption,
tempFolderPath);
if (results == null)
{
return results;
}
extractedToTemp = wasExtracted;
// Step 4: Resolve drivers
var srcDriver = ConverterUtils.ConversionOptionToDriver(gisSourceFormatOption) as FileDriver;
var destDriver = ConverterUtils.ConversionOptionToDriver(gisTargetFormatOption) as FileDriver;
if (srcDriver == null || destDriver == null)
{
if(srcDriver == null)
{
Log.Error($"Conversion failed: invalid source format option '{gisSourceFormatOption}'");
}
if(destDriver == null)
{
Log.Error($"Conversion failed: invalid destination format option '{gisTargetFormatOption}'");
}
return ConversionResult.Failure("Invalid source or destination format");
}
// Step 5: Build output path
var outputPath = ConverterUtils.BuildOutputPath(outputFolderPath, gisTargetFormatOption);
// Step 6: Build format-specific options
var options = ConverterUtils.BuildConversionOptions(gisSourceFormatOption, gisTargetFormatOption);
// Step 7: Perform conversion
VectorLayer.Convert(sourcePath, srcDriver, outputPath, destDriver, options);
Log.Info($"Conversion succeeded: {outputPath}");
return ConversionResult.Success($"Converted to {gisTargetFormatOption}; output: {outputPath}");
}
catch (Exception ex)
{
Log.Error($"Conversion failed: {ex.Message}", ex);
return ConversionResult.Failure($"Unexpected error: {ex.Message}");
}
finally
{
Log.Info("Starting conversion attempt.");
// Only cleanup when we actually extracted files into the temp folder
// This avoids removing a pre-existing temp folder that may be managed by the caller.
if (extractedToTemp )
{
Log.Debug("Cleaning up temp folder.");
try
{
ConverterUtils.TryCleanupTempFolder(tempFolderPath);
}
catch (Exception ex)
{
Log.Debug($"Cleanup failed: {ex.Message}");
}
}
Log.Info("Finished conversion attempt.");
}
}
}
}