/* Copyright (c) 2008 -- CommonsWare, LLC

	 Licensed under the Apache License, Version 2.0 (the "License");
	 you may not use this file except in compliance with the License.
	 You may obtain a copy of the License at

		 http://www.apache.org/licenses/LICENSE-2.0

	 Unless required by applicable law or agreed to in writing, software
	 distributed under the License is distributed on an "AS IS" BASIS,
	 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
	 See the License for the specific language governing permissions and
	 limitations under the License.
*/
	 
package com.commonsware.tourit;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentReceiver;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.drawable.PaintDrawable;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationProvider;
import android.location.LocationManager;
import android.net.Uri;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ImageButton;
import android.widget.TextView;
import android.widget.Spinner;
import android.widget.Toast;
import com.google.android.maps.*;
import com.google.android.maps.MapView;

public class TourMapActivity extends MapActivity {
	private static final int SPINNER_ID = Menu.FIRST+1;
	private static final int MAP_ID = Menu.FIRST+2;
	private static final int CONFIG_ID = Menu.FIRST+3;
	private static final int HELP_ID = Menu.FIRST+100;
	private static final int CLOSE_ID = Menu.FIRST+4;
	protected LocationIntentReceiver intentReceiver=new LocationIntentReceiver();
	protected final long MINIMUM_DISTANCECHANGE_FOR_UPDATE=5; // in Meters
	protected final long MINIMUM_TIME_BETWEEN_UPDATE=1000; // in Milliseconds
	protected static final String LOCATION_CHANGED_ACTION=new String("android.intent.action.LOCATION_CHANGED");
	protected final IntentFilter myIntentFilter=new IntentFilter(LOCATION_CHANGED_ACTION);
	protected final Intent myIntent=new Intent(LOCATION_CHANGED_ACTION);
	
	private MapView map;
	private MapController mc;
	private Spinner spin;
	private ImageButton goToPoint;
	private Cursor c;
	private Tour tour;
	private Waypoint start;
	private Paint paint1=new Paint();
	private Paint paint2=new Paint();
	private Paint paint3=new Paint();
	private Menu.Item spinMenu;
	private Location myLocation=null;
	private LocationProvider provider=null;
	private LocationManager myLocationManager=null;
	private boolean showMyLocation=true;
	private boolean followMe=false;
	
	@Override
	public void onCreate(Bundle icicle) {
		super.onCreate(icicle);
		setContentView(R.layout.map);
		
		map=(MapView)findViewById(R.id.map);
		map.setReticleDrawMode(MapView.ReticleDrawMode.DRAW_RETICLE_UNDER);
		
		if (!map.isEdgeZooming()) {
			map.toggleEdgeZooming();
		}
		
		mc=map.getController();
		paint1.setAntiAlias(true);
		paint2.setARGB(255, 255, 255, 255);
		paint3.setARGB(255, 255, 0, 0);
		
		myLocationManager=(LocationManager)getSystemService(Context.LOCATION_SERVICE);
 		
		if (getIntent()!=null && getIntent().getData()!=null) {
			try {
				c=managedQuery(getIntent().getData(), Tour.PROJECTION, null, null);
				c.first();
				tour=new Tour(getIntent().getData(), c);
				setTitle("TourIt! - Map of "+tour.getTitle());
				
				int startIndex=getIntent().getIntExtra(TourViewActivity.CURRENT_WAYPOINT, -1);
				
				if (startIndex>-1) {
					start=tour.getRoute().get(startIndex);
				}
				else {
					start=tour.getRoute().get(0);
				}
				
				while (start!=null && start.getPosition()==null) {
					if (start.getToDirection()==null) {
						start=null;
					}
					else {
						start=start.getToDirection().getToWaypoint();
					}
				}
				
				if (start!=null) {
					mc.centerMapTo(start.getPosition(), true);
					mc.zoomTo(16);
				}
				
				ArrayAdapter<Waypoint> aa=new ArrayAdapter<Waypoint>(this,
																	R.layout.spinner,
																	tour.getRoute());
				
				aa.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
				spin=(Spinner)findViewById(R.id.waypoints);
				spin.setAdapter(aa);
				
				goToPoint=(ImageButton)findViewById(R.id.go);
				
				goToPoint.setOnClickListener(new View.OnClickListener() {
					public void onClick(View view) {
						Waypoint pt=(Waypoint)spin.getSelectedItem();
						
						if (pt!=null) {
							mc.centerMapTo(pt.getPosition(), true);
						}
					}
				});
			}
			catch (Throwable t) {
				android.util.Log.e("TourIt", "Exception creating tour", t);
			}
		}
		
		map.createOverlayController().add(new RouteOverlay(this), true);
		map.requestFocus();
		updateView();
	}
	
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		menu.setQwertyMode(true);
		spinMenu=menu.add(0, SPINNER_ID, "Show Picker", R.drawable.misc);
		spinMenu.setAlphabeticShortcut('p');
		menu.add(0, MAP_ID, "Full Map", R.drawable.map)
				.setAlphabeticShortcut('m');
		menu.add(0, CONFIG_ID, "Config", R.drawable.configure);
		menu.add(0, HELP_ID, "Help", R.drawable.help)
				.setAlphabeticShortcut('h');
		menu.add(0, CLOSE_ID, "Close", R.drawable.eject)
				.setAlphabeticShortcut('c');

		return(super.onCreateOptionsMenu(menu));
	}

	@Override
	public boolean onOptionsItemSelected(Menu.Item item) {
		switch (item.getId()) {
			case SPINNER_ID:
				if (spin.getVisibility()==View.VISIBLE) {
					spin.setVisibility(View.INVISIBLE);
					goToPoint.setVisibility(View.INVISIBLE);
					spinMenu.setTitle("Show Picker");
				}
				else {
					spin.setVisibility(View.VISIBLE);
					goToPoint.setVisibility(View.VISIBLE);
					spinMenu.setTitle("Hide Picker");
				}
				
				return(true);
				
			case MAP_ID:
				Point here=map.getMapCenter();
				Double lat=here.getLatitudeE6()/1E6;
				Double lon=here.getLongitudeE6()/1E6;
				Uri uri=Uri.parse("geo:"+lat.toString()+","+lon.toString());
				
				startActivity(new Intent(Intent.VIEW_ACTION, uri));
				return(true);
				
			case CONFIG_ID:
				startActivity(new Intent(this, ConfigActivity.class));
				return(true);
				
			case HELP_ID:
				Intent i=new Intent(this, HelpActivity.class);
				
				i.putExtra(HelpActivity.PAGE, "map");
				startActivity(i);
				return(true);
				
			case CLOSE_ID:
				finish();
				return(true);
		}

		return(super.onOptionsItemSelected(item));
	}

	@Override
	public void onResume() {
		super.onResume();
		
		SharedPreferences prefs=getSharedPreferences(ConfigActivity.PREFS, 0);
		
		showMyLocation=prefs.getBoolean(ConfigActivity.SHOW_LOCATION, true);
		followMe=prefs.getBoolean(ConfigActivity.FOLLOW_ME, true);
		
		String providerName=prefs.getString(ConfigActivity.LOCATION_PROVIDER, null);
		
		if (providerName!=null) {
			for (LocationProvider p : myLocationManager.getProviders()) {
				if (p.getName().equals(providerName)) {
					provider=p;
					break;
				}
			}
		}
		
		if (provider==null) {
			Criteria crit=new Criteria();
			
			crit.setCostAllowed(true);
			crit.setSpeedRequired(false);
			crit.setBearingRequired(false);
			crit.setAltitudeRequired(false);
			
			provider=myLocationManager.getBestProvider(crit);
		}
		
		
		if (provider!=null) {
			registerReceiver(intentReceiver, myIntentFilter);
			myLocationManager.requestUpdates(provider, MINIMUM_TIME_BETWEEN_UPDATE,
												MINIMUM_DISTANCECHANGE_FOR_UPDATE,
												myIntent);
		}
	}
	 
	@Override
	public void onPause() {
		 super.onPause();
		 
		 if (provider!=null) {
			 myLocationManager.removeUpdates(myIntent);
			 unregisterReceiver(intentReceiver);
		 }
	} 
	
 	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		if (keyCode == KeyEvent.KEYCODE_S) {	// Switch on the satellite images
			map.toggleSatellite();
			return(true);
		}
		else if (keyCode == KeyEvent.KEYCODE_T) {	// Switch on traffic overlays
			map.toggleTraffic();
			return(true);
		}
		
		return(super.onKeyDown(keyCode, event));
	}

	private void updateView() {
		if (provider!=null) {
			myLocation=myLocationManager.getCurrentLocation(provider.getName());
			
			if (followMe) {
				Double lat=TourMapActivity.this.myLocation.getLatitude() * 1E6;
				Double lng=TourMapActivity.this.myLocation.getLongitude() * 1E6;
				Point point=new Point(lat.intValue(), lng.intValue());
				
				mc.centerMapTo(point, false);
			}
			
			map.invalidate();
		}
	}
	
	boolean showMyLocation() {
		return(showMyLocation);
	}
	
	class LocationIntentReceiver extends IntentReceiver {
		@Override
		public void onReceiveIntent(Context context, Intent intent) {
			TourMapActivity.this.updateView();
		}
	}
	
	class RouteOverlay extends Overlay {
		Activity parent;
		
		RouteOverlay(Activity parent) {
			super();
			this.parent=parent;
		}
		
		public void draw(Canvas canvas, PixelCalculator calculator,
							boolean shadow) {
			super.draw(canvas, calculator, shadow);

			if (showMyLocation() && TourMapActivity.this.myLocation!=null) {				 
				 Double lat=TourMapActivity.this.myLocation.getLatitude() * 1E6;
				 Double lng=TourMapActivity.this.myLocation.getLongitude() * 1E6;
				 Point point=new Point(lat.intValue(), lng.intValue());

				 int[] myScreenCoords = new int[2];
				 calculator.getPointXY(point, myScreenCoords);
				 
				 canvas.drawCircle(myScreenCoords[0], myScreenCoords[1], 5, paint3);
			}
			
			int i=0;
			
			for (Waypoint pt : tour.getRoute()) {
				i++;
				
				Point position=pt.getPosition();
				
				if (position!=null) {
					int[] screenCoords=new int[2];
					
					calculator.getPointXY(position, screenCoords);
					canvas.drawCircle(screenCoords[0], screenCoords[1], 12, paint1);
					canvas.drawText(Integer.toString(i), screenCoords[0] - 4,
									screenCoords[1] + 4, paint2);					
				}
			}
		}
	
		@Override
		public boolean onTap(com.google.android.maps.MapView.DeviceType deviceType,
								Point p, PixelCalculator calculator) {
			for (Waypoint pt : tour.getRoute()) {
				Point position=pt.getPosition();
				
				if (position!=null) {
					int[] screenCoords=new int[2];
					RectF rect=new RectF();
					
					calculator.getPointXY(position, screenCoords); 
					rect.set(-12,-12,12,12);
					rect.offset(screenCoords[0], screenCoords[1]);
					calculator.getPointXY(p, screenCoords);
					
					if (rect.contains(screenCoords[0], screenCoords[1])) {
						Toast.makeText(parent, pt.getTitle(), 2000).show();
					}
				}
			}
			
			return(super.onTap(deviceType, p, calculator));
		}
	}
}