using GisConverter.Lib.Models; namespace GisConverter.Lib.Converters { /// /// Contract for a single converter implementation that knows how to transform a GIS input /// artifact from one canonical format option to another. /// /// /// /// Purpose /// - Implementations of encapsulate the conversion logic required to /// transform content from a detected or declared source format into a requested target format. /// The interface is intentionally minimal so callers (CLI, services, tests) can invoke conversion /// in a uniform, testable manner and consume a single describing /// outcome and diagnostics. /// /// /// /// Expected responsibilities of implementations /// - Validate input paths and options early and return a descriptive failure result for predictable, /// user-facing error conditions (missing files, unsupported format combinations, validation failures). /// - Perform safe archive handling and extraction when the input is an archive; prefer streaming and bounded /// reads for detection where possible. Use the library helpers in ConverterUtils for common behaviors /// such as zip-slip protection and deterministic extraction. /// - Write output artifacts into and use /// for transient intermediate files. Document whether the implementation removes, renames or leaves temporaries. /// - Return a that contains a concise, human-consumable message and an appropriate /// ; include produced file paths or counts in informational results where helpful. /// /// /// /// Error handling and diagnostics /// - Prefer returning for known/expected failure modes (validation, /// missing companion files, format-specific constraints). This keeps callers and tests deterministic. /// - Catch unexpected exceptions at the converter boundary, log diagnostic details (via the host-provided logger) /// and return a failure result rather than allowing exceptions to flow to top-level runners. Only let exceptions /// escape when they represent unrecoverable framework-level failures that cannot be sensibly translated to a /// user-facing message. /// - ConversionResult.Message should be concise and suitable for presenting to users or for inclusion in CI failure /// logs. If additional diagnostic data is necessary include it via structured logging (do not embed large stacks in /// primary user messages). /// /// /// /// Concurrency and thread-safety /// - The interface is stateless. Implementations should avoid mutable static state so multiple converter instances /// may be used concurrently. If a converter shares resources (for example static caches or drivers) it must /// implement its own synchronization and document thread-safety guarantees. /// - Converters should be safe to call from parallel test cases when per-invocation temporary folders are used. /// /// /// /// Side-effects and cleanup conventions /// - Converters may create files and directories under both and /// . When possible: /// - Create output files only under the supplied output folder. /// - Use the supplied temp folder for extraction/intermediates and remove intermediate files on success. /// - Wrap cleanup in best-effort try/catch so cleanup failures do not mask the conversion result; log cleanup failures. /// - Document in your converter whether the temp folder is removed after success or retained for debugging. Tests often /// assert that temp folders are cleaned up for successful conversions; make this behavior explicit. /// /// /// /// Input types and detection /// - Implementations should accept: /// - Single-file inputs (CSV, GeoJSON, KML, etc.) /// - Archive inputs (zip, kmz, 7z, etc.) where the converter may need to detect components inside the archive /// (for example shapefile component files .shp/.shx/.dbf). /// - When the converter depends on a detected source format, prefer the caller to pass the detected canonical /// but be defensive if the option is null/ambiguous. /// /// /// /// Testing expectations /// - Tests that exercise converters call Convert and expect a rather than /// process termination. Implementations MUST NOT call Environment.Exit or otherwise terminate the process. /// - Provide deterministic outcomes for small, well-known sample inputs so unit/integration tests can assert using /// stable tokens and file-presence checks. /// /// /// /// Performance considerations /// - Keep memory usage reasonable when processing large inputs; prefer streaming where possible (for example reading /// and writing features incrementally rather than buffering whole collections in memory). /// - Avoid long-running blocking operations on shared threads; if expensive work is required document expected execution /// time and consider providing progress hooks at the host level. /// /// /// /// Security and safety /// - Treat untrusted input conservatively. When extracting archives validate entry names and paths (use zip-slip protections) /// and do not write files outside the intended temp/output folders. /// - Sanitize any file-based temporary names and limit resource creation to avoid denial-of-service risks in shared environments. /// /// /// /// Localization & messaging /// - Keep user-facing content language-agnostic where possible. Tests assert on /// tokens (case-insensitive substrings) rather than exact messages to remain resilient to localization or wording updates. /// /// /// /// Extension points /// - Converters that require configuration or logging should accept those dependencies from the host (constructor injection) /// rather than reaching into global state. This improves testability and avoids hidden global dependencies. /// /// /// /// Example guidance for implementors /// - Validate args: /// - If is null/empty or the file does not exist return a failure result. /// - Use helper utilities: /// - Use ConverterUtils to extract archives safely and to build canonical output paths. /// - Execute conversion: /// - On success return with optional file path hints. /// - On handled failure return with a helpful diagnostic message. /// - On unexpected exceptions: /// - Log the exception details and return a failure result rather than letting the exception escape. /// /// public interface IConverter { /// /// Execute a conversion run. /// /// Path to the input artifact. May be a single file or an archive. /// Canonical source format option (e.g. "Shapefile"). /// Canonical target format option (e.g. "GeoJson"). /// Destination folder where output files should be written. /// Temporary working folder for extraction and intermediates. /// /// A describing success or failure. On success the result may /// include informational text such as produced file paths; on failure it should include a /// concise message suitable for user-facing diagnostics. /// /// /// Implementations should validate inputs and return appropriate failure results for /// missing/invalid arguments. The method must not call Environment.Exit or terminate /// the process; it is expected to return a result so callers (including unit tests) can /// assert on the outcome. If the converter requires additional configuration or logging it /// should acquire those resources from the surrounding host rather than reaching into global /// state. /// ConversionResult Convert( string gisInputFilePath, string gisSourceFormatOption, string gisTargetFormatOption, string outputFolderPath, string tempFolderPath); } }