package org.azavea.lists;
import android.content.Context;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.widget.Toast;
import org.azavea.helpers.Logger;
import org.azavea.lists.data.DisplayablePlot;
import org.azavea.otm.App;
import org.azavea.otm.R;
import org.azavea.otm.data.Plot;
import org.azavea.otm.data.PlotContainer;
import org.azavea.otm.fields.TextField;
import org.azavea.otm.rest.RequestGenerator;
import org.azavea.otm.rest.handlers.ContainerRestHandler;
import org.json.JSONException;
import java.util.ArrayList;
import java.util.Locale;
import java.util.Map;
public class NearbyList implements InfoList {
private static final long MIN_TIME_DELAY = 5000;
private PlotContainer nearbyPlots;
private double lat;
private double lon;
private final ArrayList<ListObserver> observers = new ArrayList<>();
private LocationManager locationManager;
private LocationListener locationListener;
private boolean filterRecent;
private boolean filterPending;
private final Context context;
public NearbyList(Context context) {
lat = App.getCurrentInstance().getStartPos().latitude;
lon = App.getCurrentInstance().getStartPos().longitude;
filterRecent = false;
filterPending = false;
this.context = context;
}
public NearbyList(Context context, double lat, double lon) {
this.lat = lat;
this.lon = lon;
filterRecent = false;
filterPending = false;
this.context = context;
}
@Override
public void setupLocationUpdating(Context applicationContext) {
locationManager = (LocationManager) applicationContext.getSystemService(Context.LOCATION_SERVICE);
locationListener = new LocationListener() {
@Override
public void onLocationChanged(Location location) {
lat = location.getLatitude();
lon = location.getLongitude();
update();
}
@Override
public void onProviderEnabled(String provider) {
// TODO Auto-generated method stub
}
@Override
public void onProviderDisabled(String provider) {
// TODO Auto-generated method stub
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
// TODO Auto-generated method stub
}
};
if (locationManager != null) {
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,
MIN_TIME_DELAY, 0, locationListener);
setInitialLocation();
}
}
@Override
public void removeLocationUpdating() {
locationManager.removeUpdates(locationListener);
}
public void setFilterRecent(boolean filterRecent) {
this.filterRecent = filterRecent;
}
public void setFilterPending(boolean filterPending) {
this.filterPending = filterPending;
}
@Override
public DisplayablePlot[] getDisplayValues() {
ArrayList<DisplayablePlot> listValues = new ArrayList<>();
String mainInfo;
String supplementaryInfo;
String distance;
try {
if (nearbyPlots != null) {
Map<Integer, Plot> plotObjects = nearbyPlots.getAll();
for (Plot p : plotObjects.values()) {
if (p.getTree() != null) {
mainInfo = getSpecies(p);
supplementaryInfo = getDiameter(p);
} else {
mainInfo = "Unassigned plot";
supplementaryInfo = getPlotId(p);
}
distance = getDisplayDistance(p);
listValues.add(new DisplayablePlot(p, mainInfo + ", " + supplementaryInfo + ", " + distance));
}
}
} catch (JSONException e) {
Logger.error("JSONException from nearby plot list", e);
}
return listValues.toArray(new DisplayablePlot[0]);
}
private void setInitialLocation() {
Criteria crit = new Criteria();
crit.setAccuracy(Criteria.ACCURACY_FINE);
String provider = locationManager.getBestProvider(crit, true);
if (provider != null) {
Location loc = locationManager.getLastKnownLocation(provider);
if (loc != null) {
lat = loc.getLatitude();
lon = loc.getLongitude();
update();
}
}
}
public void update() {
RequestGenerator rg = new RequestGenerator();
rg.getPlotsNearLocation(lat, lon, filterRecent, filterPending, new ContainerRestHandler<PlotContainer>(
new PlotContainer()) {
@Override
public void dataReceived(PlotContainer responseObject) {
nearbyPlots = responseObject;
notifyObservers();
}
@Override
public void failure(Throwable e, String message) {
Toast.makeText(context, "Could not load nearby trees", Toast.LENGTH_SHORT).show();
}
});
}
private void notifyObservers() {
for (ListObserver o : observers) {
o.update();
}
}
private String getDisplayDistance(Plot p) {
String distance;
float dist = getDistanceFromMyLocation(p); // this is always in meters.
Locale locale = Locale.getDefault();
if (dist == -1.0) {
distance = "Distance unknown";
} else if (locale != null && locale.equals(Locale.US)) {
float feet = (float) (dist * 3.38084);
distance = Math.round(feet) + "ft";
} else {
distance = Math.round(dist) + "m";
}
return distance;
}
private String getPlotId(Plot p) {
String supplementaryInfo;
try {
supplementaryInfo = Integer.toString(p.getId());
} catch (Exception e) {
Logger.warning("Tree missing id field", e);
supplementaryInfo = "Missing ID";
}
return supplementaryInfo;
}
private String getDiameter(Plot p) {
String dbhKey = "tree.diameter";
TextField dbhField = (TextField) App.getFieldManager().getField(dbhKey);
String diameter = context.getString(R.string.diameter_missing);
try {
Double dbh = p.getTree().getDiameter();
if (dbhField != null && dbh != null && dbh > 0d) {
diameter = Double.toString(dbh) + " " + dbhField.unitText;
}
} catch (JSONException e) {
Logger.error("Unable to get tree diameter field", e);
}
return diameter;
}
private String getSpecies(Plot p) {
String species;
String speciesDefault = context.getString(R.string.species_missing);
try {
species = p.getTitle();
if (species == null) {
species = speciesDefault;
}
} catch (Exception e) {
species = speciesDefault;
}
return species;
}
@Override
public void addObserver(ListObserver observer) {
this.observers.add(observer);
}
@Override
public Object[] getListValues() {
Object[] plots;
try {
Map<Integer, Plot> plotMap = nearbyPlots.getAll();
plots = plotMap.values().toArray();
} catch (JSONException e) {
Logger.error("Error parsing nearby plot JSON", e);
return null;
}
return plots;
}
private float getDistanceFromMyLocation(Plot p) {
float[] distance = new float[1];
try {
double plotLat = p.getGeometry().getY();
double plotLon = p.getGeometry().getX();
Location.distanceBetween(lat, lon, plotLat, plotLon, distance);
return distance[0];
} catch (Exception e) {
return -1;
}
}
}