package it.unipr.dsg.tracker;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;

public class LocationTrackingService extends Service implements LocationListener{

	private LocationManager locationManager = null;
	private Location currentLocation;
	private static final int TWO_MINUTES = 1000 * 60 * 2;

	//Binder given to clients
    private final IBinder mBinder = new LocalBinder();

    /**
     * Class used for the client Binder.  Because we know this service always
     * runs in the same process as its clients, we don't need to deal with IPC.
     */
    public class LocalBinder extends Binder {
    	LocationTrackingService getService() {
            return LocationTrackingService.this;
        }
    };
	
	@Override
	public IBinder onBind(Intent arg0) {
		Log.d(MainActivity.TAG,"LocationTrackingService ---> onBind()");
		startServiceTask();
		return mBinder;
	}

	@Override
	public void onCreate() {
		Log.d(MainActivity.TAG,"LocationTrackingService ---> onCreate()");
		locationManager  = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
		super.onCreate();
	}

	@Override
	public void onDestroy() {
		Log.d(MainActivity.TAG,"LocationTrackingService ---> onDestroy()");
		super.onDestroy();
		
		if(locationManager != null)
		{
			locationManager.removeUpdates(this);
			locationManager = null;
		}
	}
	
	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		Log.d(MainActivity.TAG,"LocationTrackingService ---> onStartCommand()");
		startServiceTask();
		return super.onStartCommand(intent, flags, startId);
	}

	@Override
	public boolean onUnbind(Intent intent) {
		Log.d(MainActivity.TAG,"LocationTrackingService ---> onUnbind()");
		return super.onUnbind(intent);
	}

	public void startServiceTask()
	{
		Log.d(MainActivity.TAG,"LocationTrackingService ---> Starting LocationTrackingService");

		// Acquire a reference to the system Location Manager
		locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);

		if(locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER))
		{
			Log.d(MainActivity.TAG,"GPS_PROVIDER is ebabled !");

			Location lastKnownLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);

			Log.d(MainActivity.TAG,"Last Known Location: " + lastKnownLocation);

			if(lastKnownLocation != null)
			{
				currentLocation = lastKnownLocation;
			}

			locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
		}
		else
			Toast.makeText(this, "GPS is not ebabled !", Toast.LENGTH_LONG).show();

		if(locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER))
		{
			Log.d(MainActivity.TAG,"NETWORK_PROVIDER is ebabled !");

			Location lastKnownLocation = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);

			Log.d(MainActivity.TAG,"Last Known Location: " + lastKnownLocation);

			if(lastKnownLocation != null && isBetterLocation(lastKnownLocation,currentLocation))
			{
				currentLocation = lastKnownLocation;
			}

			// Register the listener with the Location Manager to receive location updates
			locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, this);
		}
	}
	
	/** Determines whether one Location reading is better than the current Location fix
	 * @param location  The new Location that you want to evaluate
	 * @param currentBestLocation  The current Location fix, to which you want to compare the new one
	 */
	protected boolean isBetterLocation(Location location, Location currentBestLocation) {
		if (currentBestLocation == null) {
			// A new location is always better than no location
			return true;
		}

		// Check whether the new location fix is newer or older
		long timeDelta = location.getTime() - currentBestLocation.getTime();
		boolean isSignificantlyNewer = timeDelta > TWO_MINUTES;
		boolean isSignificantlyOlder = timeDelta < -TWO_MINUTES;
		boolean isNewer = timeDelta > 0;

		// If it's been more than two minutes since the current location, use the new location
		// because the user has likely moved
		if (isSignificantlyNewer) {
			return true;
			// If the new location is more than two minutes older, it must be worse
		} else if (isSignificantlyOlder) {
			return false;
		}

		// Check whether the new location fix is more or less accurate
		int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation.getAccuracy());
		boolean isLessAccurate = accuracyDelta > 0;
		boolean isMoreAccurate = accuracyDelta < 0;
		boolean isSignificantlyLessAccurate = accuracyDelta > 200;

		// Check if the old and new location are from the same provider
		boolean isFromSameProvider = isSameProvider(location.getProvider(),
				currentBestLocation.getProvider());

		// Determine location quality using a combination of timeliness and accuracy
		if (isMoreAccurate) {
			return true;
		} else if (isNewer && !isLessAccurate) {
			return true;
		} else if (isNewer && !isSignificantlyLessAccurate && isFromSameProvider) {
			return true;
		}
		return false;
	}
	
	/** Checks whether two providers are the same */
	private boolean isSameProvider(String provider1, String provider2) {
		if (provider1 == null) {
			return provider2 == null;
		}
		return provider1.equals(provider2);
	}


	/*** LocationListener Methods ***/

	@Override
	public void onLocationChanged(Location location) {
		Log.d(MainActivity.TAG,"LocationTrackingService ---> onLocationChanged(): Provider: " + location.getProvider() + " Lat: " + location.getLatitude() + " Lng: " + location.getLongitude() + " Accuracy: " + location.getAccuracy());

		if(currentLocation == null)				
			currentLocation = location;
		else
			if(isBetterLocation(location, currentLocation))
			{
				Log.d(MainActivity.TAG,"LocationTrackingService ---> onLocationChanged(): Updating Location ... ");
				currentLocation = location;
			}
	}

	@Override
	public void onProviderDisabled(String arg0) {
		Log.d(MainActivity.TAG,"LocationTrackingService ---> onProviderDisabled()");
	}

	@Override
	public void onProviderEnabled(String provider) {
		Log.d(MainActivity.TAG,"LocationTrackingService ---> onProviderEnabled()");
	}

	@Override
	public void onStatusChanged(String provider, int status, Bundle extras) {
		Log.d(MainActivity.TAG,"LocationTrackingService ---> onStatusChanged()");
	}

	/***********************************/
	
	public Location getCurrentLocation() {
		Log.d(MainActivity.TAG,"LocationTrackingService ---> getCurrentLocation()");
		return currentLocation;
	}
}
