package source;

/**
 *
 * @author Radoslaf
 */
public class NmeaParser extends Thread {

    private DataHandler handler = null;
    private Navigator navi = null;

    // Konstruktor
    NmeaParser(String name, DataHandler handler, Navigator navi) {
        super(name);
        this.handler = handler;
        this.navi = navi;

    }

    /* ------------------------------------------
     *           NMEA0183 zpracovani
     * ----------------------------------------*/
    private String GGA,  GLL,  GSV,  RMC,  VTG,  GSA = null;
    private String buffer = null;
    private String data = null;
    private double longitude = 0;
    private double latitude = 0;
    private int time = 0;
    private String NS = null;
    private String WE = null;
    private int elevation = 0;
    private double HDOP = 0.0;
    private double VDOP = 0.0;
    private double speed = 0.0;
    private int direction = 0;
    private int datum = 0;
    private int[][] sat = new int[12][4];
    private String aktGLL = null;
    private String aktRMC = null;
    private boolean aktGGA = false;
    private boolean aktGSA = false;
    private boolean aktGSV = false;
    private boolean isGLL = false;
    private boolean isRMC = false;
    //private boolean aktVTG = false;
    public boolean done = false;

    public void run() {
        while (navi.b.getIsConnect() == true) {
            this.sort();
            this.uploadData();
            Thread.yield();
        }
    }

    private void sort() {
        data = this.handler.getCache();
        done = false;
        // Rozdělení na jednotlive NMEA věty
        if (data != null) {
            while (data.indexOf("$") != -1) {
                if (data.indexOf("*") != -1) {
                    int start, end = 0;
                    start = data.indexOf("$");
                    end = data.indexOf("*");
                    // Podmínka, která ošetří, že pokud chybí znak $ dojde k chybě
                    if (start > end) {
                        data = data.substring(end + 1, data.length());
                        start = data.indexOf("$");
                        end = data.indexOf("*");
                    }
                    // Podmínka, která zaručí, že věta byla přijata v celku
                    if (start != -1 && end != -1) {
                        buffer = data.substring(start, end);
                        // Dělení na konkretní NMEA věty
                        this.nmeaSort(buffer);
                    }
                    end = data.indexOf("$");
                    data = data.substring(end + 1, data.length());
                }
            }
        }
    }

    private void nmeaSort(String buffer) {
        int s, e = 0;
        int num = 0;
        String head = buffer.substring(3, 6);
        if (head.equals("GGA")) {
            num = 1;
        }
        if (head.equals("GLL")) {
            num = 2;
        }
        if (head.equals("GSA")) {
            num = 3;
        }
        if (head.equals("GSV")) {
            num = 4;
        }
        if (head.equals("RMC")) {
            num = 5;
        }
        if (head.equals("VTG")) {
            num = 6;
        }
        switch (num) {
            case 1:
                s = buffer.indexOf("GGA");
                e = buffer.length();
                GGA = buffer.substring(s + 4, e);
                this.aktGGA = true;
                this.GGAparser();
                break;
            case 2:
                s = buffer.indexOf("GLL");
                e = buffer.length();
                GLL = buffer.substring(s + 4, e);
                this.isGLL = true;
                this.GLLparser();
                break;
            case 3:
                s = buffer.indexOf("GSA");
                e = buffer.length();
                GSA = buffer.substring(s + 4, e);
                this.aktGSA = true;
                this.GSAparser();
                break;
            case 4:
                s = buffer.indexOf("GSV");
                e = buffer.length();
                GSV = buffer.substring(s + 4, e);
                this.aktGSV = true;
                this.GSVparser();
                break;
            case 5:
                s = buffer.indexOf("RMC");
                e = buffer.length();
                RMC = buffer.substring(s + 4, e);
                this.isRMC = true;
                this.RMCparser();
                break;
            case 6:
                s = buffer.indexOf("VTG");
                e = buffer.length();
                VTG = buffer.substring(s + 4, e);
                break;
        }
    }

    private void GGAparser() {
        int e = 0;
        // Zjištění času
        e = this.GGA.indexOf(",");
        if (e != 0) {
            this.time = (int) Float.parseFloat(this.GGA.substring(0, e));
        }
        GGA = GGA.substring(e + 1, GGA.length());
        // Zjištění zeměpisné šířky
        e = this.GGA.indexOf(",");
        if (e != 0) {
            this.latitude = Float.parseFloat(this.GGA.substring(0, e));
        } else {
            this.latitude = 0;
        }
        GGA = GGA.substring(e + 1, GGA.length());
        // Zjištění zeměpisné šířky
        e = this.GGA.indexOf(",");
        this.NS = this.GGA.substring(0, e);
        GGA = GGA.substring(e + 1, GGA.length());
        // Zjištění zeměpisné delky
        e = this.GGA.indexOf(",");
        if (e != 0) {
            this.longitude = Float.parseFloat(this.GGA.substring(0, e));
        } else {
            this.longitude = 0;
        }
        GGA = GGA.substring(e + 1, GGA.length());
        // Zjištění zeměpisné delky
        e = this.GGA.indexOf(",");
        this.WE = this.GGA.substring(0, e);
        GGA = GGA.substring(e + 10, GGA.length());
        // Nadmořská výška
        e = this.GGA.indexOf(",");
        if (e != 0) {
            this.elevation = (int) Float.parseFloat(this.GGA.substring(0, e));
        } else {
            this.elevation = 0;
        }
    }

    private void GLLparser() {
        int e = 0;
        // Zjištění zeměpisné sirky
        e = this.GLL.indexOf(",");
        if (e != 0) {
            this.latitude = Float.parseFloat(this.GLL.substring(0, e));
        } else {
            this.latitude = 0;
        }
        GLL = GLL.substring(e + 1, GLL.length());
        // Zjištění zeměpisné sirky
        e = this.GLL.indexOf(",");
        this.NS = this.GLL.substring(0, e);
        GLL = GLL.substring(e + 1, GLL.length());
        // Zjištění zeměpisné delky
        e = this.GLL.indexOf(",");
        if (e != 0) {
            this.longitude = Float.parseFloat(this.GLL.substring(0, e));
        } else {
            this.longitude = 0;
        }
        GLL = GLL.substring(e + 1, GLL.length());
        // Zjištění zeměpisné delky
        e = this.GLL.indexOf(",");
        this.WE = this.GLL.substring(0, e);
        GLL = GLL.substring(e + 1, GLL.length());
        // Zjištění času
        e = this.GLL.indexOf(",");
        if (e != 0) {
            this.time = (int) Float.parseFloat(this.GLL.substring(0, e));
        } else {
            this.time = 0;
        }
        GLL = GLL.substring(e + 1, GLL.length());
        // Aktualnost dat
        e = this.GLL.indexOf(",");
        this.aktGLL = this.GLL.substring(e + 1, GLL.length());
    }

    private void GSAparser() {
        // Budu získavat pouze udaje HDOP a VDOP
        int e = GSA.length();
        // Ořezání věty na posledni dva parametry
        GSA = GSA.substring(e - 8, e);
        int l = GSA.indexOf(",");
        if (l == 0) {
            GSA = GSA.substring(1, GSA.length());
        }
        if (l == 1) {
            GSA = GSA.substring(2, GSA.length());
        }
        e = this.GSA.indexOf(",");
        if (e != 0) {
            this.VDOP = (double) Float.parseFloat(this.GSA.substring(e + 1, GSA.length()));
            this.HDOP = (double) Float.parseFloat(this.GSA.substring(0, e));
        }
    }

    private void GSVparser() {
        // Posunutí při příchodu další části věty GSV s různými informacemi
        int k = 0;
        k = (int) Float.parseFloat(this.GSV.substring(2, 3));
        int d = 0;
        if (k == 1) {
            d = 0;
        }
        if (k == 2) {
            d = 4;
        }
        if (k == 3) {
            d = 8;
        }
        // Ořezání věty a upravení věty
        this.GSV = GSV.substring(7, GSV.length());
        this.GSV = GSV + ",";
        int GSV_len = GSV.length();
        int tmp = 0;
        if (GSV_len < 14) {
            tmp = 1;
        }
        if (GSV_len < 27 && tmp != 1) {
            tmp = 2;
        }
        if (GSV_len < 40 && tmp != 2 && tmp != 1) {
            tmp = 3;
        }
        if (GSV_len < 53 && tmp != 2 && tmp != 1 && tmp != 3) {
            tmp = 4;
        }
        // Jedna věta obsahuje data o 4 družicích
        int e = 0;
        for (int j = 0; j < tmp; j++) {
            //if (j != 0) {
            //    this.GSV.substring(12, this.GSV.length());
            //}
            for (int i = 0; i < 4; i++) {
                e = this.GSV.indexOf(",");
                // Pokud retezec je prazdny
                if (this.GSV.substring(0, e).equals("")) {
                    this.sat[j + d][i] = 0;
                } else {
                    this.sat[j + d][i] = (int) Float.parseFloat(this.GSV.substring(0, e));
                }
                // Podmínka pro poslední cyklus
                //if (j != 3) {
                this.GSV = this.GSV.substring(e + 1, this.GSV.length());
            //}
            }
        }
    }

    private void RMCparser() {
        int e = 0;
        // Aktualní čas
        e = this.RMC.indexOf(",");
        if (e != 0) {
            this.time = (int) Float.parseFloat(this.RMC.substring(0, e));
        } else {
            this.time = 0;
        }
        this.RMC = this.RMC.substring(e + 1, this.RMC.length());
        // Stav dat
        e = this.RMC.indexOf(",");
        this.aktRMC = this.RMC.substring(0, e);
        this.RMC = this.RMC.substring(e + 1, this.RMC.length());
        // Zeměpisná sirky
        e = this.RMC.indexOf(",");
        if (e != 0) {
            this.latitude = Float.parseFloat(this.RMC.substring(0, e));
        } else {
            this.latitude = 0;
        }
        this.RMC = this.RMC.substring(e + 1, this.RMC.length());
        // Zeměpisná sirky
        e = this.RMC.indexOf(",");
        this.NS = this.RMC.substring(0, e);
        this.RMC = this.RMC.substring(e + 1, this.RMC.length());
        // Zeměpisná delky
        e = this.RMC.indexOf(",");
        if (e != 0) {
            this.longitude = Float.parseFloat(this.RMC.substring(0, e));
        } else {
            this.longitude = 0;
        }
        this.RMC = this.RMC.substring(e + 1, this.RMC.length());
        // Zeměpisná delky
        e = this.RMC.indexOf(",");
        this.WE = this.RMC.substring(0, e);
        this.RMC = this.RMC.substring(e + 1, this.RMC.length());
        // Rychlost
        e = this.RMC.indexOf(",");
        if (e != 0) {
            this.speed = Float.parseFloat(this.RMC.substring(0, e));
        } else {
            this.speed = 0;
        }
        this.RMC = this.RMC.substring(e + 1, this.RMC.length());
        // Směr
        e = this.RMC.indexOf(",");
        if (e != 0) {
            this.direction = (int) Float.parseFloat(this.RMC.substring(0, e));
        } else {
            this.direction = 0;
        }
        this.RMC = this.RMC.substring(e + 1, this.RMC.length());
        // Datum
        e = this.RMC.indexOf(",");
        if (e != 0) {
            this.datum = (int) Float.parseFloat(this.RMC.substring(0, e));
        } else {
            this.datum = 0;
        }
    }

    private synchronized void uploadData() {
        // Dočasná proměnná
        int tmp = 0;
        // Zkouska jsou li data platné
        if (this.isGLL == true) {
            if (this.aktGLL.equals("A")) {
                // Získání stupnu a minut zeměpisné delky
                short longit[] = new short[4];
                longit[0] = (short) (this.longitude / 100);
                longit[1] = (short) (this.longitude % 100);
                // Získaní sekund ve formatu ss.ss
                tmp = (int) ((this.longitude - (int) this.longitude) * 6000);
                longit[2] = (short) (tmp / 100);
                longit[3] = (short) (tmp % 100);
                this.handler.setLongitude(longit);
                this.handler.setNS(this.NS);
                longit = null;
                // -----------------------------------------------------------------
                // Získání stupnu a minut zeměpisné sirky
                short latit[] = new short[4];
                latit[0] = (short) ((int) this.latitude / 100);
                latit[1] = (short) ((int) this.latitude % 100);
                // Získaní sekund ve formatu ss.ss
                tmp = (int) ((this.latitude - (int) this.latitude) * 6000);
                latit[2] = (short) ((int) tmp / 100);
                latit[3] = (short) ((int) tmp % 100);
                this.handler.setLatitude(latit);
                this.handler.setWE(this.WE);
                latit = null;
                // -----------------------------------------------------------------
                // Získání akualního času
                // Hodiny
                short cas[] = new short[3];
                cas[0] = (short) (this.time / 10000);
                // Minuty a sekundy
                tmp = (int) (this.time % 10000);
                cas[1] = (short) (tmp / 100);
                cas[2] = (short) (tmp % 100);
                this.handler.setTime(cas);
                cas = null;
                //------------------------------------------------------------------
                this.aktGLL = null;
                this.isGLL = false;
            }
        }

        if (this.isRMC == true) {
            if (this.aktRMC.equals("A")) {
                // Získání akualního času
                // Hodiny
                short cas[] = new short[3];
                cas[0] = (short) (this.time / 10000);
                // Minuty a sekundy
                tmp = (int) (this.time % 10000);
                cas[1] = (short) (tmp / 100);
                cas[2] = (short) (tmp % 100);
                this.handler.setTime(cas);
                cas = null;
                //-----------------------------------------------------------------
                // Získání stupnu a minut zeměpisné delky
                short longit[] = new short[4];
                longit[0] = (short) (this.longitude / 100);
                longit[1] = (short) (this.longitude % 100);
                // Získaní sekund ve formatu ss.ss
                tmp = (int) ((this.longitude - (int) this.longitude) * 6000);
                longit[2] = (short) (tmp / 100);
                longit[3] = (short) (tmp % 100);
                this.handler.setLongitude(longit);
                this.handler.setNS(this.NS);
                longit = null;
                // -----------------------------------------------------------------
                // Získání stupnu a minut zeměpisné sirky
                short latit[] = new short[4];
                latit[0] = (short) ((int) this.latitude / 100);
                latit[1] = (short) ((int) this.latitude % 100);
                // Získaní sekund ve formatu ss.ss
                tmp = (int) ((this.latitude - (int) this.latitude) * 6000);
                latit[2] = (short) ((int) tmp / 100);
                latit[3] = (short) ((int) tmp % 100);
                this.handler.setLatitude(latit);
                this.handler.setWE(this.WE);
                latit = null;
                // -----------------------------------------------------------------
                // Přepočet rychlosti 1 uz = 1,852 km/h
                this.speed = this.speed * 1.852;
                this.handler.setSpeed((double) (int) ((this.speed + 0.005) * 100.0) / 100);
                // -----------------------------------------------------------------
                // Směr
                this.handler.setDirection((short) this.direction);
                //------------------------------------------------------------------
                // Aktualní datum
                // Den
                short date[] = new short[3];
                date[0] = (short) (this.datum / 10000);
                // Měsíc a roky
                tmp = (int) (this.datum % 10000);
                date[1] = (short) (tmp / 100);
                date[2] = (short) ((tmp % 100) + 2000);
                this.handler.setDatum(date);
                date = null;
                //------------------------------------------------------------------
                this.aktRMC = null;
                this.isRMC = false;
            }
        }

        if (this.aktGGA == true) {
            // Získání akualního času
            // Hodiny
            short cas[] = new short[3];
            cas[0] = (short) (this.time / 10000);
            // Minuty a sekundy
            tmp = (int) (this.time % 10000);
            cas[1] = (short) (tmp / 100);
            cas[2] = (short) (tmp % 100);
            this.handler.setTime(cas);
            cas = null;
            //-----------------------------------------------------------------
            // Získání stupnu a minut zeměpisné delky
            short longit[] = new short[4];
            longit[0] = (short) (this.longitude / 100);
            longit[1] = (short) (this.longitude % 100);
            // Získaní sekund ve formatu ss.ss
            tmp = (int) ((this.longitude - (int) this.longitude) * 6000);
            longit[2] = (short) (tmp / 100);
            longit[3] = (short) (tmp % 100);
            this.handler.setLongitude(longit);
            this.handler.setNS(this.NS);
            longit = null;
            // -----------------------------------------------------------------
            // Získání stupnu a minut zeměpisné sirky
            short latit[] = new short[4];
            latit[0] = (short) ((int) this.latitude / 100);
            latit[1] = (short) ((int) this.latitude % 100);
            // Získaní sekund ve formatu ss.ss
            tmp = (int) ((this.latitude - (int) this.latitude) * 6000);
            latit[2] = (short) ((int) tmp / 100);
            latit[3] = (short) ((int) tmp % 100);
            this.handler.setLatitude(latit);
            this.handler.setWE(this.WE);
            latit = null;
            // -----------------------------------------------------------------
            // Elevace
            this.handler.setElevation((short) this.elevation);
            this.aktGGA = false;
        }

        if (this.aktGSA == true) {
            this.handler.setHDOP(this.HDOP);
            this.handler.setVDOP(this.VDOP);
            this.aktGSA = false;
        }

        if (this.aktGSV == true) {
            // Kopírovaní pameti
            short druzice[][] = new short[12][4];
            for (int i = 0; i < 12; i++) {
                for (int j = 0; j < 4; j++) {
                    druzice[i][j] = (short) this.sat[i][j];
                }
            }
            this.handler.setSat(druzice);
            druzice = null;
            this.aktGSV = false;
        }
        done = true;
    }
}

   
