package eu.simstadt.regionchooser;

import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Scanner;
import java.util.concurrent.Callable;
import org.osgeo.proj4j.CoordinateReferenceSystem;
import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.Model.CommandSpec;
import picocli.CommandLine.Option;
import picocli.CommandLine.Spec;

// Example usage:
// --input /home/ricou/Desktop/CGSC_Repository/Würzburg.proj/LoD2_566_5516_2_BY.gml,/home/ricou/Desktop/CGSC_Repository/Würzburg.proj/LoD2_568_5516_2_BY.gml
// --output /home/ricou/Desktop/output.gml
// --wkt /home/ricou/Desktop/grombuhl.txt


@Command(name = "region_chooser", mixinStandardHelpOptions = true, version = "regionChooser x.x", description = "Extracts a region from one or more citygmls.", sortOptions = false)
class RegionChooserCommandLineInterface implements Callable<Integer>
{
	@Spec
	CommandSpec spec;

	//TODO: Add --gui?

	@Option(names = { "-i",
			"--input" }, required = true, split = ",", description = "Citygml files to extract from", paramLabel = "input.gml")
	//TODO: Allow folders too?
	Path[] citygmls;

	@Option(names = { "-o",
			"--output" }, required = true, description = "Output file", paramLabel = "output.gml")
	Path outputCityGML;

	@Option(names = { "-e", "--epsg" }, description = "EPSG id for coordinate reference system", paramLabel = "31467")
	Integer espgId;

	@Option(names = { "-l",
			"--local" }, description = "Are WKT coordinates in local CRS?", paramLabel = "local_coordinates?")
	boolean localCoordinates;

	@Option(names = { "-w",
			"--wkt" }, required = true, description = "File containing WKT polygon, or - for stdin", paramLabel = "polygon.wkt")
	String wktFile = "-";

	@Override
	public Integer call() throws Exception {
		CoordinateReferenceSystem localCRS;

		if (espgId == null) {
			localCRS = RegionChooserUtils.crsFromCityGMLHeader(citygmls[0]);
		} else {
			localCRS = RegionChooserUtils.crsFromSrsName("EPSG:" + espgId);
		}
		logInfo("Coordinate system: " + localCRS);

		String wktPolygon;

		if (wktFile.equals("-")) {
			if (System.in.available() == 0) {
				throw new IllegalArgumentException("Please provide \"POLYGON((x1 y1, x2 y2, ...))\" to standard input.");
			} else {
				wktPolygon = getInput();
			}
		} else {
			wktPolygon = new String(Files.readAllBytes(Paths.get(wktFile)), StandardCharsets.UTF_8);
			if (wktPolygon.isEmpty()) {
				throw new IllegalArgumentException("Please write \"POLYGON((x1 y1, x2 y2, ...))\" inside " + wktFile);
			}
		}

		if (!localCoordinates) {
			// WKT coordinates are in WGS84, so should be first converted to srsName
			wktPolygon = RegionChooserUtils.wktPolygonToLocalCRS(wktPolygon, localCRS);
		}

		logInfo("WKT Polygon expressed in local coordinates: " + wktPolygon);

		StringBuilder sb = RegionExtractor.selectRegionDirectlyFromCityGML(wktPolygon, localCRS.toString(), citygmls);

		RegionChooserUtils.writeStringBuilderToFile(sb, outputCityGML);

		return 0;
	}

	private void logInfo(String message) {
		spec.commandLine().getErr().println(message);
	}

	private static String getInput() {
		try (Scanner myObj = new Scanner(System.in)) {
			return myObj.nextLine();
		}
	}

	// this example implements Callable, so parsing, error handling and handling user
	// requests for usage help or version help can be done with one line of code.
	public static void main(String... args) {
		int exitCode = new CommandLine(new RegionChooserCommandLineInterface()).execute(args);
		System.exit(exitCode);
	}
}