/*
Trieda hlavného meracieho vlákna, ktorej objekt sa tvorí v triede hlavného
okna programu používateľského rozhrania.
Zodpovedá, za proces merania, príjem a uloženie súboru dát, zo zariadenia Arduino,
a čiastočnú úpravu zachytených dát, do podoby, aby boli použiteľné v objektoch
vizualizačných tied TableWindow a GraphsWindow ...
 */

package measurementThread;

import CommunicationAndSaving.propertiesFile;
import CommunicationAndSaving.serialCommunication;
import Windows.Window;

import javax.swing.*;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;

public class ThreadM extends Thread{

    private ArduinoAnswear answear;
    private Window window;
    private serialCommunication serial;
    private propertiesFile properties;
    private Thread functionThread;
    private boolean measurementStopped;
    private boolean measurementEnded;
    private StringBuilder firstValues;
    private ArrayList<String> fullValues;
    private static ArrayList<ArrayList<String>> measurementStaticSetsForResultsWindow;

    /*
    Konštruktor triedy "ThreadM", nastavuje premenné ovplyvňujúce proces merania ...
     */
    public ThreadM(Window window, ArduinoAnswear answear, serialCommunication serial, propertiesFile properties) throws IOException {
        this.window = window;
        this.answear = answear;
        this.serial = serial;
        this.properties = properties;
        measurementStopped = false;
        measurementEnded = false;
    }

    /*
    Funkcia, ktorá nastaví hodnotu premennej "measurementStopped = true",
    čo spôsobí ukončenie procesu merania, ďalej v cykle "while" merania ...
     */
    public void stopMeasurementThread() {
        measurementStopped = true;
        window.show("Sendding STOP COMMAND!");

    }

    /*
    Funkcia, ktorá vymaže "obrazovku" merania, vypne možnosť "stláčania"
    tlačidiel používateľského rozhrania, ... prechádza plynule do funkcie
    "run()" ...
     */
    public void startThread() {
        window.clean();
        window.show("\nSTART ");
        window.clickEnableFunction(false);
        functionThread = new Thread(this);
        functionThread.start();
    }

    /*
    Funkcia "run()" ... obsahuje algoritmus merania ....
     */
    @Override
    public void run() {

        serial.openSerialPort();
        try {
            serial.serialSend(serial.START_COMMAND);
        } catch (InterruptedException e) {
            window.show("\nCan not send the START command!" + "\n");
        } catch (IOException e) {
            window.show("\nCan not send the START command!" + "\n");
        }

        try {
            if (answear.findAnswear()) {
                window.show("\nARDUINO READY measurement can continue ..." + "\n");
                answear.setDataFromArduino("");
                try {
                    if (window.getID7_Dg() != "") {
                        serial.serialSend(String.valueOf(Integer.parseInt(window.getID7_Dg()) * serial.M_FACTOR_FOR_GAMMA));
                        System.out.println((String.valueOf(Integer.parseInt(window.getID7_Dg()) * serial.M_FACTOR_FOR_GAMMA)));
                    } else {
                        serial.serialSend(String.valueOf(Integer.parseInt(properties.get_Property("ID7_Dg")) * serial.M_FACTOR_FOR_GAMMA));
                    }
                } catch (Exception e) {
                    window.show("\nCan not send the GAMMA MOTOR FACTOR command!" + "\n");
                }
                try {
                    if (window.getID5_Dc() != "") {
                        serial.serialSend(String.valueOf(Integer.parseInt(window.getID5_Dc()) * serial.M_FACTOR_FOR_CPLANE));
                        System.out.println(String.valueOf(Integer.parseInt(window.getID5_Dc()) * serial.M_FACTOR_FOR_CPLANE));

                    } else {
                        serial.serialSend(String.valueOf(Integer.parseInt(properties.get_Property(("ID5_Dc"))) * serial.M_FACTOR_FOR_CPLANE + 1));
                    }
                } catch (Exception e) {
                    window.show("\nCan not send the CPLANE MOTOR FACTOR command!");
                }

                if (window.getIlumQuestion()) {
                    try {
                        serial.serialSend(window.getDistanceValue());
                    } catch (Exception e) {
                        window.show("\nCan not send the DISTANCE VALUE!");
                    }
                }else{
                    try {
                        serial.serialSend(String.valueOf(1));
                    } catch (Exception e) {
                        window.show("\nCan not send the DISTANCE VALUE!");
                    }
                }

                answear.setDataFromArduino("");
            }else {
                window.show("\nARDUINO DID NOT ANSWEAR measurement can NOT continue ...");
                measurementStopped = true;
                window.clickEnableFunction(true);
                answear.setDataFromArduino("");
            }
        } catch (Exception exce) {
            JOptionPane.showMessageDialog(null, "Something went WRONG in communication proces between ARDUINO and PC-JAVA_PROGRAM!");
        }

        try {
            continueMeasureProcess();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void continueMeasureProcess() throws IOException {
        firstValues = new StringBuilder("");
        fullValues = new ArrayList<String>();

        try {
            while (!measurementStopped & !measurementEnded) {
                while (!firstValues.toString().endsWith(serial.SPLIT_CHAR_SEPARATOR) & !measurementEnded & !measurementStopped) {
                    try {
                        firstValues.append(serial.serialRead());
                    } catch (IOException e) {
                        e.printStackTrace();
                    }

                }
                fullValues.addAll(Arrays.asList(firstValues.toString().split(serial.SPLIT_CHAR_SEPARATOR)));
                if (fullValues.get(fullValues.size() - 1).equalsIgnoreCase(serial.END_COMMAND)) {
                    measurementEnded = true;
                }
                window.show("<-------- " + "Sensor value: " + firstValues + "\n");
                firstValues.delete(0, firstValues.length());
            }
        } finally {
            try {
                if (measurementStopped || measurementEnded) {
                    try {
                        serial.serialSend(serial.STOP_COMMAND);
                    } catch (InterruptedException e) {
                        window.show("\nCan not send the STOP command!");
                    } catch (IOException e) {
                        window.show("\nCan not send the STOP command!");
                    }
                    window.clickEnableFunction(true);
                    if (measurementStopped){
                        window.show("\nMeasurement was stopped by User!");
                    }
                    if (measurementEnded){
                        window.show("\nMeasurement ended successfully!");
                    }
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    serial.closeSerialPort();
                }
            } finally {
                try {
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    /*
                    Ak nie je hodnota, získaná v procese merania prázdna,
                    uplatni funkcie, ktoré upravujú hodnoty v doteraz
                    uloženom súbore hodnot svietivosti + separačných
                    znakov ...
                     */
                    if (!fullValues.isEmpty()) {
                        removeEnd(fullValues);
                        System.out.println(fullValues);
                        measurementStaticSetsForResultsWindow = new ArrayList<>();
                        measurementStaticSetsForResultsWindow = createDatabase(fullValues);
                        reverseList(measurementStaticSetsForResultsWindow);
                        window.show("\n\nRaw Data: ");
                        window.show("\n" + measurementStaticSetsForResultsWindow + "\n");
                        window.show( "Total measured values: " + measurementStaticSetsForResultsWindow.size()*measurementStaticSetsForResultsWindow.get(0).size() + "\n");
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public ArrayList<ArrayList<String>> createDatabase(ArrayList<String> rawMeasurement) throws IOException {
        ArrayList<String> separatedCplane = new ArrayList<>();
        ArrayList<String> help;
        ArrayList<ArrayList<String>> luminousMeasurement = new ArrayList<>();

        for (String stringFullValues : rawMeasurement) {

            if (stringFullValues.equalsIgnoreCase(serial.NEW_PLANE)) {
                help = new ArrayList<>();
                help = (ArrayList<String>) separatedCplane.clone();
                luminousMeasurement.add(help);
                separatedCplane.clear();
            }else{
                separatedCplane.add(stringFullValues);
            }
        }
        return luminousMeasurement;
    }

    /*
    List hodnôt, ktoré boli získané v opačnej C-rovine, je
    nutné obrátiť .... na to slúži nasledujúca funkcia ...
    Každý nepárna list (nepárny podľa indexu) je vyselektovaný,
    a obrátený ...
     */
    public void reverseList(ArrayList<ArrayList<String>> cPlaneSets){
        int counter = 0;
        for (ArrayList<String> s: cPlaneSets) {

            if (counter % 2 != 0){
                Collections.reverse(s);
            }
            counter++;
        }
    }

    /*
    Posledná hodnota, v nameranom súbore hodnôt, obsahuje separačný znak,
    tento je nepotrebný, a nežiadúci, a preto je prostredníctvom funkcie
    "removeEnd" so súbora hodnlt odstránený ...
     */
    public ArrayList<String> removeEnd(ArrayList<String> list) {
        if (list.size() != 0){
            list.remove(list.size() - 1);
        }
        return list;
    }

    /*
    Funkcia vracajúca súbor s nameranými hodnotami. Tieto hodnoty sa
    prenášajú do tried "TableWindow" a "GraphsWindow" ...
     */
    public static ArrayList<ArrayList<String>> getMeasurementStaticSetsForResultsWindow(){
        return  measurementStaticSetsForResultsWindow;
    }
}
