package gpslogger;
import java.awt.BorderLayout;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.Label;
import java.awt.Panel;
import java.awt.TextField;
import java.awt.Toolkit;
import java.awt.Image;
import java.text.DecimalFormat;
import java.util.Timer;
import java.util.TimerTask;
import java.net.MalformedURLException;
import java.net.URL;
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 util.GoogleTile;
import util.GoogleTileURL;
import util.ImageCanvas;
import util.PositionHelper;
/**
* This is the meat of our application. It will be only be created
* once the services it uses exist.
*
* @author finsprings
*
*/
public class MyApplication {
/**
* The time, in milliseconds, between updates of our position.
*/
private static final long PERIOD = 3000;
/**
* The zoom level we want for our Google Tiles.
*/
private final int TILE_ZOOM_LEVEL = 2;
/**
* The starting position of our route.
*/
private LatLon startLatLon = null;
/**
* Our current position.
*/
private LatLon currentLatLon;
/**
* The frame into which we'll stuff our UI.
*/
private Frame frame;
/**
* The panel where we'll stick our positions and distance traveled.
*/
private Panel topPanel;
/**
* The panel where we'll stick the Google Tile.
*/
private Panel bottomPanel;
/**
* The field we'll display our start position in.
*/
private TextField startPosition;
/**
* The field we'll display our current position in.
*/
private TextField currentPosition;
/**
* The field we'll display the distance traveled in.
*/
private TextField distance;
/**
* A helper to let us get the Google Tile onto our UI.
*/
private Toolkit tk;
/**
* A canvas to stick the Google Tile image on.
*/
private ImageCanvas canvas;
/**
* The format for the distance we display so we don't show tedious
* numbers of digits after the decimal point.
*/
private final DecimalFormat distanceFormat = new DecimalFormat("##0.00;-##0.00");
/**
* The timer that will ping us every time we want to update the UI.
*/
private final Timer timer = new Timer();
/**
* Our access to the display.
*/
private final IModuleDisplay display;
/**
* Our access to our current position from the GPS.
*/
private final IPositionProvider position;
/**
* Our constructor. We just save the service handles.
*
* @param display handle to the display service so we can make our UI
* @param position handle to the position service (GPS)
*/
public MyApplication(IModuleDisplay display, IPositionProvider position) {
this.display = display;
this.position = position;
}
/**
* Start ourselves up.
*/
public void start() {
System.out.println( "GpsLogger: app starting" );
createUI();
frame.show();
// Set up our timer to fire every PERIOD ms and call our update method.
timer.schedule( new TimerTask() {
public void run() {
MyApplication.this.update();
}
}, 0, PERIOD );
System.out.println( "GpsLogger: app started" );
}
/**
* Shut ourselves down.
*/
public void stop() {
System.out.println( "GpsLogger: app stopping" );
// make sure we don't try and update again
timer.cancel();
// get rid of our UI
frame.dispose();
System.out.println( "GpsLogger: app stopped" );
}
/**
* Build our ugly UI.
*/
private void createUI() {
frame = display.getFrame();
frame.setTitle("GpsLogger");
frame.setLayout( new BorderLayout() );
topPanel = new Panel();
topPanel.setLayout( new GridLayout( 3, 2) );
topPanel.add( new Label( "Start Position:" ));
startPosition = new TextField();
topPanel.add( startPosition );
topPanel.add(new Label( "Current Position:" ));
currentPosition = new TextField();
topPanel.add( currentPosition );
topPanel.add(new Label( "Distance Travelled:" ));
distance = new TextField();
topPanel.add( distance );
frame.add( topPanel, BorderLayout.NORTH );
tk = Toolkit.getDefaultToolkit();
canvas = new ImageCanvas();
bottomPanel = new Panel();
bottomPanel.setLayout( new BorderLayout() );
bottomPanel.add(canvas, BorderLayout.CENTER );
// I can't remember any AWT stuff so this looks
// pretty bad on-screen.
frame.add( bottomPanel, BorderLayout.CENTER );
}
/**
* Our callback when our update timer fires. We
* need to get our current position and update our UI.
*/
private void update() {
System.out.println( "GpsLogger: updating position" );
try {
// update where we are
currentLatLon = position.getLatitudeLongitude();
if (currentLatLon == null) {
System.err.println("Unable to update position: got null position back.");
return;
}
} catch (Exception e) {
System.err.println("Unable to get position because of:");
e.printStackTrace();
return;
}
currentPosition.setText( PositionHelper.latLonToString( currentLatLon ) );
// if this is the first time we've gotten a fix then
// set our start position as well
if (startPosition.getText().length() == 0) {
System.out.println("Setting start info (" + startLatLon +
" / " + startPosition);
startLatLon = currentLatLon;
startPosition.setText(currentPosition.getText());
}
// update how far we've come
final double d = PositionHelper.calculateDistance( startLatLon, currentLatLon );
distance.setText( "" + distanceFormat.format( d ) + " km" );
// update the tile for where we are
final GoogleTile tile = new GoogleTile(
currentLatLon.latitude, currentLatLon.longitude, TILE_ZOOM_LEVEL );
try {
final Image img = tk.createImage(new URL( GoogleTileURL.url( tile ) ) );
canvas.setImage( img );
}
catch ( MalformedURLException e ) {
System.err.println( "Failed to update Google Tile: " + e.getMessage() );
}
}
}