package com.papagiannis.tuberun;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.content.Intent;
import android.graphics.Color;
import android.location.Location;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.GoogleMap.OnCameraChangeListener;
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.CameraPosition;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.LatLngBounds;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.android.gms.maps.model.PolylineOptions;
import com.papagiannis.tuberun.cyclehire.CycleHireStation;
import com.papagiannis.tuberun.fetchers.Observer;
import com.papagiannis.tuberun.fetchers.RoutesBusFetcher;
import com.papagiannis.tuberun.fragments.MeMapFragment;
import com.papagiannis.tuberun.overlays.TubeMarkerClickListener;
import com.papagiannis.tuberun.overlays.RailMarkerClickListener;
public class NearbyMapActivity extends FragmentActivity implements Observer {
private static final int SELECT_DIRECTION_DIALOG = -1;
private static final int WAIT_DIALOG = -2;
protected GoogleMap gMap;
protected MeMapFragment mapFragment;
final NearbyMapActivity self = this;
private LinearLayout keyLayout;
private String type = "";
// when type==bus
String point1 = null;
String point2 = null;
ArrayList<String> routes = new ArrayList<String>();
ArrayList<Station> tubeStations = new ArrayList<Station>();
ArrayList<CycleHireStation> csStations = new ArrayList<CycleHireStation>();
ArrayList<OysterShop> oysterShops = new ArrayList<OysterShop>();
ArrayList<Station> railStations = new ArrayList<Station>();
RoutesBusFetcher busFetcher = new RoutesBusFetcher(this);
@SuppressWarnings("unchecked")
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.full_screen_map_fragment);
keyLayout = (LinearLayout) findViewById(R.id.key_layout);
gMap = ((SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map)).getMap();
mapFragment = (MeMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map_fragment);
try {
Bundle extras = getIntent().getExtras();
type = (String) extras.get("type");
if (type.equals("bus")) {
routes = (ArrayList<String>) extras.get("routes");
point1 = extras.getString("point1");
point2 = extras.getString("point2");
askForDirection();
} else if (type.equals("tube")) {
tubeStations = (ArrayList<Station>) extras.get("stations");
showTubePushPins();
} else if (type.equals("cyclehire")) {
csStations = (ArrayList<CycleHireStation>) extras
.get("stations");
showCycleHirePushPins();
} else if (type.equals("oystershop")) {
oysterShops = (ArrayList<OysterShop>) extras.get("stations");
showOysterPushPins();
} else if (type.equals("rail")) {
railStations = (ArrayList<Station>) extras.get("stations");
showRailPushPins();
}
} catch (Exception e) {
Log.w("Directions", e);
}
}
@SuppressWarnings("deprecation")
private void askForDirection() {
if (point1 != null && point2 != null) {
showDialog(SELECT_DIRECTION_DIALOG);
} else
requestBusRoutes(0);
}
@SuppressWarnings("deprecation")
private void requestBusRoutes(int direction) {
showDialog(WAIT_DIALOG);
busFetcher.registerCallback(this);
busFetcher.setRoutes(routes);
busFetcher.setDirection(direction);
busFetcher.update();
}
@Override
public void update() {
displayRoute = true;
wait_dialog.dismiss();
if (isBus()) {
showBusPushpins(busFetcher.getDirection());
} else if (isCycle()) {
} else if (isTube()) {
}
}
private void generateKey(HashMap<String, Integer> resultColors) {
for (String route : routes) {
LinearLayout ll = new LinearLayout(this);
ll.setOrientation(LinearLayout.HORIZONTAL);
ImageView iv = new ImageView(this);
iv.setBackgroundColor(resultColors.get(route));
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
30, 8);
params.gravity = Gravity.CENTER_VERTICAL;
params.rightMargin = 5;
iv.setLayoutParams(params);
TextView tv = new TextView(this);
tv.setText(route);
tv.setTextColor(Color.WHITE);
tv.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT);
ll.addView(iv);
ll.addView(tv);
keyLayout.addView(ll);
}
keyLayout.setVisibility(View.VISIBLE);
}
private ArrayList<Marker> createMarkers(List<? extends AbstractLocatable> stations, int bitmap,
SnippetGenerator sGen) {
if (stations.size() == 0)
return new ArrayList<Marker>();
final ArrayList<Marker> markers = new ArrayList<Marker>(stations.size());
for (AbstractLocatable s : stations) {
MarkerOptions opt = new MarkerOptions();
Location l = s.getLocation();
opt.title(s.getName());
opt.snippet(sGen.getSnippet(s));
opt.position(new LatLng(l.getLatitude(), l.getLongitude()));
opt.icon(BitmapDescriptorFactory.fromResource(bitmap));
markers.add(gMap.addMarker(opt));
}
return markers;
}
private void animateToMarkers(final ArrayList<Marker> markers) {
mapFragment.getView().post(new Runnable() {
@Override
public void run() {
mapFragment.animateToMarkers(markers);
}
});
}
private void showTubePushPins() {
gMap.setOnMarkerClickListener(new TubeMarkerClickListener(this));
animateToMarkers(createMarkers(tubeStations, R.drawable.tube, new SnippetGenerator() {
@Override
public String getSnippet(AbstractLocatable l) {
Station st=(Station)l;
return st.getCode();
}
}));
}
private void showBusPushpins(int direction) {
gMap.setOnMarkerClickListener(new OnMarkerClickListener() {
@Override
public boolean onMarkerClick(final Marker marker) {
showBusDepartures(marker.getSnippet(), marker.getTitle());
return true;
}
});
generateKey(busFetcher.getResultColors());
for (PolylineOptions line:busFetcher.getPolylines()) {
gMap.addPolyline(line);
}
final ArrayList<Marker> markers = new ArrayList<Marker>();
for (String route:routes) {
markers.addAll(createMarkers(
busFetcher.getRouteStops(route).get(direction),
R.drawable.buses,
new SnippetGenerator() {
@Override
public String getSnippet(AbstractLocatable st) {
BusStation bs=(BusStation) st;
return bs.getCode();
}
}));
}
gMap.setOnCameraChangeListener(new OnCameraChangeListener() {
double previousZoom=-1.0;
final int ZOOM_LIMIT=14;
@Override
public void onCameraChange(CameraPosition position) {
if (position.zoom>ZOOM_LIMIT && (previousZoom<=ZOOM_LIMIT || previousZoom==-1.0)) {
for (Marker m:markers) m.setVisible(true);
}
else if (position.zoom<=ZOOM_LIMIT && (previousZoom>ZOOM_LIMIT || previousZoom==-1.0)) {
for (Marker m:markers) m.setVisible(false);
}
}
});
final LatLngBounds bounds=busFetcher.getBounds();
if (bounds==null) return;
mapFragment.getView().post(new Runnable() {
@Override
public void run() {
gMap.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds, 20));
}
});
}
public void showBusDepartures(String code, String snippet) {
Intent i=new Intent(this, BusDeparturesActivity.class);
i.putExtra("code", code);
i.putExtra("name", snippet);
startActivity(i);
}
private void showCycleHirePushPins() {
animateToMarkers(createMarkers(csStations, R.drawable.cycle_hire_pushpin,
new SnippetGenerator() {
@Override
public String getSnippet(AbstractLocatable st) {
CycleHireStation cst = (CycleHireStation) st;
return "Available Bikes: " + cst.getnAvailableBikes()
+ "\n" + "Available Docks: "
+ cst.getnEmptyDocks();
}
}));
}
private void showOysterPushPins() {
animateToMarkers(createMarkers(oysterShops, R.drawable.ic_oyster_selected,
new SnippetGenerator() {
@Override
public String getSnippet(AbstractLocatable st) {
return null;
}
}));
}
private void showRailPushPins() {
gMap.setOnMarkerClickListener(new RailMarkerClickListener(this));
animateToMarkers(createMarkers(railStations, R.drawable.rail,
new SnippetGenerator() {
@Override
public String getSnippet(AbstractLocatable st) {
Station s=(Station) st;
return s.getCode();
}
}));
}
private Dialog wait_dialog;
@Override
protected Dialog onCreateDialog(int id) {
switch (id) {
case SELECT_DIRECTION_DIALOG:
String[] items = { point2, point1 };
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Pick a direction");
builder.setItems(items, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int item) {
requestBusRoutes(item);
}
});
builder.setOnCancelListener(new OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
self.finish();
}
});
wait_dialog = builder.create();
return wait_dialog;
case WAIT_DIALOG:
String msg = "";
if (isBus()) {
msg = "Fetching bus route";
if (routes.size() > 1)
msg += "s";
}
wait_dialog = ProgressDialog
.show(this, msg, "Please wait...", true);
wait_dialog.setCancelable(true);
wait_dialog
.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
if (busFetcher != null)
busFetcher.abort();
self.finish();
}
});
return wait_dialog;
}
return wait_dialog;
}
boolean displayRoute = true;
private boolean isBus() {
return type.equals("bus");
}
private boolean isCycle() {
return type.equals("cycle");
}
private boolean isTube() {
return type.equals("tube");
}
@Override
protected void onDestroy() {
if (busFetcher != null)
busFetcher.abort();
super.onDestroy();
}
private interface SnippetGenerator {
String getSnippet(AbstractLocatable st);
}
}