/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package gps;

import javax.microedition.location.*;
import mdot.Main;
import structures.Constants;
//import CommonFunctions.debugPrinter;

/**
 *
 * @author Ali
 */
public class GPS implements LocationListener {
    // Criteria can be used to provide underlying implementation the criteria
    // information to choose the appropriate location provider (if multiple
    // are available). However, the implementation does not guarantee that
    // a provider would be returned incase the criteria is not met. Hence, I
    // decided not to specify the criteria at this time
    //Criteria criteria;

    LocationProvider provider;
    UpdateHandler handler;
    boolean done;

    public GPS() {
        done = false;
	handler = new UpdateHandler();
	new Thread(handler).start();
        try {
            //criteria = new Criteria();
            provider = LocationProvider.getInstance(null);
            provider.setLocationListener(this,
                    -1 /* use the default interval */,
                    -1 /* use the default timeout */,
                    -1 /* use the default maxAge */);
        }
        catch (LocationException e) {
            //debugPrinter.printLine("LOCATION ERROR: Unable to connect to" +
            //        " location provider.");

            // Give default latitude and longitude
            Main.getMe().setObjectAsString(Constants.HASH_LATITUDE, "42.251952");
            Main.getMe().setObjectAsString(Constants.HASH_LONGITUDE, "-85.641168");
        }
        catch (SecurityException e) {
            //debugPrinter.printLine("SECURITY ERROR: application does not have" +
            //        " permission to query the location information.");

            // Give default latitude and longitude
            Main.getMe().setObjectAsString(Constants.HASH_LATITUDE, "42.251896533");
            Main.getMe().setObjectAsString(Constants.HASH_LONGITUDE, "-85.641268281");
        }
    }

    @Override
    public void locationUpdated(LocationProvider provider, Location location) {
	handler.handleUpdate(location);
    }

    @Override
    public void providerStateChanged(LocationProvider provider, int newState) {
        // Not using, in which case the old location will be used
    }

    class UpdateHandler implements Runnable {
	private Location updatedLocation = null;

	// The run method performs the actual processing of the location updates
        @Override
	public void run() {
	    Location locationToBeHandled = null;
	    while (!done) {
		synchronized(this) {
		    if (updatedLocation == null) {
			try {
			    wait();
			} catch (Exception e) {
			    e.printStackTrace();
			}
		    }
		    locationToBeHandled = updatedLocation;
		    updatedLocation = null;
		}

		if (locationToBeHandled != null)
		    processUpdate(locationToBeHandled);
	    }
	}

	public synchronized void handleUpdate(Location update) {
	    updatedLocation = update;
	    notify();
	}

	private void processUpdate(Location update) {
            if (update != null) {
                QualifiedCoordinates coord = update.getQualifiedCoordinates();
                if (coord.getLatitude() == 2.0 && coord.getLongitude() == 2.0) {
                    // This is only needed for emulator. When nothing is
                    // specified in the External Event Generator (Location)
                    // window, the values default to 2.0, in which case we
                    // set it to our default values
                    Main.getMe().setObjectAsString(Constants.HASH_LATITUDE, "42.251896533");
                    Main.getMe().setObjectAsString(Constants.HASH_LONGITUDE, "-85.641268281");
                }
                else {
                    float azimuth = 0.0f;
                    String gpsOrientation = "";
                    double numberHeading =  0.0;

                    // Replace Latitude, Longitude and heading in context
                    if (Main.getMe().ContainsKey(Constants.HASH_LATITUDE)) {
                        Main.getMe().replaceObjectAsString(Constants.HASH_LATITUDE,
                                Double.toString(coord.getLatitude()));
                    } else {
                        Main.getMe().setObjectAsString(Constants.HASH_LATITUDE,
                                Double.toString(coord.getLatitude()));
                    }
                    if (Main.getMe().ContainsKey(Constants.HASH_LONGITUDE)) {
                        Main.getMe().replaceObjectAsString(Constants.HASH_LONGITUDE,
                                Double.toString(coord.getLongitude()));
                    } else {
                        Main.getMe().setObjectAsString(Constants.HASH_LONGITUDE,
                                Double.toString(coord.getLongitude()));
                    }

                    // Change azimuth degrees to 8 point heading
                    try {
                        azimuth = Orientation.getOrientation().getCompassAzimuth();
                        numberHeading = Math.round(azimuth / 45);
                    }
                    catch (Exception e) { e.printStackTrace(); }

                    if (numberHeading == 0) {
                        gpsOrientation = Constants.GPS_ORIENTATION_NORTH;
                    } else if (numberHeading == 1) {
                        gpsOrientation = Constants.GPS_ORIENTATION_NORTHEAST;
                    } else if (numberHeading == 2) {
                        gpsOrientation = Constants.GPS_ORIENTATION_EAST;
                    } else if (numberHeading == 3) {
                        gpsOrientation = Constants.GPS_ORIENTATION_SOUTHEAST;
                    } else if (numberHeading == 4) {
                        gpsOrientation = Constants.GPS_ORIENTATION_SOUTH;
                    } else if (numberHeading == 5) {
                        gpsOrientation = Constants.GPS_ORIENTATION_SOUTHWEST;
                    } else if (numberHeading == 6) {
                        gpsOrientation = Constants.GPS_ORIENTATION_WEST;
                    } else if (numberHeading == 7) {
                        gpsOrientation = Constants.GPS_ORIENTATION_NORTHWEST;
                    } else if (numberHeading == 8) {
                        gpsOrientation = Constants.GPS_ORIENTATION_NORTH;
                    }

                    if (Main.getMe().ContainsKey(Constants.HASH_HEADING)) {
                        Main.getMe().replaceObjectAsString(Constants.HASH_HEADING, gpsOrientation);
                    } else {
                        if (gpsOrientation != null) {
                            Main.getMe().setObjectAsString(Constants.HASH_HEADING, gpsOrientation);
                        }
                    }
                }
            }
        }
    }
}