package io.adrianulbona.cloc.service;

import ch.hsr.geohash.GeoHash;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import io.github.adrianulbona.cloc.CountryLocator;
import lombok.Data;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import spark.Request;
import spark.Response;

import java.io.IOException;
import java.util.List;
import java.util.stream.Collectors;

import static ch.hsr.geohash.GeoHash.withCharacterPrecision;
import static java.lang.String.format;
import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
import static spark.Spark.*;

/**
 * Created by adrianulbona on 08/08/16.
 */
public class ClocService {

	private final static Logger LOGGER = LoggerFactory.getLogger(ClocService.class);

	private final Gson gson;
	private final CountryLocator countryLocator;

	public static void main(String[] args) throws IOException {
		new ClocService();
	}

	public ClocService() throws IOException {
		LOGGER.info("Initializing Service...");
		this.gson = new Gson();
		this.countryLocator = CountryLocator.fromFreshIndex();
		LOGGER.info("Loaded Country Locator...");

		get("/locate", this::locate, this.gson::toJson);
		get("/locate/:lat/:long", this::locateLatLong, this.gson::toJson);
		exception(JsonSyntaxException.class, (e, req, res) -> halt(SC_BAD_REQUEST, req.body()));
		LOGGER.info("Created Routes...");
	}

	private List<Location> locate(Request req, Response res) {
		final Coordinate coordinate = this.gson.fromJson(req.body(), Coordinate.class);
		return locate(coordinate);
	}

	private List<Location> locateLatLong(Request req, Response res) {
		final Double latitude = Double.valueOf(req.params("lat"));
		final Double longitude = Double.valueOf(req.params("long"));
		return locate(new Coordinate(latitude, longitude));
	}

	private List<Location> locate(Coordinate coordinate) {
		LOGGER.info(format("Searching locations for: %s", coordinate));
		final GeoHash geoHash = withCharacterPrecision(coordinate.getLat(), coordinate.getLon(), 6);
		final List<String> locations = this.countryLocator.locate(geoHash.toBase32());
		LOGGER.info(format("Found %d locations", locations.size()));
		return locations
				.stream()
				.map(Location::new)
				.collect(Collectors.toList());
	}

	@Data
	public static class Coordinate {

		private final double lat;
		private final double lon;
	}

	@Data
	public static class Location {

		private final String countryCode;
	}
}

@@ -44,100 +44,25 @@
 rt c
-h.hsr.geohash.GeoHash;%0Aimport com.google.gson.Gson;%0Aimport com.google.gson.JsonSyntaxExcepti
+om.google.gson.Gs
 on;%0A
@@ -116,28 +116,8 @@
 or;%0A
-import lombok.Data;%0A
 impo
@@ -269,44 +269,8 @@
 ist;
-%0Aimport java.util.stream.Collectors;
 %0A%0Aim
@@ -629,34 +629,8 @@
 );%0A%0A
-%09private final Gson gson;%0A
 %09pri
@@ -847,34 +847,8 @@
 %22);%0A
-%09%09this.gson = new Gson();%0A
 %09%09th
@@ -945,16 +945,48 @@
 ...%22);%0A%0A
+%09%09final Gson gson = new Gson();%0A
 %09%09get(%22/
@@ -991,16 +991,27 @@
 %22/locate
+/:lat/:long
 %22, this:
@@ -1017,23 +1017,25 @@
 ::locate
-, this.
+LatLong, 
 gson::to
@@ -1053,33 +1053,31 @@
 t(%22/locate/:
-lat/:long
+geohash
 %22, this::loc
@@ -1083,22 +1083,17 @@
 cate
-LatLong, this.
+GeoHash, 
 gson
@@ -1103,16 +1103,17 @@
 oJson);%0A
+%0A
 %09%09except
@@ -1120,18 +1120,20 @@
 ion(
-JsonSyntax
+NumberFormat
 Exce
@@ -1185,24 +1185,97 @@
 UEST
-, req.body()
+));%0A%09%09exception(IllegalArgumentException.class, (e, req, res) -%3E halt(SC_BAD_REQUEST
 ));%0A
+%0A
 %09%09LO
@@ -1324,32 +1324,30 @@
 te List%3C
-Location
+String
 %3E locate
 (Request
@@ -1338,16 +1338,23 @@
 %3E locate
+GeoHash
 (Request
@@ -1387,79 +1387,45 @@
 nal 
-Coordinate coordinate = this.gson.fromJson(req.body(), Coordinate.class
+String geohash = req.params(%22geohash%22
 );%0A%09
@@ -1439,26 +1439,23 @@
  locate(
-coordinate
+geohash
 );%0A%09%7D%0A%0A%09
@@ -1463,32 +1463,30 @@
 rivate List%3C
-Location
+String
 %3E locateLatL
@@ -1648,57 +1648,113 @@
 ;%0A%09%09
-return locate(new Coordinate(latitude, longitude)
+final String geohash = withCharacterPrecision(latitude, longitude, 6).toBase32();%0A%09%09return locate(geohash
 );%0A%09
@@ -1770,24 +1770,22 @@
 te List%3C
-Location
+String
 %3E locate
@@ -1789,29 +1789,22 @@
 ate(
-Coordinate coordinate
+String geohash
 ) %7B%0A
@@ -1859,114 +1859,16 @@
 s%22, 
-coordinate));%0A%09%09final GeoHash geoHash = withCharacterPrecision(coordinate.getLat(), coordinate.getLon(), 6
+geohash)
 );%0A%09
@@ -1933,23 +1933,12 @@
 (geo
-Hash.toBase32()
+hash
 );%0A%09
@@ -1967,20 +1967,11 @@
 ound
+:
  %25
-d location
 s%22, 
@@ -1983,15 +1983,8 @@
 ions
-.size()
 ));%0A
@@ -2005,262 +2005,8 @@
 ions
-%0A%09%09%09%09.stream()%0A%09%09%09%09.map(Location::new)%0A%09%09%09%09.collect(Collectors.toList());%0A%09%7D%0A%0A%09@Data%0A%09public static class Coordinate %7B%0A%0A%09%09private final double lat;%0A%09%09private final double lon;%0A%09%7D%0A%0A%09@Data%0A%09public static class Location %7B%0A%0A%09%09private final String countryCode
 ;%0A%09%7D

Simplify API