package gpsalarmclock.app;
/*This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see .
*/	
import java.awt.Button;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.Label;
import java.awt.Color;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.Double;
import java.util.Timer;
import java.util.TimerTask;

import gpsalarmclock.util.VKey;
import com.buglabs.bug.module.gps.pub.IPositionProvider;
import com.buglabs.bug.module.gps.pub.LatLon;
import com.buglabs.bug.module.lcd.pub.IModuleDisplay;
import gpsutilities.pub.*;

/**
 * An alarm clock for commuters, designed to go off within proximity to a station, 
 * rather than a specific time. The achilles heel is that you may not get a GPS signal
 * on your train or bus, but it was easy enough to whip up so hopefully it will work for some people.
 *  
 * @author Kevin Schultz kschultz@buglabs.net
 * @version 1
 * 
 * Current defects: 
 * 1) It doesn't alarm, while the base does have a tone generator I haven't coded it in here yet
 * 2) It doesn't save locations, ultimately I want to make a web service that keeps locations for all the various
 * GPS applications
 * 3) I want to make a virtual keyboard with only numbers, but we might be able to get the X11 virtual keyboard
 * without having to do anything, so I have to experiment with that on a BUG
 *
 */
public class GPSAlarmClockApp implements ActionListener {

	private Frame frame;
	private Label currentPositionLabelLat;
	private Label currentPositionLabelLon;
	private Label destinationLabelLat;
	private Label destinationLabelLon;
	private TextField currentPositionFieldLat;
	private TextField currentPositionFieldLon;
	private TextField destinationFieldLat;
	private TextField destinationFieldLon;
	private TextField distanceField;
	private Button destinationSet;	
	private Button dismissSet;
	private Button favoriteLocation;
	
	private Timer timer;
	
	private LatLon currentPosition = null;
	private LatLon destination = null;

	private boolean dismiss = false;
	
	/**
	 * Shaun's virtual keyboard, thanks Shaun!
	 */
	private VKey vkb; 
	
	private IGPSUtilProvider gpsUtil;
	
	private IPositionProvider position;
	
	private IModuleDisplay display;
	
	/**
	 * The constructor, takes two BUG module interfaces
	 * @param position
	 * @param display
	 */
	public GPSAlarmClockApp(IPositionProvider position, IModuleDisplay display, IGPSUtilProvider gpsUtil)  {
		//It only needs to poll the GPS every few minutes, the radius will be 2 or 3 miles
		final long PERIOD = 20000;
		
		this.position = position;
		this.display = display;
		this.gpsUtil = gpsUtil;
		
		vkb = new VKey(display.getFrame());
		
		currentPosition = new LatLon();
		destination = new LatLon();
		destination.latitude = 45;
		destination.longitude = -70;
				
		createUI();
		
		setCurrentPosition();
		
		timer = new Timer();
		timer.schedule( new TimerTask() { public void run() { withinRadius(); }}, 0, PERIOD );
	
	}
	
	/**
	 * Uses IGPSUtilProvider to see how far we are from the destination
	 */
	private void withinRadius() {

		final double alarmRadius = 2; //km
		double distance = 0;
		if ( dismiss == false ) {
			setCurrentPosition();
				
			distance = gpsUtil.calculateDistance(currentPosition, destination);
			distanceField.setText(Double.toString(distance));
			
			if ( distance <= alarmRadius && dismiss == false ) {
				ringAlarm();
			}
			else {
				System.out.println("GPSAlarmClock: Outside of alarm radius");
			}
		}
		else {
			timer.cancel();
		}
	}
	
	/**
	 * Currently does not ring alarm
	 */
	private void ringAlarm() {
		//TODO Actually make it ring
		System.out.println("GPSAlarmClock: Ring!");
	}
	private void setDestination() {
		//TODO make sure that the Lat and Lon coordinates are plausible
		
		destination.latitude = Double.parseDouble(destinationFieldLat.getText());
		destination.longitude = Double.parseDouble(destinationFieldLon.getText());
		System.out.println("GPSAlarmClock: Destination Latitude: " + destination.latitude);
		System.out.println("GPSAlarmClock: Destination Longitude: " + destination.longitude);
	}
	private void setCurrentPosition() {
		currentPosition = position.getLatitudeLongitude();
		currentPositionFieldLat.setText(Double.toString(currentPosition.latitude));
		currentPositionFieldLon.setText(Double.toString(currentPosition.longitude));
	}
	
	/**
	 * Sets up the frame and adds the components to it
	 */
	private void createUI() {

		//Make our frame
		frame = new Frame();
		frame = display.getFrame();
		frame.setBackground(Color.WHITE);
		frame.setLayout(new GridLayout(0,2));
		
		//Create all the objects
		currentPositionLabelLat = new Label("Current Position Latitude:");
		currentPositionFieldLat = new TextField();
		currentPositionLabelLon = new Label("Current Position Longitude:");
		currentPositionFieldLon = new TextField();
		destinationLabelLat     = new Label("Destination Latitude:");
		destinationFieldLat     = new TextField();
		destinationLabelLon     = new Label("Destination Longitude:");
		destinationFieldLon     = new TextField();
		destinationSet          = new Button("Set Destination");
		distanceField           = new TextField("Range");
		dismissSet              = new Button("Dismiss Alarm");
		favoriteLocation        = new Button("Favorite Location");
		
		//Add some color
		currentPositionFieldLat.setBackground(Color.WHITE);
		currentPositionFieldLon.setBackground(Color.WHITE);
		destinationFieldLat.setBackground(Color.WHITE);
		destinationFieldLon.setBackground(Color.WHITE);
		distanceField.setBackground(Color.RED);
		
		//Add the event handling
		currentPositionFieldLat.addFocusListener(vkb);
		currentPositionFieldLon.addFocusListener(vkb);
		destinationFieldLat.addFocusListener(vkb);
		destinationFieldLon.addFocusListener(vkb);
		destinationSet.addActionListener(this);
		dismissSet.addActionListener(this);
		
		//Add all the objects to the frame
		frame.add(currentPositionLabelLat);
		frame.add(currentPositionFieldLat);	
		frame.add(currentPositionLabelLon);
		frame.add(currentPositionFieldLon);	
		frame.add(destinationLabelLat);
		frame.add(destinationFieldLat);
		frame.add(destinationLabelLon);
		frame.add(destinationFieldLon);
		frame.add(destinationSet);
		frame.add(distanceField);
		frame.add(dismissSet);
		frame.add(favoriteLocation);

		//Paint it!
		frame.show();
		
	}

	/**
	 * Event handler
	 */
	public void actionPerformed(ActionEvent event) {
		if (event.getSource() == destinationSet) {
			setDestination();	
			withinRadius();
		}
		else if (event.getSource() == dismissSet) {
			dismiss = true;
			System.out.println("GPSAlarmClock: Alarm Dismissed");
		}
	}
}