content: /*
   * Copyright (c) 2013 Akexorcist
   *
   * Permission is hereby granted, free of charge, to any person obtaining a copy
   * of this software and associated documentation files (the "Software"), to deal
   * in the Software without restriction, including without limitation the rights
   * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   * copies of the Software, and to permit persons to whom the Software is
   * furnished to do so, subject to the following conditions:
   *
   * The above copyright notice and this permission notice shall be included in
   * all copies or substantial portions of the Software.
   *
   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
   * THE SOFTWARE.
   */
  
  package app.akexorcist.gdaplibrary;
  
  import java.io.IOException;
  import java.io.InputStream;
  import java.util.ArrayList;
  import java.util.List;
  
  import javax.xml.parsers.DocumentBuilder;
  import javax.xml.parsers.DocumentBuilderFactory;
  import javax.xml.parsers.ParserConfigurationException;
  
  import org.apache.http.HttpResponse;
  import org.apache.http.client.HttpClient;
  import org.apache.http.client.methods.HttpPost;
  import org.apache.http.impl.client.DefaultHttpClient;
  import org.apache.http.protocol.BasicHttpContext;
  import org.apache.http.protocol.HttpContext;
  import org.w3c.dom.Document;
  import org.w3c.dom.Node;
  import org.w3c.dom.NodeList;
  import org.xml.sax.SAXException;
  
  import com.google.android.gms.maps.CameraUpdateFactory;
  import com.google.android.gms.maps.GoogleMap;
  import com.google.android.gms.maps.model.CameraPosition;
  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.google.android.gms.maps.model.Polyline;
  import com.google.android.gms.maps.model.PolylineOptions;
  
  import android.annotation.SuppressLint;
  import android.content.Context;
  import android.os.AsyncTask;
  import android.os.Handler;
  import android.util.DisplayMetrics;
  import android.util.Log;
  
  @SuppressLint("NewApi")
  public class GoogleDirection {
      public final static String MODE_DRIVING = "driving";
      public final static String MODE_WALKING = "walking";
      public final static String MODE_BICYCLING = "bicycling";
  
      public final static String STATUS_OK = "OK";
      public final static String STATUS_NOT_FOUND = "NOT_FOUND";
      public final static String STATUS_ZERO_RESULTS = "ZERO_RESULTS";
      public final static String STATUS_MAX_WAYPOINTS_EXCEEDED = "MAX_WAYPOINTS_EXCEEDED";
      public final static String STATUS_INVALID_REQUEST = "INVALID_REQUEST";
      public final static String STATUS_OVER_QUERY_LIMIT = "OVER_QUERY_LIMIT";
      public final static String STATUS_REQUEST_DENIED = "REQUEST_DENIED";
      public final static String STATUS_UNKNOWN_ERROR = "UNKNOWN_ERROR";
  
      public final static int SPEED_VERY_FAST = 1;
      public final static int SPEED_FAST = 2;
      public final static int SPEED_NORMAL = 3;
      public final static int SPEED_SLOW = 4;
      public final static int SPEED_VERY_SLOW = 5;
      
  	private OnDirectionResponseListener mDirectionListener = null;
  	private OnAnimateListener mAnimateListener = null;
  	
  	private boolean isLogging = false;
  	
  	private LatLng animateMarkerPosition = null;
  	private LatLng beginPosition = null;
  	private LatLng endPosition = null;
  	private ArrayList<LatLng> animatePositionList = null;
  	private Marker animateMarker = null;
  	private Polyline animateLine = null;
  	private GoogleMap gm = null;
  	private int step = -1;
  	private int animateSpeed = -1;
  	private int zoom = -1;
  	private double animateDistance = -1;
  	private double animateCamera = -1;
  	private double totalAnimateDistance = 0;
  	private boolean cameraLock = false;
  	private boolean drawMarker = false;
  	private boolean drawLine = false;
  	private boolean flatMarker = false;
  	private boolean isCameraTilt = false;
  	private boolean isCameraZoom = false;
  	private boolean isAnimated = false;
  	
  	private Context mContext = null;
   
      public GoogleDirection(Context context) { 
      	mContext = context;
      }
   
      public String request(LatLng start, LatLng end, String mode) {
          final String url = "http://maps.googleapis.com/maps/api/directions/xml?"
                  + "origin=" + start.latitude + "," + start.longitude  
                  + "&destination=" + end.latitude + "," + end.longitude 
                  + "&sensor=false&units=metric&mode=" + mode;
  
     		if(isLogging)
     			Log.i("GoogleDirection", "URL : " + url);
          new RequestTask().execute(new String[]{ url });
          return url;
      }
      
      private class RequestTask extends AsyncTask<String, Void, Document> {
  		protected Document doInBackground(String... url) {
  			try {
  				HttpClient httpClient = new DefaultHttpClient();
  				HttpContext localContext = new BasicHttpContext();
  				HttpPost httpPost = new HttpPost(url[0]);
  				HttpResponse response = httpClient.execute(httpPost, localContext);
  				InputStream in = response.getEntity().getContent();
  				DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
  				return builder.parse(in);
  			} catch (IOException e) {
  				e.printStackTrace();
  			} catch (ParserConfigurationException e) {
  				e.printStackTrace();
  			} catch (SAXException e) {
  				e.printStackTrace();
  			} 
  			return null;
  		}
  		
  		protected void onPostExecute(Document doc) {
  			super.onPostExecute(doc);
  			if(mDirectionListener != null)
  				mDirectionListener.onResponse(getStatus(doc), doc, GoogleDirection.this);
  		}
  	    
  	   	private String getStatus(Document doc) {
  	   		NodeList nl1 = doc.getElementsByTagName("status");
  	   		Node node1 = nl1.item(0);
  	   		if(isLogging)
  	   			Log.i("GoogleDirection", "Status : " + node1.getTextContent());
  	   		return node1.getTextContent();
  	    }
      }
      
      public void setLogging(boolean state) {
      	isLogging = state;
      }
      
     	public String getStatus(Document doc) {
     		NodeList nl1 = doc.getElementsByTagName("status");
     		Node node1 = nl1.item(0);
     		if(isLogging)
     			Log.i("GoogleDirection", "Status : " + node1.getTextContent());
     		return node1.getTextContent();
      }
          
     	public String[] getDurationText(Document doc) {
     		NodeList nl1 = doc.getElementsByTagName("duration");
     		String[] arr_str = new String[nl1.getLength() - 1];
     		for(int i = 0 ; i < nl1.getLength() - 1 ; i++) {
  	   		Node node1 = nl1.item(i);
  	   		NodeList nl2 = node1.getChildNodes();
  	   		Node node2 = nl2.item(getNodeIndex(nl2, "text"));
  	   		arr_str[i] = node2.getTextContent();
  	   		if(isLogging)
  	   			Log.i("GoogleDirection", "DurationText : " + node2.getTextContent());
     		}
     		return arr_str;
      }
     	    
     	public int[] getDurationValue(Document doc) {
     		NodeList nl1 = doc.getElementsByTagName("duration");
     		int[] arr_int = new int[nl1.getLength() - 1];
     		for(int i = 0 ; i < nl1.getLength() - 1 ; i++) {
  	   		Node node1 = nl1.item(i);
  	   		NodeList nl2 = node1.getChildNodes();
  	   		Node node2 = nl2.item(getNodeIndex(nl2, "value"));
  	   		arr_int[i] = Integer.parseInt(node2.getTextContent());
  	   		if(isLogging)
  	   			Log.i("GoogleDirection", "Duration : " + node2.getTextContent());
     		}
     		return arr_int;
      }
     	
     	public String getTotalDurationText(Document doc) {
     		NodeList nl1 = doc.getElementsByTagName("duration");
     		Node node1 = nl1.item(nl1.getLength() - 1);
     		NodeList nl2 = node1.getChildNodes();
     		Node node2 = nl2.item(getNodeIndex(nl2, "text"));
     		if(isLogging)
     			Log.i("GoogleDirection", "TotalDuration : " + node2.getTextContent());
     		return node2.getTextContent();
      }
      
     	public int getTotalDurationValue(Document doc) {
     		NodeList nl1 = doc.getElementsByTagName("duration");
     		Node node1 = nl1.item(nl1.getLength() - 1);
     		NodeList nl2 = node1.getChildNodes();
     		Node node2 = nl2.item(getNodeIndex(nl2, "value"));
     		if(isLogging)
     			Log.i("GoogleDirection", "TotalDuration : " + node2.getTextContent());
     		return Integer.parseInt(node2.getTextContent());
      }
    
      public String[] getDistanceText(Document doc) {
     		NodeList nl1 = doc.getElementsByTagName("distance");
     		String[] arr_str = new String[nl1.getLength() - 1];
     		for(int i = 0 ; i < nl1.getLength() - 1 ; i++) {
  	   		Node node1 = nl1.item(i);
  	   		NodeList nl2 = node1.getChildNodes();
  	   		Node node2 = nl2.item(getNodeIndex(nl2, "text"));
  	   		arr_str[i] = node2.getTextContent();
  	   		if(isLogging)
  	   			Log.i("GoogleDirection", "DurationText : " + node2.getTextContent());
     		}
     		return arr_str;
      }
   
      public int[] getDistanceValue(Document doc) {
      	NodeList nl1 = doc.getElementsByTagName("distance");
     		int[] arr_int = new int[nl1.getLength() - 1];
     		for(int i = 0 ; i < nl1.getLength() - 1 ; i++) {
  	   		Node node1 = nl1.item(i);
  	   		NodeList nl2 = node1.getChildNodes();
  	   		Node node2 = nl2.item(getNodeIndex(nl2, "value"));
  	   		arr_int[i] = Integer.parseInt(node2.getTextContent());
  	   		if(isLogging)
  	   			Log.i("GoogleDirection", "Duration : " + node2.getTextContent());
     		}
     		return arr_int;
      }
  
     	public String getTotalDistanceText(Document doc) {
     		NodeList nl1 = doc.getElementsByTagName("distance");
     		Node node1 = nl1.item(nl1.getLength() - 1);
     		NodeList nl2 = node1.getChildNodes();
     		Node node2 = nl2.item(getNodeIndex(nl2, "text"));
     		if(isLogging)
     			Log.i("GoogleDirection", "TotalDuration : " + node2.getTextContent());
     		return node2.getTextContent();
      }
      
     	public int getTotalDistanceValue(Document doc) {
     		NodeList nl1 = doc.getElementsByTagName("distance");
     		Node node1 = nl1.item(nl1.getLength() - 1);
     		NodeList nl2 = node1.getChildNodes();
     		Node node2 = nl2.item(getNodeIndex(nl2, "value"));
     		if(isLogging)
     			Log.i("GoogleDirection", "TotalDuration : " + node2.getTextContent());
     		return Integer.parseInt(node2.getTextContent());
      }
   
      public String getStartAddress(Document doc) {
          NodeList nl1 = doc.getElementsByTagName("start_address");
          Node node1 = nl1.item(0);
     		if(isLogging)
     			Log.i("GoogleDirection", "StartAddress : " + node1.getTextContent());
          return node1.getTextContent();
      }
   
      public String getEndAddress(Document doc) {
          NodeList nl1 = doc.getElementsByTagName("end_address");
          Node node1 = nl1.item(0);
     		if(isLogging)
     			Log.i("GoogleDirection", "StartAddress : " + node1.getTextContent());
          return node1.getTextContent();
      }
   
      public String getCopyRights(Document doc) {
          NodeList nl1 = doc.getElementsByTagName("copyrights");
          Node node1 = nl1.item(0);
     		if(isLogging)
     			Log.i("GoogleDirection", "CopyRights : " + node1.getTextContent());
          return node1.getTextContent();
      }
   
      public ArrayList<LatLng> getDirection(Document doc) {
          NodeList nl1, nl2, nl3;
          ArrayList<LatLng> listGeopoints = new ArrayList<LatLng>();
          nl1 = doc.getElementsByTagName("step");
          if (nl1.getLength() > 0) {
              for (int i = 0; i < nl1.getLength(); i++) {
                  Node node1 = nl1.item(i);
                  nl2 = node1.getChildNodes();
  
                  Node locationNode = nl2.item(getNodeIndex(nl2, "start_location"));
                  nl3 = locationNode.getChildNodes();
                  Node latNode = nl3.item(getNodeIndex(nl3, "lat"));
                  double lat = Double.parseDouble(latNode.getTextContent());
                  Node lngNode = nl3.item(getNodeIndex(nl3, "lng"));
                  double lng = Double.parseDouble(lngNode.getTextContent());
                  listGeopoints.add(new LatLng(lat, lng));
  
                  locationNode = nl2.item(getNodeIndex(nl2, "polyline"));
                  nl3 = locationNode.getChildNodes();
                  latNode = nl3.item(getNodeIndex(nl3, "points"));
                  ArrayList<LatLng> arr = decodePoly(latNode.getTextContent());
                  for(int j = 0 ; j < arr.size() ; j++) {
                      listGeopoints.add(new LatLng(arr.get(j).latitude
                              , arr.get(j).longitude));
                  }
  
                  locationNode = nl2.item(getNodeIndex(nl2, "end_location"));
                  nl3 = locationNode.getChildNodes();
                  latNode = nl3.item(getNodeIndex(nl3, "lat"));
                  lat = Double.parseDouble(latNode.getTextContent());
                  lngNode = nl3.item(getNodeIndex(nl3, "lng"));
                  lng = Double.parseDouble(lngNode.getTextContent());
                  listGeopoints.add(new LatLng(lat, lng));
              }
          }
          
          return listGeopoints;
      }
      
      public ArrayList<LatLng> getSection(Document doc) {
          NodeList nl1, nl2, nl3;
          ArrayList<LatLng> listGeopoints = new ArrayList<LatLng>();
          nl1 = doc.getElementsByTagName("step");
          if (nl1.getLength() > 0) {
              for (int i = 0; i < nl1.getLength(); i++) {
                  Node node1 = nl1.item(i);
                  nl2 = node1.getChildNodes();
  
                  Node locationNode = nl2.item(getNodeIndex(nl2, "end_location"));
                  nl3 = locationNode.getChildNodes();
                  Node latNode = nl3.item(getNodeIndex(nl3, "lat"));
                  double lat = Double.parseDouble(latNode.getTextContent());
                  Node lngNode = nl3.item(getNodeIndex(nl3, "lng"));
                  double lng = Double.parseDouble(lngNode.getTextContent());
                  listGeopoints.add(new LatLng(lat, lng));
              }
          }
          
          return listGeopoints;
      }
      
      public PolylineOptions getPolyline(Document doc, int width, int color) {
      	ArrayList<LatLng> arr_pos = getDirection(doc);
      	PolylineOptions rectLine = new PolylineOptions().width(dpToPx(width)).color(color);
          for(int i = 0 ; i < arr_pos.size() ; i++)        
              rectLine.add(arr_pos.get(i));
          return rectLine;
      }
   
      private int getNodeIndex(NodeList nl, String nodename) {
          for(int i = 0 ; i < nl.getLength() ; i++) {
              if(nl.item(i).getNodeName().equals(nodename))
                  return i;
          }
          return -1;
      }
   
      private ArrayList<LatLng> decodePoly(String encoded) {
          ArrayList<LatLng> poly = new ArrayList<LatLng>();
          int index = 0, len = encoded.length();
          int lat = 0, lng = 0;
          while (index < len) {
              int b, shift = 0, result = 0;
              do {
                  b = encoded.charAt(index++) - 63;
                  result |= (b & 0x1f) << shift;
                  shift += 5;
              } while (b >= 0x20);
              int dlat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
              lat += dlat;
              shift = 0;
              result = 0;
              do {
                  b = encoded.charAt(index++) - 63;
                  result |= (b & 0x1f) << shift;
                  shift += 5;
              } while (b >= 0x20);
              int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
              lng += dlng;
     
              LatLng position = new LatLng((double)lat / 1E5, (double)lng / 1E5);
              poly.add(position);
          }
          return poly;
      }
      
      private int dpToPx(int dp) {
  	    DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();
  	    int px = Math.round(dp * (displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT));       
  	    return px;
  	}
  
  	public void setOnDirectionResponseListener(OnDirectionResponseListener listener) {
  		mDirectionListener = listener;
      }
  	
  	public void setOnAnimateListener(OnAnimateListener listener) {
  		mAnimateListener = listener;
  	}
  	
  	public interface OnDirectionResponseListener {
  	    public void onResponse(String status, Document doc, GoogleDirection gd);
  	}
  	
  	public interface OnAnimateListener {
  	    public void onFinish();
  	    public void onStart();
  	    public void onProgress(int progress, int total);
  	}
  	
  	public void animateDirection(GoogleMap gm, ArrayList<LatLng> direction, int speed
  			, boolean cameraLock, boolean isCameraTilt, boolean isCameraZoom
  			, boolean drawMarker, MarkerOptions mo, boolean flatMarker
  			, boolean drawLine, PolylineOptions po) {
  		if(direction.size() > 1) {
  			isAnimated = true;
  			animatePositionList = direction;
  			animateSpeed = speed;
  			this.drawMarker = drawMarker;
  			this.drawLine = drawLine;
  			this.flatMarker = flatMarker;
  			this.isCameraTilt = isCameraTilt;
  			this.isCameraZoom = isCameraZoom;
  			step = 0;
  			this.cameraLock = cameraLock;
  			this.gm = gm;
  				
  			setCameraUpdateSpeed(speed);
  			
  			beginPosition = animatePositionList.get(step);
  			endPosition = animatePositionList.get(step + 1);
  			animateMarkerPosition = beginPosition;
  			
  			if(mAnimateListener != null)
  				mAnimateListener.onProgress(step, animatePositionList.size());
  			
  	        if(cameraLock) {
  				float bearing = getBearing(beginPosition, endPosition);
  	        	CameraPosition.Builder cameraBuilder = new CameraPosition.Builder()
  					.target(animateMarkerPosition).bearing(bearing);
  
  	        	if(isCameraTilt) 
  	        		cameraBuilder.tilt(90);
  	        	else 
  	        		cameraBuilder.tilt(gm.getCameraPosition().tilt);
  
  	        	if(isCameraZoom) 
  	        		cameraBuilder.zoom(zoom);
  	        	else 
  	        		cameraBuilder.zoom(gm.getCameraPosition().zoom);
  	        	
  	        	CameraPosition cameraPosition = cameraBuilder.build();
  	        	gm.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
  	        }
  	        
  	        if(drawMarker) {
  	        	if(mo != null)
  	        		animateMarker = gm.addMarker(mo.position(beginPosition));
  	        	else 
  	        		animateMarker = gm.addMarker(new MarkerOptions().position(beginPosition));
  	        	
  	        	if(flatMarker) {
  		        	animateMarker.setFlat(true);
  
  		        	float rotation = getBearing(animateMarkerPosition, endPosition) + 180;
  		        	animateMarker.setRotation(rotation);
  		        }
  	        }
  	        
  	        
  	        if(drawLine) {
  	        	if(po != null) 
  	        		animateLine = gm.addPolyline(po.add(beginPosition)
  			        		.add(beginPosition).add(endPosition)
  			        		.width(dpToPx((int)po.getWidth())));
  	        	else 
  		        	animateLine = gm.addPolyline(new PolylineOptions()
      						.width(dpToPx(5)));
  	        }
  	        
  			new Handler().postDelayed(r, speed);
  			if(mAnimateListener != null)
  				mAnimateListener.onStart();
  		}
  	}
  	
  	public void cancelAnimated() {
  		isAnimated = false;
  	}
  	
  	public boolean isAnimated() {
  		return isAnimated;
  	}
  
      private Runnable r = new Runnable() {
      	public void run() {
      		
      		animateMarkerPosition = getNewPosition(animateMarkerPosition, endPosition);
  
  	        if(drawMarker)
  	        	animateMarker.setPosition(animateMarkerPosition);
  
  	        
  	        if(drawLine) {
  	        	List<LatLng> points = animateLine.getPoints();
  	        	points.add(animateMarkerPosition);
  	        	animateLine.setPoints(points);
  	        }
      
      		if((animateMarkerPosition.latitude == endPosition.latitude 
      				&& animateMarkerPosition.longitude == endPosition.longitude)) {
      			if(step == animatePositionList.size() - 2) {
      				isAnimated = false;
      				totalAnimateDistance = 0;
      				if(mAnimateListener != null)
      					mAnimateListener.onFinish();
      			} else {
      				step++;
      				beginPosition = animatePositionList.get(step);
      				endPosition = animatePositionList.get(step + 1);
      				animateMarkerPosition = beginPosition;
      				
      		        if(flatMarker && step + 3 < animatePositionList.size() - 1) {
      		        	float rotation = getBearing(animateMarkerPosition, animatePositionList.get(step + 3)) + 180;
      		        	animateMarker.setRotation(rotation);
      		        }
      				
      				if(mAnimateListener != null)
      					mAnimateListener.onProgress(step, animatePositionList.size());
      			}
      		}
      		
      		if(cameraLock && (totalAnimateDistance > animateCamera || !isAnimated)) {
  				totalAnimateDistance = 0;
  				float bearing = getBearing(beginPosition, endPosition);
  	        	CameraPosition.Builder cameraBuilder = new CameraPosition.Builder()
  					.target(animateMarkerPosition).bearing(bearing);
  
  	        	if(isCameraTilt) 
  	        		cameraBuilder.tilt(90);
  	        	else 
  	        		cameraBuilder.tilt(gm.getCameraPosition().tilt);
  
  	        	if(isCameraZoom) 
  	        		cameraBuilder.zoom(zoom);
  	        	else 
  	        		cameraBuilder.zoom(gm.getCameraPosition().zoom);
  	        	
  	        	CameraPosition cameraPosition = cameraBuilder.build();
  	        	gm.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
  				
  			}
      		
      		if(isAnimated) {
      			new Handler().postDelayed(r, animateSpeed);
      		}
      	}
      };
      
      public Marker getAnimateMarker() {
      	return animateMarker;
      }
      
      public Polyline getAnimatePolyline() {
      	return animateLine;
      }
      
      private LatLng getNewPosition(LatLng begin, LatLng end) {
  		double lat = Math.abs(begin.latitude - end.latitude); 
          double lng = Math.abs(begin.longitude - end.longitude);
          
          double dis = Math.sqrt(Math.pow(lat, 2) + Math.pow(lng, 2));
          if(dis >= animateDistance) {
  	        double angle = -1;
  	        
  	        if(begin.latitude <= end.latitude && begin.longitude <= end.longitude)
  	    		angle = Math.toDegrees(Math.atan(lng / lat));
  			else if(begin.latitude > end.latitude && begin.longitude <= end.longitude)
  	    		angle = (90 - Math.toDegrees(Math.atan(lng / lat))) + 90;
  			else if(begin.latitude > end.latitude && begin.longitude > end.longitude)
  	    		angle = Math.toDegrees(Math.atan(lng / lat)) + 180;
  			else if(begin.latitude <= end.latitude && begin.longitude > end.longitude)
  	    		angle = (90 - Math.toDegrees(Math.atan(lng / lat))) + 270;
  			
  	        double x = Math.cos(Math.toRadians(angle)) * animateDistance;
  	        double y = Math.sin(Math.toRadians(angle)) * animateDistance;
  	        totalAnimateDistance += animateDistance;
  	        double finalLat = begin.latitude + x;
  	        double finalLng = begin.longitude + y;
  	        
  	        return new LatLng(finalLat, finalLng);
          } else {
          	return end;
          }
      }
      
      private float getBearing(LatLng begin, LatLng end) {
  		double lat = Math.abs(begin.latitude - end.latitude); 
          double lng = Math.abs(begin.longitude - end.longitude);
      	 if(begin.latitude < end.latitude && begin.longitude < end.longitude)
  	    	return (float)(Math.toDegrees(Math.atan(lng / lat)));
  		else if(begin.latitude >= end.latitude && begin.longitude < end.longitude)
  			return (float)((90 - Math.toDegrees(Math.atan(lng / lat))) + 90);
  		else if(begin.latitude >= end.latitude && begin.longitude >= end.longitude)
  			return  (float)(Math.toDegrees(Math.atan(lng / lat)) + 180);
  		else if(begin.latitude < end.latitude && begin.longitude >= end.longitude)
  			return (float)((90 - Math.toDegrees(Math.atan(lng / lat))) + 270);
      	 return -1;
      }
      
      public void setCameraUpdateSpeed(int speed) {		
  		if(speed == SPEED_VERY_SLOW) {
  			animateDistance = 0.000005;
  			animateSpeed = 20;
  			animateCamera = 0.0004;
  			zoom = 19;
  		} else if(speed == SPEED_SLOW) {
  			animateDistance = 0.00001;
  			animateSpeed = 20;
  			animateCamera = 0.0008;
  			zoom = 18;
  		} else if(speed == SPEED_NORMAL) {
  			animateDistance = 0.00005;
  			animateSpeed = 20;
  			animateCamera = 0.002;
  			zoom = 16;
  		} else if(speed == SPEED_FAST) {
  			animateDistance = 0.0001;
  			animateSpeed = 20;
  			animateCamera = 0.004;
  			zoom = 15;
  		} else if(speed == SPEED_VERY_FAST) {
  			animateDistance = 0.0005;
  			animateSpeed = 20;
  			animateCamera = 0.004;
  			zoom = 13;
  		} else {
  			animateDistance = 0.00005;
  			animateSpeed = 20;
  			animateCamera = 0.002;
  			zoom = 16;
  		}
      }
  }
  