package com.example.schedulerapp; import java.net.*; import java.io.*; import java.time.LocalDate; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeUnit; public class Model { private PrintWriter writer; private Socket socket; protected Map<Integer, Shift> shifts; protected Map<Integer, Employee> employees; protected Map<Integer, TimeOff> timeOff; protected Map<String, Float> positions; protected ArrayList<ModelSubscriber> subscribers; static LocalDate date; private boolean isManager; private int thisEmployee; private int selectedEmployee; public Model(String hostname, int port) { subscribers = new ArrayList<>(); if(date == null) { date = LocalDate.now(); } isManager = false; // changes if manager logs in this.shifts = new HashMap<>(); this.employees = new HashMap<>(); this.timeOff = new HashMap<>(); this.positions = new HashMap<>(); try { InetAddress ip = InetAddress.getByName(hostname); this.socket = new Socket(ip, port); System.out.println("Connected to the scheduling server"); new ReceiveThread(this.socket, this).start(); OutputStream output = this.socket.getOutputStream(); this.writer = new PrintWriter(output, true); } catch (UnknownHostException error) { System.out.println("Server not found: " + error.getMessage()); } catch (IOException error) { System.out.println("I/O Error: " + error.getMessage()); } } public void setIsManager(boolean aBool){ isManager = aBool; } public boolean getIsManager(){ return isManager; } public void setThisEmployee(int id){ thisEmployee = selectedEmployee = id; } public int getThisEmployee(){ return thisEmployee; } //for manager only, allows viewing of weekly schedule by employee public void setSelectedEmployee(int id){ selectedEmployee = id; notifySubscribers(); } public int getSelectedEmployee(){ return selectedEmployee; } public void dateNext(){ date = date.plusDays(1); notifySubscribers(); } public void weekNext(){ date = date.plusDays(7); notifySubscribers(); } public void datePrev(){ date = date.minusDays(1); notifySubscribers(); } public void weekPrev(){ date = date.minusDays(7); notifySubscribers(); } //todo: add calender to fill jump field public void dateJump(LocalDate date){ //this.date = date; notifySubscribers(); } // Have this just in case we need it. void updateAllShifts(){ writer.println("allShifts"); } // Have this just in case we need it. void updateAllEmployees(){ writer.println("allEmployees"); } void addEmployee(String firstName, String lastName) { writer.println("addEmployee/" + firstName + "/" + lastName + "/" + false + "/" + "empty" + "/" + "empty" + "/" + 0.0f); updateAllEmployees(); } void addEmployee(String firstName, String lastName, boolean isManager, String email, String phoneNumber, float wage) { writer.println("addEmployee/" + firstName + "/" + lastName + "/" + isManager + "/" + email + "/" + phoneNumber + "/" + wage); } void removeEmployee(String employeeID) { writer.println("removeEmployee/" + employeeID); updateAllEmployees(); } Employee getEmployee(int employeeID) { return employees.get(employeeID); } /* Sorry if this breaks anything. */ void printAllEmployees(){ ArrayList<String> employeeList = new ArrayList<>(); for (Employee employee : this.employees.values()) { employeeList.add(employee.getFullName()); } System.out.println(employeeList); } int employeeSize(){ return this.employees.size(); } String getEmployeeByID(int id) { if (!this.employees.isEmpty()) { Employee employee = this.employees.get(id); if (employee != null) { return employee.getFullName(); } return "No Employee with that ID"; } return "No Employees"; } //This sends " " as the position. void addShift(int id, String date, int start, int end){ writer.println("addShift/"+id+"/"+date+"/"+start+"/"+end+"/"+" "); notifySubscribers(); } // void addShift(int id, String date, int start, int end, String position){ writer.println("addShift/"+id+"/"+date+"/"+start+"/"+end+"/"+position); notifySubscribers(); } void removeShift(int shiftID){ writer.println("removeShift/"+shiftID); notifySubscribers(); } void editShift(int shiftID, String day, int start, int end, Boolean availability, int employeeID) { writer.println("editShift/"+shiftID+"/"+day+"/"+start+"/"+end+"/"+availability+"/"+employeeID); notifySubscribers(); } Shift getShift(int shiftID) { return this.shifts.get(shiftID); } void printAllShifts() { System.out.println(this.shifts); } /* Parameters: - String date in format 2022-03-10. Return: ArrayList<String> where each string is a shift of format id.yyyy-mm-dd.start.end */ ArrayList<Shift> getShiftsByDay(String date){ ArrayList<Shift> shifts = new ArrayList<>(); for (Shift shift : this.shifts.values()) { if (shift.getDate().equals(date)) { shifts.add(shift); } } return shifts; } /* Parameters: startOfWeek - The first day of the week in "yyyy-mm-dd" format endOfWeek - The last day of the week in "yyyy-mm-dd" format Return: ArrayList<String> */ ArrayList<Shift> getShiftsByWeek(LocalDateTime startOfWeek, LocalDateTime endOfWeek){ ArrayList<Shift> shifts = new ArrayList<>(); for (Shift shift : this.shifts.values()) { LocalDateTime start = shift.getStart(); LocalDateTime end = shift.getEnd(); if ((start.isAfter(startOfWeek) || start.isEqual(startOfWeek)) && (end.isBefore(endOfWeek)) || end.isEqual(endOfWeek)) { shifts.add(shift); } } return shifts; } //for view public ArrayList<Shift> getWeeklySchedule(){ LocalDateTime start; LocalDateTime end; // get start and end dates to pass along int today = date.getDayOfWeek().getValue(); // Mon is 1, Sun is 7 if (today == 7) { //this is the start date start = date.atTime(0, 0); end = date.plusDays(6).atTime(0,0); } else { start = date.minusDays(today).atTime(0, 0); end = date.plusDays(6 - today).atTime(0, 0); } return getEmployeeShiftsByWeek(selectedEmployee, start, end); } //for view public ArrayList<Shift> getDailySchedule(){ return getShiftsByDay(date.toString()); } ArrayList<Shift> getEmployeeShifts(String id) { int intID = -1; try { intID = Integer.parseInt(id); } catch (NumberFormatException exception) { exception.printStackTrace(); } ArrayList<Shift> shifts = new ArrayList<>(); for (Shift shift: this.shifts.values()) { if (shift.getEmployeeID() == intID) { shifts.add(shift); } } return shifts; } ArrayList<Shift> getEmployeeShiftsByWeek(int employeeID, LocalDateTime startOfWeek, LocalDateTime endOfWeek){ ArrayList<Shift> shifts = new ArrayList<>(); for (Shift shift : this.shifts.values()) { LocalDateTime start = shift.getStart(); LocalDateTime end = shift.getEnd(); if ((shift.getEmployeeID() == employeeID) && (start.isAfter(startOfWeek) || start.isEqual(startOfWeek)) && (end.isBefore(endOfWeek)) || end.isEqual(endOfWeek)) { shifts.add(shift); } } return shifts; } void editShiftAvailability(int shiftID, boolean available) { writer.println("editShiftAvailability/" + shiftID + "/" + available); } // adds a position if its one of the possible positions in the position table. void addEmployeePosition(int employeeID, String position) { writer.println("addEmployeePosition/" + employeeID + "/" + position); } void removeEmployeePosition(int employeeID, String position) { writer.println("removeEmployeePosition/" + employeeID + "/" + position); } void editAvailability(int employeeID, int dayOfTheWeek, int start, int end) { writer.println("editAvailability/" + employeeID + "/" + dayOfTheWeek + "/" + start + "/" + end); } //"YYYY-MM-DD" void addTimeOff(int employeeID, String startDate, String endDate, String reason) { writer.println("addTimeOff/" + employeeID + "/" + startDate + "/" + endDate + "/" + reason); } void setTimeOffApproval(int timeOffID, boolean approval) { writer.println("setTimeOffApproval/" + timeOffID + "/" + approval); } void removeTimeOff(int timeOffID) { writer.println("removeTimeOff/" + timeOffID); } void addPosition(String position, float wage) { writer.println("addPosition/"); } void editPositionWage(String position, float wage) { writer.println("editPosition/"); } void removePosition(String position, float wage) { writer.println("removePosition/"); } void logOut() { writer.println("logout"); try { this.socket.close(); } catch (IOException ex){ System.out.println("Error: Failed to close socket"); } } public static void main(String[] args) { String hostname = "localhost"; int port = 8989; Model client = new Model(hostname, port); System.out.print("Retrieving Data"); while(client.employees.isEmpty()){ System.out.print("."); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { System.out.println("Error: ScheduleClient main. Interrupted while retrieving data "); } } System.out.println(); System.out.println("Data retrieved."); System.out.println("ScheduleClient is ready to use!"); } public ArrayList<String> returnFormattedEmployeeNames(){ ArrayList<String> result = new ArrayList<>(); for (Employee employee: this.employees.values()) { result.add(employee.getFullName()); } System.out.println(result); return result; } public int getIDbyIndex(int index) { Employee[] employeeList = this.employees.values().toArray(new Employee[0]); return employeeList[index].getEmployeeID(); } //for publish/subscribe public void addSubscriber(ModelSubscriber sub){ subscribers.add(sub); } public void notifySubscribers(){ for (ModelSubscriber sub : subscribers){ sub.modelChanged(); } } }