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

package gps;

import CommonFunctions.debugPrinter;
import java.io.*;
import java.util.*;
import gnu.io.*;
import java.text.DecimalFormat;
import mdot.Main;
import structures.Constants;

/**
 *
 * @author Jamie Groos
 */
public class GPS implements SerialPortEventListener {

    static CommPortIdentifier portId;
    static Enumeration portList;

    InputStream inputStream;
    SerialPort serialPort;

    public GPS(String port)
    {
        boolean serialPortFound = false;
        boolean serialSetupSuccess = false;

        //Detect GPS device connected to serial port
        portList = CommPortIdentifier.getPortIdentifiers();

        while (portList.hasMoreElements()) {
            portId = (CommPortIdentifier) portList.nextElement();
            if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) {
                if (portId.getName().equals(port)) {

                    serialPortFound = true;
                    serialSetupSuccess = setupSerialPort();

                }
            }
        }

        //Handle Errors
        if(serialPortFound == false)
        {
            debugPrinter.printLine("GPS ERROR: No serial port found.");

            //give default latitude and longitude
            Main.getMe().setObjectAsString(Constants.HASH_LATITUDE, "42.251896533");
            Main.getMe().setObjectAsString(Constants.HASH_LONGITUDE, "-85.641268281");
        }
        if(serialSetupSuccess == false)
        {
            debugPrinter.printLine("GPS ERROR: Failed to setup serial port.");

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

    private boolean setupSerialPort()
    {
        boolean success = true;
        try {
            serialPort = (SerialPort) portId.open("SimpleReadApp", 2000);
            }
        catch (PortInUseException e) {
            System.out.println(e);
            success = false;
            }
        try {
            inputStream = serialPort.getInputStream();
            }
        catch (IOException e) {
            System.out.println(e);
            success = false;
            }
	try {
            serialPort.addEventListener(this);
            }
        catch (TooManyListenersException e) {
            System.out.println(e);
            success = false;
            }

        serialPort.notifyOnDataAvailable(true);

        try {
            serialPort.setSerialPortParams(9600,
                SerialPort.DATABITS_8,
                SerialPort.STOPBITS_1,
                SerialPort.PARITY_NONE);
            }
        catch (UnsupportedCommOperationException e) {
            System.out.println(e);
            success = false;
            }
            
        return success;

    }

    public void serialEvent(SerialPortEvent event) {
         switch (event.getEventType()) {
            case SerialPortEvent.BI:
            case SerialPortEvent.OE:
            case SerialPortEvent.FE:
            case SerialPortEvent.PE:
            case SerialPortEvent.CD:
            case SerialPortEvent.CTS:
            case SerialPortEvent.DSR:
            case SerialPortEvent.RI:
            case SerialPortEvent.OUTPUT_BUFFER_EMPTY:
                break;
            case SerialPortEvent.DATA_AVAILABLE:
                byte[] readBuffer = new byte[120];
                byte byteRead;
                try {
                    int i = 0;

                    //Read string until there is a carriage return
                    while (true) {
                        byteRead = (byte) inputStream.read();

                        //Check to see if it is the commpand prompt;
                        if (byteRead == "\r".getBytes()[0]) {
                            break;
                        } else { //keep reading
                            readBuffer[i] = byteRead;
                            i++;
                        }
                    }

                    String nmea = new String(readBuffer);
                    String firstToken = nmea.split(",")[0];
                    firstToken.trim();

                    //System.out.println(nmea);

                    //Read the sentences that start with $GPRMC
                    //$GPRMC,212627,A,4217.0638,N,08535.3452,W,000.1,059.0,140110,005.0,W*7F
                    if (firstToken.contains("$GPRMC")) {
                        //Error in string - should be 12 tokens
                        if (nmea.split(",").length < 12) {
                            
                            if (Main.getMe().ContainsKey(Constants.HASH_LATITUDE)) {
                            Main.getMe().removeObject(Constants.HASH_LATITUDE);
                            }
                            if (Main.getMe().ContainsKey(Constants.HASH_LONGITUDE)) {
                            Main.getMe().removeObject(Constants.HASH_LONGITUDE);
                            }
                            if (Main.getMe().ContainsKey(Constants.HASH_HEADING)) {
                            Main.getMe().removeObject(Constants.HASH_HEADING);
                            }
                            if (Main.getMe().ContainsKey(Constants.HASH_BEARING)) {
                            Main.getMe().removeObject(Constants.HASH_BEARING);
                            }

                            try {
                            Main.treeView.UpdateTree();
                            } catch (Exception ex) {
                            }
                             
                        } else {
                            String leadingZero = "^0*";
                            String nmealat = nmea.split(",")[3].replaceAll(leadingZero, "");
                            String nmealon = nmea.split(",")[5].replaceAll(leadingZero, "");

                            //format ddmm.mmmm convert to dd.dddddd
                            //1. Strip off dd
                            String latdegrees = nmealat.substring(0, 2);
                            String londegrees = nmealon.substring(0, 2);

                            //2. Convert mm.mmmm to .dddddd
                            Double latdecimal = Double.parseDouble(nmealat.substring(2));
                            Double londecimal = Double.parseDouble(nmealon.substring(2));

                            DecimalFormat sixDecPlaces = new DecimalFormat(".######");

                            latdecimal = Double.parseDouble(sixDecPlaces.format(latdecimal / 60));
                            londecimal = Double.parseDouble(sixDecPlaces.format(londecimal / 60));

                            //3. Add degrees
                            Double lat = latdecimal + Double.parseDouble(latdegrees);
                            Double lon = londecimal + Double.parseDouble(londegrees);

                            //Handle Hemispheres
                            String hemishphereNS = nmea.split(",")[4];
                            String hemishphereEW = nmea.split(",")[6];

                            if (hemishphereNS.equals("S")) {
                                lat *= -1;
                            }
                            if (hemishphereEW.equals("W")) {
                                lon *= -1;
                            }


                            //Change bearing degrees to 8 point heading
                            String gpsOrientation = "";
                            Double bearing = Double.parseDouble(nmea.split(",")[8]);
                            double numberHeading = Math.round(bearing / 45);

                            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;
                            }

                            //Replace Latitude, Longitude, heading, and bearing in context.
                            if (Main.getMe().ContainsKey(Constants.HASH_LATITUDE)) {
                            Main.getMe().replaceObjectAsString(Constants.HASH_LATITUDE, lat.toString());
                            } else {
                            Main.getMe().setObjectAsString(Constants.HASH_LATITUDE, lat.toString());
                            }
                            if (Main.getMe().ContainsKey(Constants.HASH_LONGITUDE)) {
                            Main.getMe().replaceObjectAsString(Constants.HASH_LONGITUDE, lon.toString());
                            } else {
                            Main.getMe().setObjectAsString(Constants.HASH_LONGITUDE, lon.toString());
                            }
                            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);
                            }
                            }
                            if (Main.getMe().ContainsKey(Constants.HASH_BEARING)) {
                            Main.getMe().replaceObjectAsString(Constants.HASH_BEARING, bearing.toString());
                            } else {
                            Main.getMe().setObjectAsString(Constants.HASH_BEARING, bearing.toString());
                            }

                            //Update the debug window
                            try {
                            Main.treeView.UpdateTree();
                            } catch (Exception ex) {
                            }

                           /*
                            debugPrinter.printLine("LAT: " + lat.toString());
                            debugPrinter.printLine("LON: " + lon.toString());
                            debugPrinter.printLine("BEARING: " + bearing.toString());*/

                        }
                    }


                } catch (IOException e) {
                    System.out.println(e);
                }
                break;
        }
    }
}
