package com.papagiannis.tuberun;
import java.util.ArrayList;
import java.util.HashMap;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.Intent;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.net.Uri;
import android.os.Bundle;
import android.provider.SearchRecentSuggestions;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.GoogleMap.OnMarkerClickListener;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import com.papagiannis.tuberun.binders.SelectLinesBinder;
import com.papagiannis.tuberun.fetchers.NearbyStationsForDeparturesFetcher;
import com.papagiannis.tuberun.fetchers.Observer;
import com.papagiannis.tuberun.fetchers.ReverseGeocodeFetcher;
import com.papagiannis.tuberun.fetchers.StationsBusFetcher;
import com.papagiannis.tuberun.fragments.MeMapFragment;
public class SelectLineActivity extends FragmentActivity implements
OnClickListener, LocationListener, Observer {
private static final int FAILED_DIALOG = 1;
public static final String VIEW = "android.Intent.action.VIEW";
protected Button searchButton;
protected EditText searchEditText;
private ListView listView;
private View emptyView;
protected GoogleMap gMap;
protected MeMapFragment mapFragment;
ArrayList<Station> stationsList = new ArrayList<Station>();
private LocationManager locationManager;
ReverseGeocodeFetcher geocoder = new ReverseGeocodeFetcher(this, null);
private NearbyStationsForDeparturesFetcher fetcherStations = new NearbyStationsForDeparturesFetcher(this);
private StationsBusFetcher fetcherBusStops = new StationsBusFetcher(this);
private final Observer observerFetcherBusStops=new Observer() {
@Override
public void update() {
updateBusStops();
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
new SlidingBehaviour(this, R.layout.select_line);
emptyView=findViewById(R.id.empty_layout);
emptyView.setVisibility(View.VISIBLE);
listView = (ListView) findViewById(R.id.nearby_stations_list);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> arg0, View view,
int position, long id) {
onListItemClick(view, position, id);
}
});
searchButton = (Button) findViewById(R.id.search_station_button);
searchButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
onSearchRequested();
}
});
fetcherStations.registerCallback(this);
fetcherBusStops.registerCallback(observerFetcherBusStops);
Intent intent = getIntent();
if (Intent.ACTION_VIEW.equals(intent.getAction())) {
handleIntent(intent);
finish();
return;
}
locationManager = (LocationManager) this
.getSystemService(Context.LOCATION_SERVICE);
gMap = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map)).getMap();
mapFragment=(MeMapFragment) getSupportFragmentManager().findFragmentById(R.id.map_fragment);
gMap.setOnMarkerClickListener(new OnMarkerClickListener() {
@Override
public boolean onMarkerClick(Marker marker) {
startBusDepartures(marker.getSnippet(), marker.getTitle());
return true;
}
});
}
@Override
public void onPause() {
super.onPause();
if (locationManager != null)
locationManager.removeUpdates(this);
fetcherStations.abort();
fetcherStations.deregisterCallback(this);
fetcherBusStops.abort();
fetcherBusStops.deregisterCallback(observerFetcherBusStops);
}
@Override
public void onResume() {
super.onResume();
if (locationManager != null) {
requestLocationUpdates();
fetcherStations.registerCallback(this);
fetcherBusStops.registerCallback(observerFetcherBusStops);
}
}
// LocationListener Methods
private Location lastKnownLocation;
private boolean hasMoved=false;
@Override
public void onLocationChanged(Location l) {
if (MeMapFragment.isBetterLocation(l, lastKnownLocation)) {
lastKnownLocation = l;
fetcherStations.setLocation(l);
fetcherStations.update();
fetcherBusStops.setLocation(l);
fetcherBusStops.update();
if (!hasMoved) {
animateTo(l);
hasMoved=true;
}
}
}
private void animateTo(Location l) {
if (l==null || gMap==null) return;
gMap.animateCamera(CameraUpdateFactory.newLatLng(new LatLng(l.getLatitude(), l.getLongitude())));
}
private void requestLocationUpdates() {
try {
if (locationManager != null) {
locationManager.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER, 10 * 1000, 35, this);
locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER, 10 * 1000, 35, this);
}
} catch (Exception e) {
Log.w("LocationService", e);
}
}
@Override
public void update() {
stationsList = fetcherStations.getResult();
populateStationsList(stationsList);
emptyView.setVisibility(View.GONE);
}
private ArrayList<BusStation> prevResult=new ArrayList<BusStation>();
public void updateBusStops() {
ArrayList<BusStation> result=fetcherBusStops.getResult();
if (result.size()==0) return;
if (prevResult.size()!=result.size()) { //a bit dangerous...
gMap.clear();
final ArrayList<Marker> markers=new ArrayList<Marker>(result.size());
for (BusStation s: result){
MarkerOptions opt=new MarkerOptions();
Location l=s.getLocation();
opt.title(s.getCode());
opt.snippet(s.getName()+" (moving "+s.getHeading()+")");
opt.position(new LatLng(l.getLatitude(),l.getLongitude()));
opt.icon(BitmapDescriptorFactory.fromResource(R.drawable.buses));
markers.add(gMap.addMarker(opt));
}
if (prevResult.size()==0) {
mapFragment.getView().post(new Runnable() {
@Override
public void run() {
mapFragment.animateToMarkers(markers, 0.95, 0.6);
}
});
}
}
prevResult=result;
}
private void populateStationsList(ArrayList<Station> nearby) {
ArrayList<HashMap<String, Object>> list = new ArrayList<HashMap<String, Object>>();
for (Station s : nearby) {
HashMap<String, Object> m = new HashMap<String, Object>();
m.put("line_name", s.getName());
m.put("line_color", null);
m.put("line_image", s.getIcon());
m.put("line_distance", (int)s.getDistanceTo(lastKnownLocation));
list.add(m);
}
SimpleAdapter adapter = new SimpleAdapter(this, list, R.layout.line,
new String[] { "line_name", "line_color", "line_image",
"line_distance" }, new int[] { R.id.line_name,
R.id.line_color, R.id.line_image, R.id.line_distance });
adapter.setViewBinder(new SelectLinesBinder(this));
listView.setAdapter(adapter);
}
@Override
protected void onNewIntent(Intent intent) {
try {
setIntent(intent);
handleIntent(intent);
} catch (Exception e) {
Log.w("SelectLineActivity", e);
}
}
@SuppressWarnings("deprecation")
private void handleIntent(Intent intent) {
String a = intent.getAction();
if (VIEW.equals(a) || Intent.ACTION_VIEW.equals(a)) {
// store the query as a future suggestion
String query = intent.getData().toString();
SearchRecentSuggestions suggestions = new SearchRecentSuggestions(
this, StationsProvider.AUTHORITY, StationsProvider.MODE);
suggestions.saveRecentQuery(query, null);
// and launch the new activity
Uri data = intent.getData();
char first = data.toString().charAt(0);
if (first >= '0' && first <= '9') {
String[] tokens = data.toString().split("_");
if (tokens.length < 2)
showDialog(FAILED_DIALOG);
else
startBusDepartures(tokens[1], tokens[0]);
} else {
String[] tokens = data.toString().split("_");
if (tokens.length != 3)
showDialog(FAILED_DIALOG);
Station s = new Station(tokens[0], tokens[1]);
s.addLineTypeForDepartures(LineType.fromString(tokens[2]));
startDepartures(s);
}
}
}
protected void onListItemClick(View v, int position, long id) {
try {
Station s = stationsList.get(position);
startDepartures(s);
} catch (Exception e) {
Log.w("SelectLine", e);
}
}
private void startDepartures(Station s) {
if (s==null) return;
if (s.locatedOn(LineType.RAIL)) {
startRailDepartures(s);
return;
}
Intent i = null;
i = new Intent(this, DeparturesActivity.class);
i.putExtra("type", "station");
i.putExtra("station", s);
startActivity(i);
}
private void startBusDepartures(String name, String code) {
Intent i = new Intent(this, BusDeparturesActivity.class);
i.putExtra("code", code);
i.putExtra("name", name);
startActivity(i);
}
private void startRailDepartures(Station s) {
Intent i = new Intent(this, RailDeparturesActivity.class);
i.putExtra("station", s);
startActivity(i);
}
@Override
protected Dialog onCreateDialog(int id) {
Dialog result = null;
switch (id) {
case FAILED_DIALOG:
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Internal Error")
.setMessage("Please try another stop/station.")
.setCancelable(true);
result = builder.create();
break;
}
return result;
}
@Override
public void onClick(View v) {
finish();
}
@Override
public void onProviderDisabled(String provider) {
}
@Override
public void onProviderEnabled(String provider) {
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
}