/* ***********************************************************
 * This file was automatically generated on 2012-09-28.      *
 *                                                           *
 * If you have a bugfix for this file and want to commit it, *
 * please fix the bug in the generator. You can find a link  *
 * to the generator git on tinkerforge.com                   *
 *************************************************************/

package com.tinkerforge;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;

/**
 * Device for receiving GPS position
 */
public class BrickletGPS extends Device {
	private final static byte FUNCTION_GET_COORDINATES = (byte)1;
	private final static byte FUNCTION_GET_STATUS = (byte)2;
	private final static byte FUNCTION_RESTART = (byte)3;
	private final static byte FUNCTION_SET_COORDINATES_CALLBACK_PERIOD = (byte)4;
	private final static byte FUNCTION_GET_COORDINATES_CALLBACK_PERIOD = (byte)5;
	private final static byte FUNCTION_SET_STATUS_CALLBACK_PERIOD = (byte)6;
	private final static byte FUNCTION_GET_STATUS_CALLBACK_PERIOD = (byte)7;
	private final static byte CALLBACK_COORDINATES = (byte)8;
	private final static byte CALLBACK_STATUS = (byte)9;

	public class Coordinates {
		public char ns;
		public int[] latitude = new int[2];
		public char ew;
		public int[] longitude = new int[2];
		public int pdop;
		public int hdop;
		public int vdop;

		public String toString() {
			return "[" + "ns = " + ns + ", " + "latitude = " + latitude + ", " + "ew = " + ew + ", " + "longitude = " + longitude + ", " + "pdop = " + pdop + ", " + "hdop = " + hdop + ", " + "vdop = " + vdop + "]";
		}
	}

	public class Status {
		public short fix;
		public short satellitesView;
		public short satellitesUsed;
		public int speed;
		public int course;
		public long date;
		public long time;
		public short altitude;
		public short altitudeAccuracy;

		public String toString() {
			return "[" + "fix = " + fix + ", " + "satellitesView = " + satellitesView + ", " + "satellitesUsed = " + satellitesUsed + ", " + "speed = " + speed + ", " + "course = " + course + ", " + "date = " + date + ", " + "time = " + time + ", " + "altitude = " + altitude + ", " + "altitudeAccuracy = " + altitudeAccuracy + "]";
		}
	}

	/**
	 * 
	 */
	public interface CoordinatesListener {
		public void coordinates(char ns, int[] latitude, char ew, int[] longitude, int pdop, int hdop, int vdop);
	}

	/**
	 * 
	 */
	public interface StatusListener {
		public void status(short fix, short satellitesView, short satellitesUsed, int speed, int course, long date, long time, short altitude, short altitudeAccuracy);
	}

	/**
	 * Creates an object with the unique device ID \c uid. This object can
	 * then be added to the IP connection.
	 */
	public BrickletGPS(String uid) {
		super(uid);

		expectedName = "GPS Bricklet";

		bindingVersion[0] = 1;
		bindingVersion[1] = 0;
		bindingVersion[2] = 0;

		callbacks[CALLBACK_COORDINATES] = new CallbackListener() {
			public void callback(byte[] data) {
				ByteBuffer bb = ByteBuffer.wrap(data, 4, data.length - 4);
				bb.order(ByteOrder.LITTLE_ENDIAN);

				char ns = (char)(bb.get());
				int[] latitude = new int[2];
				for(int i = 0; i < 2; i++) {
					latitude[i] = IPConnection.unsignedShort(bb.getShort());
				}

				char ew = (char)(bb.get());
				int[] longitude = new int[2];
				for(int i = 0; i < 2; i++) {
					longitude[i] = IPConnection.unsignedShort(bb.getShort());
				}

				int pdop = IPConnection.unsignedShort(bb.getShort());
				int hdop = IPConnection.unsignedShort(bb.getShort());
				int vdop = IPConnection.unsignedShort(bb.getShort());

				((CoordinatesListener)listenerObjects[CALLBACK_COORDINATES]).coordinates(ns, latitude, ew, longitude, pdop, hdop, vdop);
			}
		};

		callbacks[CALLBACK_STATUS] = new CallbackListener() {
			public void callback(byte[] data) {
				ByteBuffer bb = ByteBuffer.wrap(data, 4, data.length - 4);
				bb.order(ByteOrder.LITTLE_ENDIAN);

				short fix = IPConnection.unsignedByte(bb.get());
				short satellitesView = IPConnection.unsignedByte(bb.get());
				short satellitesUsed = IPConnection.unsignedByte(bb.get());
				int speed = IPConnection.unsignedShort(bb.getShort());
				int course = IPConnection.unsignedShort(bb.getShort());
				long date = IPConnection.unsignedInt(bb.getInt());
				long time = IPConnection.unsignedInt(bb.getInt());
				short altitude = (bb.getShort());
				short altitudeAccuracy = (bb.getShort());

				((StatusListener)listenerObjects[CALLBACK_STATUS]).status(fix, satellitesView, satellitesUsed, speed, course, date, time, altitude, altitudeAccuracy);
			}
		};
	}

	/**
	 * 
	 */
	public Coordinates getCoordinates() throws IPConnection.TimeoutException {
		ByteBuffer bb = IPConnection.createRequestBuffer((byte)stackID, FUNCTION_GET_COORDINATES, (short)4);

		byte[] response = sendRequestExpectResponse(bb.array(), FUNCTION_GET_COORDINATES);

		bb = ByteBuffer.wrap(response, 4, response.length - 4);
		bb.order(ByteOrder.LITTLE_ENDIAN);

		Coordinates obj = new Coordinates();
		obj.ns = (char)(bb.get());
		for(int i = 0; i < 2; i++) {
			obj.latitude[i] = IPConnection.unsignedShort(bb.getShort());
		}

		obj.ew = (char)(bb.get());
		for(int i = 0; i < 2; i++) {
			obj.longitude[i] = IPConnection.unsignedShort(bb.getShort());
		}

		obj.pdop = IPConnection.unsignedShort(bb.getShort());
		obj.hdop = IPConnection.unsignedShort(bb.getShort());
		obj.vdop = IPConnection.unsignedShort(bb.getShort());

		return obj;
	}

	/**
	 * 
	 */
	public Status getStatus() throws IPConnection.TimeoutException {
		ByteBuffer bb = IPConnection.createRequestBuffer((byte)stackID, FUNCTION_GET_STATUS, (short)4);

		byte[] response = sendRequestExpectResponse(bb.array(), FUNCTION_GET_STATUS);

		bb = ByteBuffer.wrap(response, 4, response.length - 4);
		bb.order(ByteOrder.LITTLE_ENDIAN);

		Status obj = new Status();
		obj.fix = IPConnection.unsignedByte(bb.get());
		obj.satellitesView = IPConnection.unsignedByte(bb.get());
		obj.satellitesUsed = IPConnection.unsignedByte(bb.get());
		obj.speed = IPConnection.unsignedShort(bb.getShort());
		obj.course = IPConnection.unsignedShort(bb.getShort());
		obj.date = IPConnection.unsignedInt(bb.getInt());
		obj.time = IPConnection.unsignedInt(bb.getInt());
		obj.altitude = (bb.getShort());
		obj.altitudeAccuracy = (bb.getShort());

		return obj;
	}

	/**
	 * 
	 */
	public void restart(short restartType)  {
		ByteBuffer bb = IPConnection.createRequestBuffer((byte)stackID, FUNCTION_RESTART, (short)5);
		bb.put((byte)restartType);

		sendRequestNoResponse(bb.array());
	}

	/**
	 * 
	 */
	public void setCoordinatesCallbackPeriod(long period)  {
		ByteBuffer bb = IPConnection.createRequestBuffer((byte)stackID, FUNCTION_SET_COORDINATES_CALLBACK_PERIOD, (short)8);
		bb.putInt((int)period);

		sendRequestNoResponse(bb.array());
	}

	/**
	 * Returns the period as set by {@link com.tinkerforge.BrickletGPS.setCoordinatesCallbackPeriod}.
	 */
	public long getCoordinatesCallbackPeriod() throws IPConnection.TimeoutException {
		ByteBuffer bb = IPConnection.createRequestBuffer((byte)stackID, FUNCTION_GET_COORDINATES_CALLBACK_PERIOD, (short)4);

		byte[] response = sendRequestExpectResponse(bb.array(), FUNCTION_GET_COORDINATES_CALLBACK_PERIOD);

		bb = ByteBuffer.wrap(response, 4, response.length - 4);
		bb.order(ByteOrder.LITTLE_ENDIAN);

		long period = IPConnection.unsignedInt(bb.getInt());

		return period;
	}

	/**
	 * 
	 */
	public void setStatusCallbackPeriod(long period)  {
		ByteBuffer bb = IPConnection.createRequestBuffer((byte)stackID, FUNCTION_SET_STATUS_CALLBACK_PERIOD, (short)8);
		bb.putInt((int)period);

		sendRequestNoResponse(bb.array());
	}

	/**
	 * Returns the period as set by {@link com.tinkerforge.BrickletGPS.getStatusCallbackPeriod}.
	 */
	public long getStatusCallbackPeriod() throws IPConnection.TimeoutException {
		ByteBuffer bb = IPConnection.createRequestBuffer((byte)stackID, FUNCTION_GET_STATUS_CALLBACK_PERIOD, (short)4);

		byte[] response = sendRequestExpectResponse(bb.array(), FUNCTION_GET_STATUS_CALLBACK_PERIOD);

		bb = ByteBuffer.wrap(response, 4, response.length - 4);
		bb.order(ByteOrder.LITTLE_ENDIAN);

		long period = IPConnection.unsignedInt(bb.getInt());

		return period;
	}

	/**
	 * Registers a listener object.
	 */
	public void addListener(Object o) {
		if(o instanceof CoordinatesListener) {
			listenerObjects[CALLBACK_COORDINATES] = o;
		} else if(o instanceof StatusListener) {
			listenerObjects[CALLBACK_STATUS] = o;
		}
	}
}