package com.samknows.measurement.environment;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import com.samknows.libcore.SKPorting;
import com.samknows.measurement.SKApplication;
import com.samknows.measurement.schedule.ScheduleConfig.LocationType;
import com.samknows.measurement.util.DCSStringBuilder;
import com.samknows.measurement.util.SKDateFormat;
import android.location.Address;
import android.location.Location;
import android.location.LocationProvider;
public class LocationData implements DCSData {
public static final String LASTKNOWNLOCATION = "LASTKNOWNLOCATION";
public static final String LOCATION = "LOCATION";
public static final String JSON_LOCATION = "location";
public static final String JSON_LASTKNOWNLOCATION = "last_known_location";
public static final String JSON_LOCATION_TYPE = "location_type";
public static final String JSON_LATITUDE = "latitude";
public static final String JSON_LONGITUDE = "longitude";
// public static final String JSON_MUNICIPALITY = "muncipality";
// public static final String JSON_COUNTRY_NAME = "country_name";
public static final String JSON_ACCURACY = "accuracy";
public static final String JSON_PROVIDERSTATUS = "provider_status";
public static final String JSON_PROVIDERSTATUS_UNKNOWN = "unknown";
public static final String JSON_PROVIDERSTATUS_AVAILABLE = "available";
public static final String JSON_PROVIDERSTATUS_UNAVAILABLE = "unavailable";
private final Location mLocation;
private boolean mIsLastKnown = false;
private final LocationType mLocType;
private int mProviderStatus = LocationProvider.AVAILABLE;
private long mForcedTimeMilli = -1L;
// https://code.google.com/p/android/issues/detail?id=38009
public static List<Address> sGetAddressFromLocation(double lat, double lng, int maxResult) {
return sGetAddressFromLocation(lat, lng, maxResult, null);
}
public static List<Address> sGetAddressFromLocation(double lat, double lng, int maxResult, String withKeyOptional){
String command = "https://maps.googleapis.com/maps/api/geocode/json?";
if (withKeyOptional != null) {
command += "key=";
command += withKeyOptional;
command += "&";
}
//String arguments = String.format("latlng=%1$f,%2$f&sensor=true&result_type=locality|street_address|postal_code", lat, lng);
String arguments = String.format("latlng=%1$f,%2$f&sensor=true", lat, lng);
String finalCommand = command + arguments;
List<Address> retList = new ArrayList<>();
try {
HttpGet httpGet = new HttpGet(finalCommand);
HttpClient client = new DefaultHttpClient();
HttpResponse response;
StringBuilder stringBuilder = new StringBuilder();
response = client.execute(httpGet);
HttpEntity entity = response.getEntity();
InputStream stream = entity.getContent();
int b;
while ((b = stream.read()) != -1) {
stringBuilder.append((char) b);
}
JSONObject jsonObject = new JSONObject();
jsonObject = new JSONObject(stringBuilder.toString());
if ("OK".equalsIgnoreCase(jsonObject.getString("status"))
&& (jsonObject.has("results"))
)
{
JSONArray results = jsonObject.getJSONArray("results");
if (results.length() > 0) {
JSONObject place = results.getJSONObject(0);
Locale currentLocale = SKApplication.getAppInstance().getApplicationContext().getResources().getConfiguration().locale;
String cityName = "";
String countryName = "";
String locality = "";
String route = ""; // e.g. MyStreet
String postalTown = ""; // e.g. MyStreet
JSONArray addressComponents = place.getJSONArray("address_components");
for (int i = 0; i < addressComponents.length(); i++) {
JSONObject component = addressComponents.getJSONObject(i);
JSONArray types = component.getJSONArray("types");
for (int j = 0; j < types.length(); j++) {
Object x = types.get(j);
if (x instanceof String) {
String typeCode = (String) x;
if (typeCode.equals("locality")) {
cityName = component.getString("long_name");
} else if (typeCode.equals("country")) {
countryName = component.getString("long_name");
} else if (typeCode.equals("route")) {
route = component.getString("long_name");
} else if (typeCode.equals("postal_town")) {
postalTown = component.getString("long_name");
}
}
}
}
Address addr = new Address(currentLocale);
addr.setLatitude(lat);
addr.setLongitude(lng);
addr.setCountryName(countryName);
if (locality.length() == 0) {
locality = postalTown;
}
addr.setLocality(locality);
addr.setAddressLine(0, route);
addr.setAddressLine(1, postalTown);
retList.add(addr);
}
} else {
// Most likely reason - we're offline!
SKPorting.sAssert(false);
}
} catch (ClientProtocolException e) {
//Log.e(MyGeocoder.class.getName(), "Error calling Google geocode webservice.", e);
SKPorting.sAssert(false);
} catch (IOException e) {
//Log.e(MyGeocoder.class.getName(), "Error calling Google geocode webservice.", e);
SKPorting.sAssert(false);
} catch (JSONException e) {
//Log.e(MyGeocoder.class.getName(), "Error parsing Google geocode webservice response.", e);
SKPorting.sAssert(false);
} catch (Exception e) {
SKPorting.sAssert(false);
}
return retList;
}
public static List<Address> sGetAddressFromPostcode(String postcode, int maxResult, String withKey) {
// Spaces will cause trouble!
postcode = postcode.replace(" ", "");
String command = "https://maps.googleapis.com/maps/api/geocode/json?";
command += "key=";
command += withKey;
command += "&";
//String arguments = String.format("latlng=%1$f,%2$f&sensor=true&result_type=locality|street_address|postal_code", lat, lng);
String arguments = String.format("address=" + postcode + "&sensor=true");
String finalCommand = command + arguments;
List<Address> retList = new ArrayList<>();
try {
HttpGet httpGet = new HttpGet(finalCommand);
HttpClient client = new DefaultHttpClient();
HttpResponse response;
StringBuilder stringBuilder = new StringBuilder();
response = client.execute(httpGet);
HttpEntity entity = response.getEntity();
InputStream stream = entity.getContent();
int b;
while ((b = stream.read()) != -1) {
stringBuilder.append((char) b);
}
JSONObject jsonObject = new JSONObject();
jsonObject = new JSONObject(stringBuilder.toString());
if ("OK".equalsIgnoreCase(jsonObject.getString("status"))
&& (jsonObject.has("results"))
) {
JSONArray results = jsonObject.getJSONArray("results");
if (results.length() > 0) {
JSONObject place = results.getJSONObject(0);
Locale currentLocale = SKApplication.getAppInstance().getApplicationContext().getResources().getConfiguration().locale;
String cityName = "";
String countryName = "";
String locality = "";
String route = ""; // e.g. MyStreet
String postalTown = ""; // e.g. MyStreet
Double latitude = null;
Double longitude = null;
//JSONArray array = result.getJSONArray("results");
if (place.has("geometry")) {
JSONObject geometry = place.getJSONObject("geometry");
if (geometry.has("location")) {
JSONObject location = geometry.getJSONObject("location");
if (location.has("lat")) {
latitude = location.getDouble("lat");
}
if (location.has("lng")) {
longitude = location.getDouble("lng");
}
}
}
//JSONArray array = result.getJSONArray("results");
JSONArray addressComponents = place.getJSONArray("address_components");
for (int i = 0; i < addressComponents.length(); i++) {
JSONObject component = addressComponents.getJSONObject(i);
JSONArray types = component.getJSONArray("types");
for (int j = 0; j < types.length(); j++) {
if (types.getString(j).equals("locality")) {
cityName = component.getString("long_name");
} else if (types.getString(j).equals("country")) {
countryName = component.getString("long_name");
} else if (types.getString(j).equals("route")) {
route = component.getString("long_name");
} else if (types.getString(j).equals("postal_town")) {
postalTown = component.getString("long_name");
}
}
}
Address addr = new Address(currentLocale);
addr.setPostalCode(postcode);
addr.setCountryName(countryName);
if (locality.length() == 0) {
locality = postalTown;
}
addr.setLocality(locality);
addr.setAddressLine(0, postalTown);
addr.setAddressLine(1, route);
if (latitude != null) {
addr.setLatitude(latitude);
}
if (longitude != null) {
addr.setLongitude(longitude);
}
retList.add(addr);
}
} else {
// Most likely reason - we're offline!
SKPorting.sAssert(false);
}
} catch (ClientProtocolException e) {
//Log.e(MyGeocoder.class.getName(), "Error calling Google geocode webservice.", e);
SKPorting.sAssert(false);
} catch (IOException e) {
//Log.e(MyGeocoder.class.getName(), "Error calling Google geocode webservice.", e);
SKPorting.sAssert(false);
} catch (JSONException e) {
//Log.e(MyGeocoder.class.getName(), "Error parsing Google geocode webservice response.", e);
SKPorting.sAssert(false);
} catch (Exception e) {
SKPorting.sAssert(false);
}
return retList;
}
public void setLocationTimeMilli(long timeMilli) {
// This is used ONLY for special cases.
//mLocation.setTime(timeMilli);
mForcedTimeMilli = timeMilli;
}
// public String mMuncipality = "";
// public String mCountryName = "";
private static String providerStatusToString(int providerStatus){
String ret = JSON_PROVIDERSTATUS_UNKNOWN;
switch(providerStatus){
case LocationProvider.OUT_OF_SERVICE:
case LocationProvider.TEMPORARILY_UNAVAILABLE:
ret = JSON_PROVIDERSTATUS_UNAVAILABLE;
break;
case LocationProvider.AVAILABLE:
ret = JSON_PROVIDERSTATUS_AVAILABLE;
break;
}
return ret;
}
// private static Location sLastKnownLocation = null;
//
// public static Location sGetLastKnownLocation() {
// synchronized (LocationData.class) {
// return sLastKnownLocation;
// }
// }
private void OnLocationChanged(Location location) {
// synchronized (LocationData.class) {
// sLastKnownLocation = location;
// }
// if (mLocation != null) {
// // TODO - get municipality and country name!
//
// Geocoder geocoder = new Geocoder(SKApplication.getAppInstance().getApplicationContext(), Locale.getDefault());
// if (geocoder == null) {
// SKLogger.sAssert(false);
// } else {
// if (geocoder.isPresent() == false) {
// // Maybe we're on the Emulator!
// SKLogger.sAssert(OtherUtils.isThisDeviceAnEmulator() == true);
// } else {
// try {
// List<Address> addressList = geocoder.getFromLocation(mLocation.getLatitude(), mLocation.getLongitude(), 1);
// if (addressList != null && addressList.size() > 0) {
// Address address = addressList.get(0);
// String city = address.getLocality();
// String country = address.getCountryName();
//
// mMuncipality = city;
// mCountryName = country;
// } else {
// SKLogger.sAssert(false);
// }
// } catch (IOException e) {
// Log.e("LocationData", "Unable connect to Geocoder", e);
// SKLogger.sAssert(false);
// }
// }
// }
// }
}
public LocationData(Location loc, LocationType locType) {
mLocation = loc;
mLocType = locType;
OnLocationChanged(loc);
}
public LocationData(Location location, LocationType locType, int providerStatus){
mLocation = location;
mProviderStatus = providerStatus;
mLocType = locType;
OnLocationChanged(location);
}
public LocationData(boolean isLastKnown, Location loc, LocationType locType) {
mLocation = loc;
mIsLastKnown = isLastKnown;
mLocType = locType;
OnLocationChanged(loc);
}
@Override
public List<String> convert() {
List<String> ret = new ArrayList<>();
DCSStringBuilder dcsBuilder = new DCSStringBuilder();
dcsBuilder.append(mIsLastKnown ? LASTKNOWNLOCATION : LOCATION)
.append(mLocation.getTime() / 1000).append(mLocType + "") // Location time is in milliseconds; we write a value in SECONDS!
.append(mLocation.getLatitude())
.append(mLocation.getLongitude())
.append(mLocation.getAccuracy());
// .append(mMuncipality)
// .append(mCountryName);
ret.add(dcsBuilder.build());
return ret;
}
@Override
public List<JSONObject> getPassiveMetric() {
SKPorting.sAssert(getClass(), false);
return new ArrayList<>();
}
@Override
public List<JSONObject> convertToJSON() {
List<JSONObject> ret = new ArrayList<>();
Map<String, Object> loc = new HashMap<>();
loc.put(DCSData.JSON_TYPE, mIsLastKnown ? JSON_LASTKNOWNLOCATION : JSON_LOCATION);
long useTimeMilli = mLocation.getTime();
if (mForcedTimeMilli != -1) {
useTimeMilli = mForcedTimeMilli;
}
loc.put(DCSData.JSON_TIMESTAMP, useTimeMilli / 1000); // Location time is in milliseconds; we write a value in SECONDS!
loc.put(DCSData.JSON_DATETIME, SKDateFormat.sGetDateAsIso8601String(new java.util.Date(useTimeMilli)));
loc.put(JSON_LOCATION_TYPE, mLocType + "");
loc.put(JSON_LATITUDE, mLocation.getLatitude());
loc.put(JSON_LONGITUDE, mLocation.getLongitude());
loc.put(JSON_ACCURACY, mLocation.getAccuracy());
loc.put(JSON_PROVIDERSTATUS, providerStatusToString(mProviderStatus));
// loc.put(JSON_MUNICIPALITY, mMuncipality);
// loc.put(JSON_COUNTRY_NAME, mCountryName);
ret.add(new JSONObject(loc));
return ret;
}
}