package it.mice.voila.runtime.hibernatespatial.utils;

import java.math.BigDecimal;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.google.code.geocoder.Geocoder;
import com.google.code.geocoder.GeocoderRequestBuilder;
import com.google.code.geocoder.model.GeocodeResponse;
import com.google.code.geocoder.model.GeocoderRequest;
import com.google.code.geocoder.model.GeocoderResult;
import com.google.code.geocoder.model.GeocoderStatus;
import com.vividsolutions.jts.geom.Point;

public class GoogleGeocoder implements it.mice.voila.runtime.hibernatespatial.utils.Geocoder {
	private static Log logger = LogFactory.getLog(GoogleGeocoder.class);

	public Point geocode(String address) {
		logger.info("Start geocoding address:" + address);
		Point result = null;
		try {
			final Geocoder geocoder = new Geocoder();
			GeocoderRequest geocoderRequest = new GeocoderRequestBuilder()
					.setAddress(address).setLanguage("it")
					.getGeocoderRequest();
			int attempts = 0;
			int waitMillis = 2000;
			while (attempts < 3) {
				GeocodeResponse geocoderResponse = geocoder.geocode(geocoderRequest);
				if (geocoderResponse.getStatus() == GeocoderStatus.OK) {
					GeocoderResult geocoderResult = geocoderResponse.getResults().iterator().next();
					BigDecimal lat = geocoderResult.getGeometry().getLocation().getLat();
					BigDecimal lng = geocoderResult.getGeometry().getLocation().getLng();
					
					String geometryAsString = "POINT(" + lat + " " + lng + ")";
					result = (Point)GisConvertUtils.toGeometry(geometryAsString);
					break;
				} else {
					if (geocoderResponse.getStatus() == GeocoderStatus.OVER_QUERY_LIMIT) {
						logger.warn("OVER_QUERY_LIMIT Problem geocoding address: " + address
								+ ". request: " + geocoderRequest + ", response: "
								+ geocoderResponse.toString() + ". Wait for " + waitMillis + " millis...");
						Thread.sleep(waitMillis);
						attempts++;
					} else {
						logger.error("Problem geocoding address: " + address
								+ ". request: " + geocoderRequest + ", response: "
								+ geocoderResponse.toString());
						break;
					}
				}
			}
		} catch (Exception e) {
			if (logger.isErrorEnabled()) {
				logger.error(
						"Problem geocoding address: " + address, e);
			}
		}
		logger.info("End geocoding address:" + address + ", result:" + result);
		return result;
	}
}
