package com.example.Maps013;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.math.RoundingMode;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Color;
import android.location.Geocoder;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ToggleButton;

import com.google.android.gms.identity.intents.Address;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.GoogleMap.OnMapClickListener;
import com.google.android.gms.maps.GoogleMap.OnMapLongClickListener;
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.MarkerOptions;
import com.google.android.gms.maps.model.PolylineOptions;
import com.google.android.gms.vision.barcode.Barcode.GeoPoint;

//http://wptrafficanalyzer.in/blog/driving-distance-and-travel-time-duration-between-two-locations-in-google-map-android-api-v2/

public class MainActivity extends FragmentActivity 
{
	GoogleMap map;
	ArrayList<LatLng> markerPoints;
	TextView tvDistanceDuration;
	
	ToggleButton tbMode;
	
	int DirectionMode = 0 ;
	int MODE_DRIVING = 1;
	int MODE_WALKING = 2;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) 
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.navigation_layout);
		 
		tvDistanceDuration = (TextView) findViewById(R.id.tv_distance_time);
		
		// Initializing 
		markerPoints = new ArrayList<LatLng>();
		
		// Getting reference to SupportMapFragment of the activity_main
		SupportMapFragment fm = (SupportMapFragment)getSupportFragmentManager().findFragmentById(R.id.map);
		
		// Getting Map for the SupportMapFragment
		map = fm.getMap();
		
		// Enable MyLocation Button in the Map
		map.setMyLocationEnabled(true);
		map.setIndoorEnabled(true);
		map.getUiSettings().setZoomControlsEnabled(true);
		map.getUiSettings().setMyLocationButtonEnabled(true);
		map.getUiSettings().setCompassEnabled(true);
		map.getUiSettings().setAllGesturesEnabled(true);
		
		// zoom sur le centre de la France 
		map.moveCamera( CameraUpdateFactory.newLatLngZoom(new LatLng(46.4606 , 2.2557) , 5.5f) );
		
		tbMode = (ToggleButton) findViewById(R.id.tbMode);
		tbMode.setOnClickListener(new OnClickListener() 
		{
			@Override
			public void onClick(View v) 
			{
				// TODO Auto-generated method stub
				Toast.makeText(getBaseContext(), "No Points", Toast.LENGTH_SHORT).show();
				if (tbMode.isChecked()) 
				{
					DirectionMode = 1;
				} 
				else 
				{
					DirectionMode = 2;
				}
			}

		});
		
		// par défaut 
		tbMode.setChecked(true);
		DirectionMode = 1;
		
		 map.setOnMapLongClickListener(new GoogleMap.OnMapLongClickListener() 
		 {
	            @Override
	            public void onMapLongClick(LatLng point) 
	            {
	            	//https://stackoverflow.com/questions/12244297/how-to-add-multiple-buttons-on-a-single-alertdialog
	            	// https://android--code.blogspot.fr/2015/08/android-alertdialog-multichoice.html
	            	AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
	                builder.setTitle("MAP Type");
	                builder.setItems(new CharSequence[] {"None", "Normale", "Satellite", "Hybrid", "Terrain"}, new DialogInterface.OnClickListener() 
	                {
	                            public void onClick(DialogInterface dialog, int which) 
	                            {
	                                switch (which) 
	                                {
	                                    case 0:
	                                    	map.setMapType(GoogleMap.MAP_TYPE_NONE);         
	                                        break;
	                                    case 1:
	                                    	map.setMapType(GoogleMap.MAP_TYPE_NORMAL);      
	                                        break;
	                                    case 2:
	                                    	map.setMapType(GoogleMap.MAP_TYPE_SATELLITE);   
	                                        break;
	                                    case 3:
	                                    	map.setMapType(GoogleMap.MAP_TYPE_HYBRID);      
	                                        break;
	                                    case 4:
	                                    	map.setMapType(GoogleMap.MAP_TYPE_TERRAIN);      
	                                        break;    
	                                }
	                            }
	                });
	                builder.create().show();
	            }
	     });
		
		
		// Setting onclick event listener for the map
		map.setOnMapClickListener(new OnMapClickListener() 
		{
			
			@Override
			public void onMapClick(LatLng point) 
			{
				// Already two locations				
				if(markerPoints.size()>1)
				{
					markerPoints.clear();
					map.clear();					
				}
				
				// Adding new item to the ArrayList
				markerPoints.add(point);				
				
				// Creating MarkerOptions
				MarkerOptions options = new MarkerOptions();
				
				// Setting the position of the marker
				options.position(point);
				
				/** 
				 * For the start location, the color of marker is GREEN and
				 * for the end location, the color of marker is RED.
				 */
				
				DecimalFormat df = new DecimalFormat("#.###");
				df.setRoundingMode(RoundingMode.HALF_UP);
				
				if(markerPoints.size()==1)
				{
					Double a = point.latitude;
					Double b = point.longitude;
					String lieu_departure = getCompleteAddressString(a, b); 
					String str1 = String.valueOf(a);
					String str2 = String.valueOf(b);
					String str = str1 +" " + str2; 
					//options.snippet(str);
					
					String lat =  df.format(a); 
					String lng = df.format(b); 
					String title1 = "Départ : " + " " + lat + " " + lng; 
					options.title(title1);
					options.snippet(lieu_departure);
					options.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_GREEN));
					
//					.title("Melbourne")
//                    .snippet("Population: 4,137,400"));

					
				}
				else if(markerPoints.size()==2)
				{
					Double a = point.latitude;
					Double b = point.longitude;
					String lieu_destination = getCompleteAddressString(a, b); 
					String str1 = String.valueOf(a);
					String str2 = String.valueOf(b);
					String str = str1 +" " + str2; 
					//options.snippet(str);
					//String title2 = "Arrivée :" +str1 + " " + str2; 
					String lat =  df.format(a); 
					String lng = df.format(b); 
					String title2 = "Arrivée : " + lat + " " + lng; 
					options.title(title2);
					options.snippet(lieu_destination);
					options.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED));
				}
				
				// Add new marker to the Google Map Android API V2
				map.addMarker(options);
				
		/*		
				MarkerOptions mDestination = new MarkerOptions()
						.position(destinationPosition)
						.title(destinationPositionTitle)
						.snippet(destinationPositionSnippet)
						.icon(BitmapDescriptorFactory.fromResource(R.drawable.pin1));

				MarkerOptions mStart = new MarkerOptions()
						.position(startPosition)
						.title(startPositionTitle)
						.snippet(startPositionSnippet)
						.icon(BitmapDescriptorFactory.fromResource(R.drawable.pin2));

				mMap.addMarker(mDestination);
				mMap.addMarker(mStart);
		*/		
				
				// Checks, whether start and end locations are captured
				if(markerPoints.size() >= 2)
				{					
					LatLng origin = markerPoints.get(0);
					LatLng dest = markerPoints.get(1);
					
					// Getting URL to the Google Directions API
					String url = getDirectionsUrl(origin, dest);				
					
					DownloadTask downloadTask = new DownloadTask();
					
					// Start downloading json data from Google Directions API
					downloadTask.execute(url);
				}
				
			}
		});
		
		
		String lieu = getCompleteAddressString(43.7717, 2.1848); 
		
		getLocationFromAddress(lieu);
		
	/*	
	      Geocoder coder = new Geocoder(this);
	      try {
	          ArrayList<Address> adresses = (ArrayList<Address>) coder.getFromLocationName("Your Address", 50);
	          for(Address add : adresses){
	              if (statement) {//Controls to ensure it is right address such as country etc.
	                  double longitude = add.getLongitude();
	                  double latitude = add.getLatitude();
	              }
	          }
	      } catch (IOException e) {
	          e.printStackTrace();
	      }
		*/
	}
	
	
	private String getDirectionsUrl(LatLng origin,LatLng dest)
	{
			
		String parameters = "";
		
		// Origin of route
		String str_origin = "origin="+origin.latitude+","+origin.longitude;
		
		// Destination of route
		String str_dest = "destination="+dest.latitude+","+dest.longitude;		
					
		// Sensor enabled
		String sensor = "sensor=false";			
					
		// Building the parameters to the web service
//origine		String parameters = str_origin+"&"+str_dest+"&"+sensor;


		if (DirectionMode == MODE_DRIVING) 
		{
			String mode = "&mode=driving";
			parameters = str_origin+"&"+str_dest+"&"+sensor+"&"+mode;
			
		} 
		else if (DirectionMode == MODE_WALKING)
		{
			String mode = "&mode=walking";
			parameters = str_origin+"&"+str_dest+"&"+sensor+"&"+mode;
		}
		
		// Output format
		String output = "json";
		
		// Building the url to the web service
		String url = "https://maps.googleapis.com/maps/api/directions/"+output+"?"+parameters;
		
		return url;
	}
	
	/** A method to download json data from url */
    private String downloadUrl(String strUrl) throws IOException
    {
        String data = "";
        InputStream iStream = null;
        HttpURLConnection urlConnection = null;
        
        try{
                URL url = new URL(strUrl);

                // Creating an http connection to communicate with url 
                urlConnection = (HttpURLConnection) url.openConnection();

                // Connecting to url 
                urlConnection.connect();

                // Reading data from url 
                iStream = urlConnection.getInputStream();

                BufferedReader br = new BufferedReader(new InputStreamReader(iStream));

                StringBuffer sb  = new StringBuffer();

                String line = "";
                while( ( line = br.readLine())  != null)
                {
                        sb.append(line);
                }
                
                data = sb.toString();

                br.close();
        }
        catch(Exception e)
        {
                Log.d("Exception while downloading url", e.toString());
        }
        finally
        {
                iStream.close();
                urlConnection.disconnect();
        }
        return data;
     }
	
	// Fetches data from url passed
	private class DownloadTask extends AsyncTask<String, Void, String>
	{			
				
		// Downloading data in non-ui thread
		@Override
		protected String doInBackground(String... url) 
		{
			// For storing data from web service
			String data = "";
					
			try{
					// Fetching the data from web service
					data = downloadUrl(url[0]);
			}
			catch(Exception e)
			{
				Log.d("Background Task",e.toString());
			}
			return data;		
		}
		
		// Executes in UI thread, after the execution of
		// doInBackground()
		@Override
		protected void onPostExecute(String result) 
		{			
			super.onPostExecute(result);			
			ParserTask parserTask = new ParserTask();
			// Invokes the thread for parsing the JSON data
			parserTask.execute(result);
		}		
	}
	
	/** A class to parse the Google Places in JSON format */
    private class ParserTask extends AsyncTask<String, Integer, List<List<HashMap<String,String>>> >
    {
    	
    	// Parsing the data in non-ui thread    	
		@Override
		protected List<List<HashMap<String, String>>> doInBackground(String... jsonData) 
		{
			
			JSONObject jObject;	
			List<List<HashMap<String, String>>> routes = null;			           
            
            try{
            		jObject = new JSONObject(jsonData[0]);
            		DirectionsJSONParser parser = new DirectionsJSONParser();
            	
            		// Starts parsing data
            		routes = parser.parse(jObject);    
            }
            catch(Exception e)
            {
            	e.printStackTrace();
            }
            return routes;
		}
		
		// Executes in UI thread, after the parsing process
		@Override
		protected void onPostExecute(List<List<HashMap<String, String>>> result) 
		{
			ArrayList<LatLng> points = null;
			PolylineOptions lineOptions = null;
			MarkerOptions markerOptions = new MarkerOptions();
			String distance = "";
			String duration = "";
			
			if(result.size()<1)
			{
				Toast.makeText(getBaseContext(), "No Points", Toast.LENGTH_SHORT).show();
				return;
			}
				
			
			// Traversing through all the routes
			for(int i=0;i<result.size();i++)
			{
				points = new ArrayList<LatLng>();
				lineOptions = new PolylineOptions();
				
				// Fetching i-th route
				List<HashMap<String, String>> path = result.get(i);
				
				// Fetching all the points in i-th route
				for(int j=0;j<path.size();j++)
				{
					HashMap<String,String> point = path.get(j);	
					
					if(j==0)
					{	// Get distance from the list
						distance = (String)point.get("distance");						
						continue;
					}else if(j==1)
					{ // Get duration from the list
						duration = (String)point.get("duration");
						continue;
					}
					
					double lat = Double.parseDouble(point.get("lat"));
					double lng = Double.parseDouble(point.get("lng"));
					LatLng position = new LatLng(lat, lng);	
					
					points.add(position);						
				}
				
				// Adding all the points in the route to LineOptions
				lineOptions.addAll(points);
				lineOptions.width(2);
				lineOptions.color(Color.RED);	
				
			}
			
			tvDistanceDuration.setText("Distance:"+distance + ", Duration:"+duration);
			
			// Drawing polyline in the Google Map for the i-th route
			map.addPolyline(lineOptions);							
		}			
    }   
    
    
	
    private String getCompleteAddressString(double LATITUDE, double LONGITUDE) 
    {
        String strAdd = "";
        Geocoder geocoder = new Geocoder(this, Locale.getDefault());
        try {
            List<android.location.Address> addresses = geocoder.getFromLocation(LATITUDE, LONGITUDE, 1);
            if (addresses != null) {
                android.location.Address returnedAddress = addresses.get(0);
                StringBuilder strReturnedAddress = new StringBuilder("");

                for (int i = 0; i < returnedAddress.getMaxAddressLineIndex(); i++) {
                    strReturnedAddress.append(returnedAddress.getAddressLine(i)).append("\n");
                }
                strAdd = strReturnedAddress.toString();
                Log.w("My Current loction address", "" + strReturnedAddress.toString());
            } else {
                Log.w("My Current loction address", "No Address returned!");
            }
        } catch (Exception e) {
            e.printStackTrace();
            Log.w("My Current loction address", "Canont get Address!");
        }
        return strAdd;
    }
    
   
    
    public void  getLocationFromAddress(String strAddress) // LatLng  ou GeoPoint ???
    {

    	Geocoder coder = new Geocoder(this);
    	List<android.location.Address> address;
    	
    	//GeoPoint p1 = null;
    	// List<Address> addresses;
    	
    	try 
    	{
			address = coder.getFromLocationName(strAddress,5);
			
			if (address==null) 
			{
			      // return null;
				Toast.makeText(getBaseContext(), "Adresse introuvable !.", Toast.LENGTH_LONG).show();
			}
			else
			{	
			    android.location.Address location= address.get(0);
			    
			    
			    location.getLatitude();
			    location.getLongitude();

			    LatLng p1 = new LatLng(location.getLatitude(), location.getLongitude() );
			    
			   // p1 = new GeoPoint((double) (location.getLatitude() * 1E6),   (double) (location.getLongitude() * 1E6));
			}
		} 
    	catch (IOException e) 
    	{
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

    	
    	    
    }
    
	
	/*******************************************************************************************/

	@Override
	public boolean onCreateOptionsMenu(Menu menu) 
	{
			getMenuInflater().inflate(R.menu.activity_main, menu);
			return true;
	}
	
	@Override
    public boolean onOptionsItemSelected(MenuItem item) 
	{
		
		Intent Intent;
		 
	        switch (item.getItemId())
	        {
	        
	        	case R.id.menu_geolocalisation:
	        		Intent = new Intent(MainActivity.this, Geolocalisation02.class);
	        		startActivity(Intent);
	        		return true;
	        
	        	case R.id.menu_compas:
	        		Intent = new Intent(MainActivity.this, Compas.class);
	        		startActivity(Intent);
	        		return true;	
	        
	        	case R.id.menu_direction:
	        		Intent = new Intent(MainActivity.this, Geo06.class);  // avant geo03
	        		startActivity(Intent);
	        		return true;		

		        case R.id.menu_gps_tracker:
		  			Toast.makeText(getApplicationContext(),"GPS tracker",Toast.LENGTH_SHORT).show();
		  			Intent  = new Intent(MainActivity.this, Chrono.class); // Control_Service
		  			startActivity(Intent);
			        return true;
			        
		        //case R.id.menu_settings:
		        case R.id.menu_find_location:
		        	//Toast.makeText(getApplicationContext(),"Non fonctionnel ...",Toast.LENGTH_SHORT).show();
		  			Intent  = new Intent(MainActivity.this, Geocoder_find_address02.class);
		  			startActivity(Intent);
			        return true;    
		  		
		  		case R.id.menu_autocomplete:
		  		
		  			Intent Intent06 = new Intent(MainActivity.this, Geo04.class); // AutoComplete
		  			startActivity(Intent06);
			        return true;    
			        
		  		case R.id.menu_pedometre:
		  			Intent = new Intent(MainActivity.this,  StepCounterActivity.class);  // Podometre_mode.
	        		startActivity(Intent);
		  			
		  			
		  			//Intent Intent07 = new Intent(MainActivity.this, podometre01.class); // AutoComplete
		  			//startActivity(Intent07);
		  			//map.setMapType(GoogleMap.MAP_TYPE_TERRAIN);
			        return true;     
			        
		  		case R.id.menu_about:
		  			about();
			        return true;
			            
		
		  		case R.id.menu_quit:
		  			Toast.makeText(getApplicationContext(),"Salut on ferme la boutique...",Toast.LENGTH_SHORT).show();
		  			finish();
			        return true;    
		          
		  		default:
		          return super.onOptionsItemSelected(item);
             }
    }
	
	/*******************************************************************************************/

	public void about()
	{
		
		//http://androidexample.com/Custom_Dialog_-_Android_Example/index.php?view=article_discription&aid=88
		
        final Dialog dialog = new Dialog(MainActivity.this);
        dialog.setContentView(R.layout.about_layout);
        dialog.setTitle("About:");
        dialog.show();
        
        
        Button dialogCloseButton = (Button) dialog.findViewById(R.id.close_button);
        dialogCloseButton.setOnClickListener(new OnClickListener()
        {
              @Override
              public void onClick(View v)
              {
               // TODO Auto-generated method stub
                  dialog.dismiss();
              }                                                                             
         });
		
	}
	
}

class DirectionsJSONParser 
{
	
	/** Receives a JSONObject and returns a list of lists containing latitude and longitude */
	public List<List<HashMap<String,String>>> parse(JSONObject jObject){
		
		List<List<HashMap<String, String>>> routes = new ArrayList<List<HashMap<String,String>>>() ;
		JSONArray jRoutes = null;
		JSONArray jLegs = null;
		JSONArray jSteps = null;	
		JSONObject jDistance = null;
		JSONObject jDuration = null;
		
		try {			
			
			jRoutes = jObject.getJSONArray("routes");
			
			/** Traversing all routes */
			for(int i=0;i<jRoutes.length();i++)
			{			
				jLegs = ( (JSONObject)jRoutes.get(i)).getJSONArray("legs");				
				
				List<HashMap<String, String>> path = new ArrayList<HashMap<String, String>>();				
				
				/** Traversing all legs */
				for(int j=0;j<jLegs.length();j++)
				{
					
					/** Getting distance from the json data */
					jDistance = ((JSONObject) jLegs.get(j)).getJSONObject("distance");
					HashMap<String, String> hmDistance = new HashMap<String, String>();
					hmDistance.put("distance", jDistance.getString("text"));
					
					/** Getting duration from the json data */
					jDuration = ((JSONObject) jLegs.get(j)).getJSONObject("duration");
					HashMap<String, String> hmDuration = new HashMap<String, String>();
					hmDuration.put("duration", jDuration.getString("text"));
					
					/** Adding distance object to the path */
					path.add(hmDistance);
					
					/** Adding duration object to the path */
					path.add(hmDuration);					
					
					jSteps = ( (JSONObject)jLegs.get(j)).getJSONArray("steps");
					
					/** Traversing all steps */
					for(int k=0;k<jSteps.length();k++)
					{
						String polyline = "";
						polyline = (String)((JSONObject)((JSONObject)jSteps.get(k)).get("polyline")).get("points");
						List<LatLng> list = decodePoly(polyline);
						
						/** Traversing all points */
						for(int l=0;l<list.size();l++)
						{
							HashMap<String, String> hm = new HashMap<String, String>();
							hm.put("lat", Double.toString(((LatLng)list.get(l)).latitude) );
							hm.put("lng", Double.toString(((LatLng)list.get(l)).longitude) );
							path.add(hm);						
						}								
					}					
				}
				routes.add(path);
			}
			
		} catch (JSONException e) {			
			e.printStackTrace();
		}catch (Exception e){			
		}
		
		return routes;
	}	
	
	
	/**
	 * Method to decode polyline points 
	 * Courtesy : jeffreysambells.com/2010/05/27/decoding-polylines-from-google-maps-direction-api-with-java 
	 * */
    private List<LatLng> decodePoly(String encoded)
    {

        List<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 p = new LatLng((((double) lat / 1E5)),
                    (((double) lng / 1E5)));
            poly.add(p);
        }

        return poly;
    }
}


