package bp;

import java.awt.Color;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.DefaultListModel;

/**
 *
 * @author František Flachs
 */
public class Functions {

    MainGUI window = null;

    private String loggedUserId = "";
    public String loggedUserName = "";
    private ArrayList<Conf> loadedConfs;

    // DB setting
    private final String ip = "172.0.0.1";
    private final String port = "3306";
    private final String dnName = "bp-flachfra-2018";
    private final String userName = "flachfra";
    private final String password = "123456";

    // last conf id which is stored in the DB
    private int lastConfId = 0;

    // state of the network device
    private boolean deviceWakedUp = false;

    // setup for serial communication with the network device
    private int baudRate = 0;
    private int dataBits = 0;
    private int stopBits = 0;
    private int parity = 0;

    // constants
    private static final int BAUDRATE_110 = 110;
    private static final int BAUDRATE_300 = 300;
    private static final int BAUDRATE_600 = 600;
    private static final int BAUDRATE_1200 = 1200;
    private static final int BAUDRATE_4800 = 4800;
    private static final int BAUDRATE_9600 = 9600;
    private static final int BAUDRATE_14400 = 14400;
    private static final int BAUDRATE_19200 = 19200;
    private static final int BAUDRATE_38400 = 38400;
    private static final int BAUDRATE_57600 = 57600;
    private static final int BAUDRATE_115200 = 115200;
    private static final int BAUDRATE_128000 = 128000;
    private static final int BAUDRATE_256000 = 256000;

    private static final int DATABITS_5 = 5;
    private static final int DATABITS_6 = 6;
    private static final int DATABITS_7 = 7;
    private static final int DATABITS_8 = 8;

    private static final int STOPBITS_1 = 1;
    private static final int STOPBITS_2 = 2;
    private static final int STOPBITS_1_5 = 3;

    private static final int PARITY_NONE = 0;
    private static final int PARITY_ODD = 1;
    private static final int PARITY_EVEN = 2;
    private static final int PARITY_MARK = 3;
    private static final int PARITY_SPACE = 4;

    /**
     *
     * @param window
     */
    Functions(MainGUI window) {
        this.loadedConfs = new ArrayList<Conf>();
        this.window = window;
    }

    /**
     * This functions enebales/disables parts of main GUI.
     */
    public void toggleControls() {

        // user connected & port connected & device waked up
        if (!loggedUserId.equals("") & window.communicator.getConnected() == true & deviceWakedUp == true) {
            window.btnUploadToDevice.setEnabled(true);
            window.btnBackUpToServer.setEnabled(true);
            window.txtConfName.setEnabled(true);
            window.btnShowRunConf.setEnabled(true);
            window.btnShowMore.setEnabled(true);
            window.btnCtrlZ.setEnabled(true);
            window.btnSendCommand.setEnabled(true);
            window.txtCommand1.setEnabled(true);
            window.txtConfName.setEnabled(true);

            // com port connected && device waked up
        } else if (window.communicator.getConnected() == true & deviceWakedUp == true) {
            window.btnShowRunConf.setEnabled(true);
            window.btnShowMore.setEnabled(true);
            window.btnCtrlZ.setEnabled(true);
            window.btnSendCommand.setEnabled(true);
            window.txtCommand1.setEnabled(true);
            window.btnBackUpToServer.setEnabled(false);
            window.btnUploadToDevice.setEnabled(false);
            window.txtConfName.setEnabled(false);

            // com port connected       
        } else if (window.communicator.getConnected() == true) {
            window.btnDisconnect.setEnabled(true);
            window.btnRefresh.setEnabled(false);
            window.btnConnect.setEnabled(false);
            window.btnWakeUp.setEnabled(true);
            window.btnUpdateListConfigs.setEnabled(true);
            window.btnShowConfig.setEnabled(true);
            window.btnBackUpToServer.setEnabled(false);
            window.btnUploadToDevice.setEnabled(false);

            window.txtConfName.setEnabled(false);
            window.lstConfs.setEnabled(true);

            window.cboxPorts.setEnabled(false);
            window.cboxBaudRate.setEnabled(false);
            window.cboxDataBits.setEnabled(false);
            window.cboxStopBits.setEnabled(false);
            window.cboxParity.setEnabled(false);
        } else {
            window.btnShowRunConf.setEnabled(false);
            window.btnShowMore.setEnabled(false);
            window.btnCtrlZ.setEnabled(false);
            window.btnSendCommand.setEnabled(false);
            window.btnWakeUp.setEnabled(false);
            window.btnUpdateListConfigs.setEnabled(false);
            window.btnShowConfig.setEnabled(false);
            window.btnDisconnect.setEnabled(false);
            window.btnRefresh.setEnabled(true);
            window.btnConnect.setEnabled(true);
            window.btnUploadToDevice.setEnabled(false);
            window.btnBackUpToServer.setEnabled(false);

            window.txtConfName.setEnabled(false);
            window.txtCommand1.setEnabled(false);
            window.lstConfs.setEnabled(false);

            window.cboxPorts.setEnabled(true);
            window.cboxBaudRate.setEnabled(true);
            window.cboxDataBits.setEnabled(true);
            window.cboxStopBits.setEnabled(true);
            window.cboxParity.setEnabled(true);
        }

        // user not connected
        if (loggedUserId.equals("")) {
            window.btnLogout.setEnabled(false);
            window.btnLogin.setEnabled(true);
            window.btnReset.setEnabled(true);
            window.btnUpdateListConfigs.setEnabled(false);
            window.btnShowConfig.setEnabled(false);

            window.lstConfs.setEnabled(false);
            window.txtEmail.setEnabled(true);
            window.txtPassword.setEnabled(true);

            // user connected
        } else {
            window.btnLogout.setEnabled(true);
            window.btnLogin.setEnabled(false);
            window.btnReset.setEnabled(false);
            window.btnUpdateListConfigs.setEnabled(true);
            window.btnShowConfig.setEnabled(true);

            window.lstConfs.setEnabled(true);

            window.txtEmail.setEnabled(false);

            window.txtPassword.setEnabled(false);
            window.txtPassword.setText("");
            window.txtEmail.setText("");
        }
    }

    /**
     * Initialization of Cboxes for setup serial communication with network
     * device.
     */
    public void initCboxes() {
        window.cboxBaudRate.addItem(BAUDRATE_110);
        window.cboxBaudRate.addItem(BAUDRATE_300);
        window.cboxBaudRate.addItem(BAUDRATE_600);
        window.cboxBaudRate.addItem(BAUDRATE_1200);
        window.cboxBaudRate.addItem(BAUDRATE_4800);
        window.cboxBaudRate.addItem(BAUDRATE_9600);
        window.cboxBaudRate.addItem(BAUDRATE_14400);
        window.cboxBaudRate.addItem(BAUDRATE_19200);
        window.cboxBaudRate.addItem(BAUDRATE_38400);
        window.cboxBaudRate.addItem(BAUDRATE_57600);
        window.cboxBaudRate.addItem(BAUDRATE_115200);
        window.cboxBaudRate.addItem(BAUDRATE_128000);
        window.cboxBaudRate.addItem(BAUDRATE_256000);
        window.cboxBaudRate.setSelectedItem(BAUDRATE_9600);

        window.cboxDataBits.addItem(DATABITS_5);
        window.cboxDataBits.addItem(DATABITS_6);
        window.cboxDataBits.addItem(DATABITS_7);
        window.cboxDataBits.addItem(DATABITS_8);
        window.cboxDataBits.setSelectedItem(DATABITS_8);

        window.cboxStopBits.addItem(STOPBITS_1);
        window.cboxStopBits.addItem(STOPBITS_2);
        window.cboxStopBits.addItem(STOPBITS_1_5);
        window.cboxStopBits.setSelectedItem(STOPBITS_1);

        window.cboxParity.addItem(PARITY_NONE);
        window.cboxParity.addItem(PARITY_ODD);
        window.cboxParity.addItem(PARITY_EVEN);
        window.cboxParity.addItem(PARITY_MARK);
        window.cboxParity.addItem(PARITY_SPACE);
        window.cboxParity.setSelectedItem(PARITY_NONE);

    }

    /**
     * Loading parameters from actual selection of cboxem fo init serial
     * communication.
     */
    public void loadPortParams() {
        baudRate = (int) window.cboxBaudRate.getSelectedItem();
        dataBits = (int) window.cboxDataBits.getSelectedItem();
        stopBits = (int) window.cboxStopBits.getSelectedItem();
        parity = (int) window.cboxParity.getSelectedItem();

    }

    /**
     *
     * @param email - user email
     * @param password - user password
     * @return true if email and password inserted to the fiels is known and
     * correct by database - users table.
     */
    public boolean validate_login(String email, String password) {

        ResultSet resultSet;

        Connection connection = null;
        Statement statement = null;

        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            System.out.println("Unable to load Driver");
        }

        try {
            connection
                    = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/bp-flachfra-2018", "flachfra", "123456");
        } catch (SQLException e) {
            System.out.println("Unable to connect to database");
        }

        if (connection != null) {
            try {
                statement = connection.createStatement();
            } catch (SQLException e) {
                System.out.println("Unable to create statement" + e);
            }
        }

        if (statement != null) {
            try {

                String sql = "SELECT id, name, password FROM users WHERE email=?";

                PreparedStatement preparedStmt = connection.prepareStatement(sql);
                if (preparedStmt == null) {
                    System.out.println("null");
                }

                preparedStmt.setString(1, email);

                resultSet = preparedStmt.executeQuery();

                if (resultSet != null) {
                    try {
                        while (resultSet.next()) {

                            if (Password.testPassword(password, resultSet.getString(3))) {
                                loggedUserId = resultSet.getString(1);
                                loggedUserName = resultSet.getString(2);
                                return true;
                            } else {
                                return false;
                            }
                        }
                    } catch (SQLException e) {
                        System.out.println("Unable to iterate over resultset" + e);
                    }
                }
                connection.close();

            } catch (SQLException e) {
                System.out.println("Unable to create statement2");
            }

        }

        return false;

    }

    /**
     * Getting last conf id in the database.
     */
    public void getLastConfId() {

        Connection connection = null;
        Statement statement = null;
        ResultSet resultSet = null;

        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            System.out.println("Unable to load Driver");
        }

        try {
            connection
                    = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/bp-flachfra-2018", "flachfra", "123456");
        } catch (SQLException e) {
            System.out.println("Unable to connect to database");
        }

        if (connection != null) {
            try {
                statement = connection.createStatement();
            } catch (SQLException e) {
                System.out.println("Unable to create statement");
            }
        }

        if (statement != null) {
            try {
                resultSet = statement.executeQuery("SELECT * FROM confs");
            } catch (SQLException e) {
                System.out.println("Unable to create statement");
            }
        }

        //if resultset is receive get values
        if (resultSet != null) {
            try {
                while (resultSet.next()) {
                    System.out.println("Value in 1st column " + resultSet.getString(1));
                    lastConfId = Integer.valueOf(resultSet.getString(1));
                    System.out.println("++" + lastConfId);
                }
            } catch (SQLException e) {
                System.out.println("Unable to iterate over resultset");
            }
        }

        try {
            resultSet.close();
            statement.close();
            connection.close();
        } catch (SQLException e) {
            System.out.println("Can not close socket" + e);
        }
    }

    /**
     * Inserting new configuration to the database on the lastConfId++ place.
     *
     * @param conf_body - configuration body
     */
    public void insertConfToDatabase(String conf_body) {

        Connection connection = null;
        Statement statement = null;
        boolean resultSet = false;

        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            System.out.println("Unable to load Driver");
        }

        try {
            connection
                    = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/bp-flachfra-2018", "flachfra", "123456");
        } catch (SQLException e) {
            System.out.println("Unable to connect to database");
        }

        if (connection != null) {
            try {
                statement = connection.createStatement();
            } catch (SQLException e) {
                System.out.println("Unable to create statement");
            }
        }

        if (statement != null) {
            try {

                Calendar calendar = Calendar.getInstance();
                java.sql.Date startDate = new java.sql.Date(calendar.getTime().getTime());

                String sql = "INSERT INTO confs"
                        + "(id, title, body, created_at, updated_at, user_id, conf_body)"
                        + "VALUES (?, ?, ?, ?, ?, ?, ?)";

                PreparedStatement preparedStmt = connection.prepareStatement(sql);
                if (preparedStmt == null) {
                    System.out.println("null");
                }

                preparedStmt.setInt(1, lastConfId + 1);
                preparedStmt.setString(2, window.txtConfName.getText());
                preparedStmt.setString(3, conf_body);
                preparedStmt.setDate(4, startDate);
                preparedStmt.setDate(5, startDate);
                preparedStmt.setInt(6, Integer.valueOf(loggedUserId));
                preparedStmt.setString(7, "noconf.text");

                resultSet = preparedStmt.execute();

                connection.close();

            } catch (SQLException e) {
                System.out.println("Unable to create statement2");
            }
        }

        if (resultSet != false) {
            System.out.println("Writing ok.");
        }

        try {
            statement.close();
            connection.close();
        } catch (SQLException e) {
            System.out.println("Can not close socket" + e);
        }
    }

    /**
     * Loading all user configurations.
     */
    public void loadConfs() {
        ResultSet resultSet;

        Connection connection = null;
        Statement statement = null;

        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            System.out.println("Unable to load Driver");
        }

        try {
            connection
                    = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/bp-flachfra-2018", "flachfra", "123456");
        } catch (SQLException e) {
            System.out.println("Unable to connect to database");
        }

        if (connection != null) {
            try {
                statement = connection.createStatement();
            } catch (SQLException e) {
                System.out.println("Unable to create statement");
            }
        }

        if (statement != null) {
            try {

                String sql = "SELECT title, body FROM confs WHERE user_id=?";

                PreparedStatement preparedStmt = connection.prepareStatement(sql);
                if (preparedStmt == null) {
                    System.out.println("null");
                }

                preparedStmt.setString(1, loggedUserId);

                resultSet = preparedStmt.executeQuery();

                if (resultSet != null) {
                    try {
                        Conf c;
                        loadedConfs.clear();
                        while (resultSet.next()) {
                            c = new Conf(resultSet.getString(1), resultSet.getString(2));
                            loadedConfs.add(c);
                        }
                    } catch (SQLException e) {
                        System.out.println("Unable to iterate over resultset");
                    }
                }

                connection.close();
                updateLoadedConfs(loadedConfs);

            } catch (SQLException e) {
                System.out.println("Unable to create statement2" + e);
            }

        }

    }

    /**
     * Updating user configurations depends on the downloaded list from the DB.
     *
     * @param loadedConfs - set of loaded configuration 
    */
    public void updateLoadedConfs(ArrayList<Conf> loadedConfs) {

        DefaultListModel<String> dlm = new DefaultListModel<>();

        for (int i = 0; i < loadedConfs.size(); i++) {

            dlm.addElement(loadedConfs.get(i).getTitle());

        }

        window.lstConfs.setModel(dlm);

    }

    /**
     * Logout user and change toogleControls.
     */
    public void logoutUser() {

        displayData("", Color.BLACK, 'n', "User " + loggedUserName + " was successfully disconected.", Color.BLACK);

        loadedConfs.clear();
        updateLoadedConfs(loadedConfs);

        loggedUserId = "";
        loggedUserName = "";

        deviceWakedUp = false;
        toggleControls();

    }

    /**
     * Modifying received msg from the network device.
     *
     * @return - modifyend msg withou spaces
     */
    public String modifyReceivedMsg() {
        String s = removeSpaces(window.communicator.getReceivedMsg());
        int indexStart = s.indexOf("version");
        int indexEnd = IndexOfNth(s, "end", 2);

        s = s.substring(indexStart, indexEnd + 3);
        window.txtMainLog.setText(s);

        return s;
    }

    /**
     * Modifying msg for properly display ind the gui.
     *
     * @param msg - received msg from network devica via serial communication
     * port.
     * @return modyfied msg
     */
    public String removeSpaces(String msg) {
        String s = msg;
        String s1;
        String s2;
        int indexStart = -1;
        int indexEnd = -1;

        while (true) {
            indexStart = s.indexOf("--More--");
            indexEnd = s.");

            if (indexStart != -1 && indexEnd != -1) {
                s1 = s.substring(0, indexStart - 1);
                s2 = s.substring(indexEnd + 27, s.length());
                s = s1 + s2;
                System.out.println("s1 -> " + s1);
                System.out.println("s2 -> " + s2);
                indexStart = -1;
                indexEnd = -1;
                continue;
            }

            if (indexStart == -1) {
                break;
            }
        }

        return s;

    }

    /**
     *
     * @param string - main string to find in
     * @param substring - finding substring
     * @param nth - count of the finding.
     * @return index of substring
     */
    public int IndexOfNth(String string, String substring, int nth) {
        if (nth <= 0) {
            System.out.println("Error index.");
        }
        int index = string.indexOf(substring);
        for (int i = 1; i < nth; i++) {
            if (index == -1) {
                return -1;
            }
            index = string.indexOf(substring, index + 1);
        }
        return index;
    }

    /**
     * Disply data and activity for user control.
     *
     * @param mainLog - mani log with all detailed msgs
     * @param colorMainLog - color of the font in the field
     * @param addType - 'a' = append, 'w' = write
     */
    public void displayData(String mainLog, Color colorMainLog, char addType) {
        if (!mainLog.contains(")) {
            window.txtMainLog.setForeground(colorMainLog);

            if (addType == 'a') {
                window.txtMainLog.append(mainLog);
            } else if (addType == 'w') {
                window.txtMainLog.setText(mainLog);
            }

            System.out.print(mainLog);
        }

    }

    /**
     * Disply data and activity for user control.
     *
     * @param mainLog - mani log with all detailed msgs
     * @param colorMainLog - color of the font in the field
     * @param addType - 'a' = append, 'w' = write
     * @param log - log to the activity box
     * @param colorLog - color of the font in the field
     */
    public void displayData(String mainLog, Color colorMainLog, char addType, String log, Color colorLog) {
        if (!mainLog.contains(")) {
            switch (addType) {
                // nothing to do with MainLog
                case 'n':
                    break;
                case 'a':
                    window.txtMainLog.append(mainLog);
                    break;
                case 'w':
                    window.txtMainLog.setText(mainLog);
                    break;
                default:
                    break;
            }

            window.txtLog.setForeground(colorLog);
            window.txtLog.append(log + "\n");
        }
    }

    /**
     * Getting the state of the device.
     *
     * @return bool if is device waked up
     */
    public boolean getDeviceWakedUp() {
        return deviceWakedUp;
    }

    /**
     * Setting the state of the device.
     *
     * @param deviceWakedUp - true if device is waked up
     */
    public void setDeviceWakedUp(boolean deviceWakedUp) {
        this.deviceWakedUp = deviceWakedUp;
    }

    /**
     * Getting logged used id
     *
     * @return - logged user id
     */
    public String getLoggedUserId() {
        return loggedUserId;
    }

    /**
     * Getting the name of the logged user
     *
     * @return - return name of the logged user
     */
    public String getLoggedUserName() {
        return loggedUserName;
    }

    /**
     * Getting set of the loaded configurations depends on the logged user.
     *
     * @return - retunr set of configurations.
     */
    public ArrayList<Conf> getLoadedConfs() {
        return loadedConfs;
    }

    /**
     * Getting set baudrate
     *
     * @return baudrate
     */
    public int getBaudRate() {
        return baudRate;
    }

    /**
     * Getting set data bits
     *
     * @return data bits
     */
    public int getDataBits() {
        return dataBits;
    }

    /**
     * Getting set stop bits
     *
     * @return stop bits
     */
    public int getStopBits() {
        return stopBits;
    }

    /**
     * Getting set parity
     *
     * @return parity
     */
    public int getParity() {
        return parity;
    }

}
