/*
 * Copyright (C) 2021 berdan
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package client;

import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import utils.Message;
import javax.swing.JTextField;
import javax.swing.JButton;
import javax.swing.JTextArea;
import java.awt.Color;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.net.SocketException;
import java.util.Scanner;
import java.awt.event.ActionEvent;

/**
 * Hauptklasse des Clients
 *
 * @version 0.1.3
 * @author berdan
 */

public class Client1 extends JFrame {

    /**
     * Hier werden Objekte und Variablen deklariert, damit diese in allen
     * Methoden genutzt werden können.
     */
    private static JPanel contentPane;
    private static JTextField txtMessage;
    private static JTextField txtUsername;
    private static String currentText = " ";
    private static int i = 0;
    private static Object tosend = new Message("Leer", "Leer");
    private static Client1 t1;
    private static Socket socket;
    private static ObjectInputStream obinstr;
    private static ObjectOutputStream oboust;
    private static boolean verbunden = false;
    private static JTextArea textArea = new JTextArea();
    private static int anzahlVersuche = 0; //Ist gleich die AN
    private static int anzahlRekursionen = 0;
    private static Message temp = new Message("leer", "leer");
    private static User user;
    
    /**
     * In der main Methode wird das GUI erstellt und die start() Methode
     * aufgerufen.
     * 
     * @param args Standard Main-Methode
     * @throws InterruptedException Wirft die Exception
     */
    public static void main(String[] args) throws InterruptedException {
        t1 = new Client1();
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    Client1 frame = new Client1();
                    frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });

        try {
            start();
        } catch (ClassNotFoundException | IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * In der Methode Client1() wird das GUI und die Befehle die durch einen
     * Click des Button's ausgelöst werden festgelegt (Konstruktur)
     */

    public Client1() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(100, 100, 450, 300);
        contentPane = new JPanel();
        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
        setContentPane(contentPane);
        contentPane.setLayout(null);

        txtMessage = new JTextField();
        txtMessage.setText("Message");
        txtMessage.setBounds(20, 230, 218, 20);
        contentPane.add(txtMessage);
        txtMessage.setColumns(10);

        txtUsername = new JTextField();
        txtUsername.setText("Username");
        txtUsername.setBounds(20, 11, 86, 20);
        contentPane.add(txtUsername);
        txtUsername.setColumns(10);
        
        
        /**
         * Der Start Button sorgt sorgt dafür, dass der Username festgesetzt
         * wird, wodurch er nicht veränderlich ist. Außerdem wird die globale
         * Variabel j von 0 auf 1 gestzt, wodurch die start-Methode weiß, dass
         * sie eine Verbindung aufbauen soll.
         */
        
        JButton btnStart = new JButton("Start");
        btnStart.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                
                /**
                 * Hier wird ein User-Objekt hergestellt
                 */
                
                String name = txtUsername.getText();
                String nachricht = txtMessage.getText();
                
                user = new User(name, nachricht);

                txtUsername.setEditable(false);
                txtUsername.setEnabled(false);
                verbunden = true;

            }
        });
        btnStart.setBounds(116, 10, 89, 23);
        contentPane.add(btnStart);
        

        /**
         * Der Button "Send" nimmt die aktuelle Nachricht, welche im Textfeld
         * "message" geschrieben wurde und schreibt diese als ein Message-Objekt
         * in den Output-Stream an den Server, falls die Socket bereits
         * verbunden ist.
         *
         * Falls die Nachricht "exit" sein sollte, wird die GUI beendet.
         */
        JButton btnSend = new JButton("Send");
        btnSend.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {

                if (verbunden) {

                    String themessage = txtMessage.getText();
                    //String theusername = user.getUsername();

                    tosend = new Message(user.getUsername(), themessage);
                    i = 1;

                    temp = new Message(user.getUsername(), themessage);
                    
                    System.out.println("Button pressed");

                    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

                    try {
                        oboust.writeObject(tosend);
                        oboust.flush();
                    } catch (IOException e) {
                        e.printStackTrace();
                    } catch (Exception k) {
                        print("KEINE VERBINDUNG");
                    }
                    
                    user.setMessage(themessage);

                    if (temp.getMessage().equals("exit")) {
                        System.exit(0);
                    }
                    txtMessage.setText("");
                    

                    
                }

            }
        });

        btnSend.setBounds(264, 229, 79, 23);
        contentPane.add(btnSend);

        /**
         * Hier wird die textArea, auf welcher der Text ausgegeben wird
         * initialisiert
         */
        textArea = new JTextArea(currentText);
        textArea.setLineWrap(true);
        textArea.setForeground(Color.BLACK);
        textArea.setBackground(Color.LIGHT_GRAY);
        textArea.setBounds(20, 42, 323, 176);
        contentPane.add(textArea);



    }

    /**
     * In der Print-Methode wird der neue Text (also eine neue Nachricht) auf
     * die textArea abgebildet.
     * 
     * @param neuerText Text als String, wird auf textArea abgebildet
     */
    public static void print(String neuerText) {
        currentText = neuerText + "\n" + currentText;

        textArea.setText(currentText);
    }

    /**
     * Die start-Methode wartet, bis die Variable verbunden durch Klicken des
     * Start Buttons auf true gesetzt wird, erst dann beginnt die eigentliche
     * Methode.
     *
     * Es wird dann eine Verbindung zum Socket über den Port 1236 aufgebaut.
     * Sollte dies nicht Möglich sein, wird die Fehlermeldung in der GUI
     * ausgegeben, sodass der Nutzer weiß, dass keine Vebrindung möglich ist.
     *
     * Es wird im Sekundentakt nach einer neuen Verbindung gesucht.
     *
     * @throws IOException Wirft die Exception
     * @throws ClassNotFoundException Wirft die Exception
     * @throws InterruptedException Wirft die Exception
     */
    public static void start() throws IOException, ClassNotFoundException, InterruptedException {

        while (!verbunden) {
            Thread.sleep(100);
        }

        txtUsername.setEnabled(false);
        Scanner scan = new Scanner(System.in);

        try {
            socket = new Socket("localhost", 1236);
            oboust = new ObjectOutputStream(socket.getOutputStream());
            obinstr = new ObjectInputStream(socket.getInputStream());
            print("VERBINDUNG HERGESTELLT");
        } catch (Exception KeineSocket) {
            print("SERVER ANTWORTET NICHT");
           
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            
            anzahlRekursionen++;
            if (anzahlRekursionen == 10) {
                print("KEINE ANTWORT, CLIENT WIRD BEENDET");
                Thread.sleep(10000);
                System.exit(0);
            }
            start();
            System.exit(0);

        }

        Object erhalten = null;
        Message message = new Message("leer", "leer");

        /**
         * Die While Schleife ist der Listener, dieser wartet auf Nachrichten
         * aus dem Server und gibt diese dann aus.
         *
         * Im Falle eines Verindungsabbruches versucht er es 5 mal im Abstand
         * von 2 Sekunden nochmal eine Nachricht zu senden und ruft dann wieder
         * die start() Methode auf. wodurch die Verbindung nochmal neu
         * hergestellt wird.
         *
         * Die While-Schleife wird abgebrochen, sobald die Nachricht, welche der
         * Benutzer über das GUI sendet "exit" lautet.
         *
         */
        
        while (!temp.getMessage().equals("exit")) {
            try {
                //System.out.println("hile4");
                System.out.println("Nachricht erhalten");
                erhalten = obinstr.readObject(); //Bleibt hier stehen, bis ein neues Object reinkommt

                message = (Message) erhalten;
                System.out.println("[" + message.getUsername() + "]  " + message.getMessage());
                String Ausgeben = message.getTime() + " [" + message.getUsername() + "]  " + message.getMessage();
                print(Ausgeben);
                //System.out.println("[CLIENT] NACHRICHT ERHALTEN");

                oboust.flush();

            } catch (SocketException h) {
                System.out.println(h);
                print("VERBINDUNGSABBRUCH");
                anzahlVersuche++;

                Thread.sleep(2000);

                if (anzahlVersuche == 5) {
                    anzahlVersuche = 0;
                    anzahlRekursionen++;

                    if (anzahlRekursionen == 10) {
                        print("KEINE ANTWORT, CLIENT WIRD BEENDET");
                        Thread.sleep(10000);
                        System.exit(0);

                    }

                    start();
                    System.exit(0);
                }

            } catch (Exception f) {
                Thread.sleep(1000);
            }

        }

        /**
         * Nach dem Abbruch der While Schleife, was nur bei der Nachricht exit
         * passiert, schließt der Client den ObjectOutputstream,
         * Objectinputstream und den Socket und beendet dann das Programm
         */
        oboust.close();
        obinstr.close();
        socket.close();

        System.exit(0);

    }
}
