package com.example.schedulerapp;

import java.io.*;
import java.net.*;

/*
    Class Name: ReceiveThread
    Description: This class handles messages sent from the server, and the required parsing to be used for in the Model class.
 */
public class ReceiveThread extends Thread {
    private BufferedReader reader;
    private final Model client;

    /*
    Name: ReceiveThread
    Parameters:
        Socket socket: socket for communicating to the server.
        Model client: class that contains the employee and shift hashmaps.
    Description: Constructor class that gets the input stream to be read when server messages are sent.
    Return: ReceiveThread
     */
    public ReceiveThread(Socket socket, Model client) {
        this.client = client;

        try {
            InputStream input = socket.getInputStream();
            reader = new BufferedReader(new InputStreamReader(input));
        } catch (IOException exception) {
            System.out.println("Error getting input stream: " + exception.getMessage());
            exception.printStackTrace();
        }
    }

    /*
    Name: Run
    Parameters: none
    Description: Responsible for handling and parsing messages from the server.
    Return: void
     */
    public void run() {
        while(true) {
            try {
                String response = reader.readLine(); // Waits for messages from the server.
                String[] args = response.split("/");
                switch (args[0]) {
                    case "allEmployees" -> allEmployees(args);
                    case "allShifts" -> allShifts(args);
                    case "addEmployee" -> addEmployee(args[1]);
                    case "removeEmployee" -> removeEmployee(args[1]);
                    case "addShift" -> addShift(args[1]);
                    case "removeShift" -> removeShiftByID(args[1]);
                    case "editShift" -> editShift(args[1]); // fix
                }

            } catch (IOException exception) {
                System.out.println("Dropped connection from server: " + exception.getMessage());
                exception.printStackTrace();
                break;
            }

        }
    }

    /*
    Name: allEmployees
    Parameters:
        String[] allEmployees: All employee information sent from server. Employee fields are is separated by a '.'
        delimiter.
    Description: Separates all employees and adds them to the local employee HashMap by their ID.
    Return: void
     */
    private void allEmployees(String[] allEmployees) {
        for (String employee : allEmployees) {
            if (!employee.equals("allEmployees")){
               addEmployee(employee);
            }
        }
    }

    /*
    Name: addEmployee
    Parameters:
        String employeeData: All the information for a given employee separated by '.'
    Description: Adds an employee to the local employee HashMap by their ID.
    Return: void
     */
    private void addEmployee(String employeeData) {
        try {
            String[] dataSplit = employeeData.split("\\.");
            this.client.employees.put(Integer.parseInt(dataSplit[0]), new Employee(employeeData));
        } catch (Exception exception) {
            exception.printStackTrace();
        }
    }

    /*
    Name: RemoveEmployee
    Parameters:
        String employeeID: The employeeID of the employee.
    Description: Removes an employee from the employee HashMap by there employee ID.
    Return: void
     */
    private void removeEmployee(String employeeID) {
        try {
            int intID = Integer.parseInt(employeeID);
            this.client.employees.remove(intID);
            for (Shift shift : this.client.shifts.values()) {
                if (shift.getEmployeeID() == intID) {
                    this.client.shifts.remove(shift.getShiftID());
                }
            }
        } catch (Exception exception) {
            exception.printStackTrace();
        }
    }

    /*
    Name: allShifts
    Parameters:
        String[] allShifts: All the shifts to be added locally from the server in the form String[].
    Description: Adds all the shifts to the local shift hashmap by the shift id.
    Return: void
     */
    private void allShifts(String[] allShifts) {
        for (String shift : allShifts) {
            if (!shift.equals("allShifts")){
                addShift(shift);
            }
        }
    }

    /*
    Name: addShift
    Parameters:
        String shiftData: a string containing shift data from the server
    Description: Adds a shift to the local shift Hashmap by shift ID.
    Return: void
     */
    private void addShift(String shiftData) {
        try {
            String[] dataSplit = shiftData.split("\\.");
            this.client.shifts.put(Integer.parseInt(dataSplit[4]), new Shift(shiftData));
        } catch (Exception exception) {
            exception.printStackTrace();
        }
    }

    /*
    Name: removeShiftByID
    Parameters:
        String id: The shift id of an existing shift.
    Description: Removes a shift from the local shift HashMap.
    Return: void
     */
    private void removeShiftByID(String id) {
        try {
            this.client.shifts.remove(Integer.parseInt(id));
        } catch (Exception exception) {
            exception.printStackTrace();
        }
    }

    /*
    Name: editShift
    Parameters:
        String editedShift: The information of the editedShift from the server.
    Description: Edits an existing shift.
    Return: void
     */
    private void editShift(String editedShift) {
        String[] shiftSplit = editedShift.split("\\.");
        try {
            Integer.parseInt(shiftSplit[4]);
            removeShiftByID(shiftSplit[4]);
            addShift(editedShift);
        } catch (Exception exception) {
            exception.printStackTrace();
        }
    }

}