Skip to content
Snippets Groups Projects
Model.java 21.6 KiB
Newer Older
  • Learn to ignore specific revisions
  • eyan_'s avatar
    eyan_ committed
    package com.example.schedulerapp;
    
    
    eyan_'s avatar
    eyan_ committed
    import java.net.*;
    import java.io.*;
    
    ArktikHunter's avatar
    ArktikHunter committed
    import java.time.LocalDate;
    
    ArktikHunter's avatar
    ArktikHunter committed
    import java.time.LocalDateTime;
    
    ArktikHunter's avatar
    ArktikHunter committed
    import java.util.ArrayList;
    
    import java.util.HashMap;
    import java.util.Map;
    
    eyan_'s avatar
    eyan_ committed
    import java.util.concurrent.TimeUnit;
    
    ArktikHunter's avatar
    ArktikHunter committed
    
    
    eyan_'s avatar
    eyan_ committed
    public class Model {
    
    eyan_'s avatar
    eyan_ committed
        private PrintWriter writer;
        private Socket socket;
    
        protected Map<Integer, Shift> shifts;
        protected Map<Integer, Employee> employees;
    
        protected  Map<Integer, TimeOff> timeOff;
    
    ArktikHunter's avatar
    ArktikHunter committed
        protected ArrayList<ModelSubscriber> subscribers;
    
    ArktikHunter's avatar
    ArktikHunter committed
    
    
    eyan_'s avatar
    eyan_ committed
        static LocalDate date;
    
        private boolean isManager;
        private int thisEmployee;
        private int selectedEmployee;
    
    ArktikHunter's avatar
    ArktikHunter committed
    
    
    eyan_'s avatar
    eyan_ committed
        public Model(String hostname, int port) {
    
    ArktikHunter's avatar
    ArktikHunter committed
            subscribers = new ArrayList<>();
    
    eyan_'s avatar
    eyan_ committed
            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<>();
    
    eyan_'s avatar
    eyan_ committed
            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());
            }
    
    ArktikHunter's avatar
    ArktikHunter committed
        }
    
    
        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){
    
    ArktikHunter's avatar
    ArktikHunter committed
            notifySubscribers();
    
        }
    
        public int getSelectedEmployee(){
            return selectedEmployee;
        }
    
        public void dateNext(){
            date = date.plusDays(1);
    
    ArktikHunter's avatar
    ArktikHunter committed
            notifySubscribers();
    
        public void weekNext(){
            date = date.plusDays(7);
            notifySubscribers();
        }
    
    
        public void datePrev(){
            date = date.minusDays(1);
    
    ArktikHunter's avatar
    ArktikHunter committed
            notifySubscribers();
    
        public void weekPrev(){
            date = date.minusDays(7);
            notifySubscribers();
        }
    
    
        //todo: add calender to fill jump field
        public void dateJump(LocalDate date){
    
    ArktikHunter's avatar
    ArktikHunter committed
            notifySubscribers();
    
        /*
        Name: addEmployee
        Parameters:
            String firstName: The new employees first name.
            String lastName: The new employees last name.
        Description: Adds an employee to the database.
        Return: String indicating the result
         */
        String addEmployee(String firstName, String lastName) {
            if (firstName.contains("/") || lastName.contains("/") || firstName.contains(",") || lastName.contains(",")){
                return "Illegal character(s)";
            }
    
            else {
                writer.println("addEmployee/" + firstName + "/" + lastName + "/" + false + "/" + "empty" + "/" + "empty" + "/" + 0.0f);
                return "Employee added";
            }
    
        void addEmployee(String firstName, String lastName, boolean isManager, String email, String phoneNumber, float wage) {
            writer.println("addEmployee/" + firstName + "/" + lastName + "/" + isManager + "/" + email + "/" + phoneNumber +
                    "/" + wage);
        }
    
    
        String editEmployee(int employeeID, String firstName, String lastName, boolean isManager, String email, String phoneNumber, float wage) {
            if (employeeID <= 0){
                return "Invalid ID";
            }
            if (firstName.contains("/") || lastName.contains("/") || firstName.contains(",") || lastName.contains(",")){
                return "Name contains illegal character(s)";
            }
            if(email.contains("/") || email.contains(",")){
                return "Email contains illegal character(s)";
            }
            if(phoneNumber.contains("/") || phoneNumber.contains(",")){
                return "phoneNumber contains illegal character(s)";
            }
            if (wage < 0){
                return "Invalid wage";
            }
            if (this.employees.containsKey(employeeID)) {
                writer.println("editEmployee/" + employeeID + "/" + firstName + "/" + lastName + "/" + isManager + "/" + email + "/" + phoneNumber +
                        "/" + wage);
                return "Employee edited";
            }
    
            return "Employee does not exist";
    
        /*
        Name: removeEmployee
        Parameters:
            String ID: The employees unique ID.
        Description: Removes an employee with the given ID if it exists.
        Return: String indicating the result
         */
        String removeEmployee(String employeeID) {
            if (Integer.parseInt(employeeID) <= 0){
                return "Invalid ID";
            }
    
            if (this.employees.size() < Integer.parseInt(employeeID)){
                return "Employee does not exist";
            }
    
            if (this.employees.containsKey(Integer.parseInt(employeeID))) {
                writer.println("removeEmployee/" + employeeID);
                return "Employee removed";
            }
            return "Employee does not exist";
    
        /*
        Name: getEmployee
        Parameters:
            int ID: The employees unique ID.
        Description: Gets an employee with the given ID if it exists.
        Return: The employee object if it exists, null if not
         */
    
        Employee getEmployee(int employeeID) {
    
            return employees.getOrDefault(employeeID, null);
    
    eyan_'s avatar
    eyan_ committed
        void printAllEmployees(){
    
            ArrayList<String> employeeList = new ArrayList<>();
            for (Employee employee : this.employees.values()) {
                employeeList.add(employee.getFullName());
            }
            System.out.println(employeeList);
    
        /*
        Name: employeeSize
        Description: Gets the number of employees in the database.
        Return: The total number of employees.
         */
    
    eyan_'s avatar
    eyan_ committed
        }
    
    
        /*
        Name: getEmployeeByID
        Parameters:
            int ID: The employees unique ID.
        Description: Gets an employee's name with the given ID if it exists.
        Return: A string containing the employees full name
         */
    
    eyan_'s avatar
    eyan_ committed
        String getEmployeeByID(int id) {
    
            if (this.employees.containsKey(id)) {
    
                Employee employee = this.employees.get(id);
    
                return employee.getFullName();
    
    eyan_'s avatar
    eyan_ committed
            }
    
            return "No Employee with that ID";
    
    eyan_'s avatar
    eyan_ committed
        }
    
    
        /*
        Name: addShift
        Parameters:
            int ID: The employees unique ID.
            String date: The date in yyyy-mm-dd format.
            int start: The start time in 24 hour time.
            int end: The end time in 24 hour time.
        Description: Adds a new shift on the given date.
        Return: String indicating the result
         */
        String addShift(int id, String date, int start, int end){
            if (id <= 0){
                return "Invalid ID";
            }
    
            if (start < 0 || end < 0 || end > 2359 || start >= end){
    
                return "Invalid start or end time";
            }
    
            if (this.employees.containsKey(id)){
                for (Shift shift : getShiftsByDay(date)) {
                    if (shift.getEmployeeID() == id) {
                        /* Commented out split shift just in case
                        int otherShiftStart = Integer.parseInt(shift.getStart().toLocalTime().toString().replace(":", ""));
                        int otherShiftEnd = Integer.parseInt(shift.getEnd().toLocalTime().toString().replace(":", ""));
                        if (start <= otherShiftEnd && !(end <= otherShiftStart)){
                            return "Shift time conflict with existing shift";
                        }
                        */
    
    Michael Kish's avatar
    Michael Kish committed
                        return "Shift time conflict for employee";
    
    Michael Kish's avatar
    Michael Kish committed
            if (this.employees.containsKey(id)) {
                int[] dayOfTheWeekAvailability = this.employees.get(id).getAvailabilityForDay(LocalDate.parse(date)
                        .getDayOfWeek().getValue() % 7);
                if (dayOfTheWeekAvailability[0] > start || dayOfTheWeekAvailability[1] < start || dayOfTheWeekAvailability[1] < end) {
                    return "Shift time conflicts with employees availability";
                }
            }
    
    
            else {return "No Employee with that ID";}
    
    
            writer.println("addShift/" + id + "/" + date + "/" + start + "/" + end + "/" + " ");
            notifySubscribers();
            return "New shift added";
    
    
    eyan_'s avatar
    eyan_ committed
        }
    
    
        //
        void addShift(int id, String date, int start, int end, String position){
            writer.println("addShift/"+id+"/"+date+"/"+start+"/"+end+"/"+position);
            notifySubscribers();
        }
    
        /*
        Name: removeShift
        Parameters:
            String shiftID: The unique ID for the shift.
        Description: Removes the shift with the given ID if it exists.
        Return: String indicating the result
         */
        String removeShift(int shiftID){
            if (shiftID <= 0){
                return "Invalid ID";
            }
            if (this.shifts.containsKey(shiftID)) {
                writer.println("removeShift/" + shiftID);
                notifySubscribers();
                return "Shift removed";
            }
            return "Shift does not exist";
    
    eyan_'s avatar
    eyan_ committed
        }
    
    
        String editShift(int shiftID, String day, int start, int end, Boolean availability, int employeeID) {
            if (shiftID <= 0){
                return "Invalid shift ID";
            }
            if (employeeID <= 0){
                return "Invalid employee ID";
            }
    
            if (start < 0 || end < 0 || start > 2359 || end > 2359){
    
                return "Invalid start or end time";
            }
            if (this.shifts.containsKey(shiftID)) {
                writer.println("editShift/" + shiftID + "/" + day + "/" + start + "/" + end + "/" + availability + "/" + employeeID);
                notifySubscribers();
                return "Shift successfully edited";
            }
            return "Shift does not exist";
    
        /*
        Name: getShift
        Parameters:
            int shiftID: The unique shift ID
        Description: Gets the shift with the given ID if it exists.
        Return: The shift object if it exists, null if not
         */
    
            return shifts.getOrDefault(shiftID, null);
    
    eyan_'s avatar
    eyan_ committed
        void printAllShifts() {
            System.out.println(this.shifts);
        }
    
    
    Rafi's avatar
    Rafi committed
        /*
        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);
    
    Rafi's avatar
    Rafi committed
                }
            }
    
    Rafi's avatar
    Rafi committed
        }
    
    
    eyan_'s avatar
    eyan_ committed
        /*
        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);
    
    eyan_'s avatar
    eyan_ committed
                }
            }
    
    eyan_'s avatar
    eyan_ committed
        }
    
    
    ArktikHunter's avatar
    ArktikHunter committed
        //for view
        public ArrayList<Shift> getWeeklySchedule(){
    
            LocalDateTime start;
            LocalDateTime end;
    
    ArktikHunter's avatar
    ArktikHunter committed
            // 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);
    
    ArktikHunter's avatar
    ArktikHunter committed
            }
            else {
    
                start = date.minusDays(today).atTime(0, 0);
                end = date.plusDays(6 - today).atTime(0, 0);
    
    ArktikHunter's avatar
    ArktikHunter committed
            }
    
            return getEmployeeShiftsByWeek(selectedEmployee, start, end);
    
    ArktikHunter's avatar
    ArktikHunter committed
        }
    
        //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);
    
    eyan_'s avatar
    eyan_ committed
                }
            }
    
            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);
    
    eyan_'s avatar
    eyan_ committed
        }
    
    
        String editShiftAvailability(int shiftID, boolean available) {
            if (shiftID <= 0){
                return "Invalid shift ID";
            }
            if (this.shifts.containsKey(shiftID)) {
                writer.println("editShiftAvailability/" + shiftID + "/" + available);
                return "Shift edited";
            }
            return "Shift does not exist";
    
        // adds a position if its one of the possible positions in the position table.
    
        String addEmployeePosition(int employeeID, String position) {
            if (employeeID <= 0){
                return "Invalid employee ID";
            }
            if (!this.positions.containsKey(position)){
                return "Position does not exist";
            }
            if (this.employees.containsKey(employeeID)) {
                writer.println("addEmployeePosition/" + employeeID + "/" + position);
                return "Position added to employee";
            }
            return "Employee does not exist";
    
        String removeEmployeePosition(int employeeID, String position) {
            if (employeeID <= 0){
                return "Invalid employee ID";
            }
            if (!this.positions.containsKey(position)){
                return "Position does not exist";
            }
            if (this.employees.containsKey(employeeID)) {
                writer.println("removeEmployeePosition/" + employeeID + "/" + position);
                return "Position removed from employee";
            }
            return "Employee does not exist";
    
        String editAvailability(int employeeID, int dayOfTheWeek, int start, int end) {
            if (employeeID <= 0){
                return "Invalid employee ID";
            }
            if (dayOfTheWeek < 0 || dayOfTheWeek > 8){
                return "Invalid day";
            }
            if (start < 0 || end < 0 || start > 2359 || end > 2359){
                return "Invalid start or end time";
            }
            if (this.employees.containsKey(employeeID)) {
                writer.println("editAvailability/" + employeeID + "/" + dayOfTheWeek + "/" + start + "/" + end);
            }
            return "Employee does not exist";
    
        String addTimeOff(int employeeID, String startDate, String endDate, String reason) {
            if (employeeID <= 0){
                return "Invalid employee ID";
            }
            if (reason.contains("/") || reason.contains(",")){
                return "Illegal character(s)";
            }
            if (this.employees.containsKey(employeeID)) {
                writer.println("addTimeOff/" + employeeID + "/" + startDate + "/" + endDate + "/" + reason);
                return "Time off added";
            }
            return "Employee does not exist";
    
        String setTimeOffApproval(int timeOffID, boolean approval) {
            if (timeOffID <= 0){
                return "Invalid employee ID";
            }
            if(this.timeOff.containsKey(timeOffID)) {
                writer.println("setTimeOffApproval/" + timeOffID + "/" + approval);
                return "Time off approved";
            }
            return "Time off request doesn't exist";
    
        String removeTimeOff(int timeOffID) {
            if (timeOffID <= 0){
                return "Invalid employee ID";
            }
            if(this.timeOff.containsKey(timeOffID)) {
                writer.println("removeTimeOff/" + timeOffID);
                return "Time off removed";
            }
            return "Time off request does not exist";
    
        String addPosition(String position, float wage) {
            if (position.contains("/") || position.contains(",")){
                return "Illegal character(s)";
            }
            if (wage <= 0){
                return "Invalid wage";
            }
            writer.println("addPosition/" + position + "/" + wage);
            return "Position added";
    
        String editPositionWage(String position, float wage) {
            if (position.contains("/") || position.contains(",")){
                return "Illegal character(s)";
            }
            if (wage <= 0){
                return "Invalid wage";
            }
            if(this.positions.containsKey(position)) {
                writer.println("editPosition/" + position + "/" + wage);
                return "Position edited";
            }
            return "Position does not exist";
    
        String removePosition(String position, float wage) {
            if (position.contains("/") || position.contains(",")){
                return "Illegal character(s)";
            }
            if (wage <= 0){
                return "Invalid wage";
            }
            if(this.positions.containsKey(position)) {
                writer.println("removePosition/"+ position + "/" + wage);
                return "Position removed";
            }
            return "Position does not exist";
    
        //How this works is if you start within 5 minutes of your shift than you can "signed-in" and
        //assumes you work the whole shift, if you leave early of come in late the shift manager
        //must change it in the schedule.
        void checkIn(int shiftID) {
            LocalDateTime nMinutesAfter = this.shifts.get(shiftID).getStart().plusMinutes(5);
            LocalDateTime nMinutesBefore = this.shifts.get(shiftID).getStart().minusMinutes(5);
            LocalDateTime now = LocalDateTime.now();
            if (nMinutesBefore.isBefore(now) && nMinutesAfter.plusMinutes(5).isAfter(now)) {
                writer.println("checkIn/" + shiftID);
            }
        }
    
    
    
        //This allows the manager to mark any shift as checked-in.
        void managerCheckIn(int shiftID) {
            writer.println("checkIn/" + shiftID);
        }
    
    
        //The dates need to be in form "yyyy-mm-dd"
        //Also the start and end are inclusive.
        float getHoursWorked(int employeeID, String start, String end) {
            float hoursWorked = 0.0f;
            try {
                SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
                Date startDate = formatter.parse(start);
                Date endDate = formatter.parse(end);
                for (Shift shift : this.shifts.values()) {
                    if (shift.getEmployeeID() == employeeID) {
                        Date shiftDate = formatter.parse(shift.getDate());
                        if (!startDate.after(shiftDate) && !endDate.before(shiftDate)){
                            if (shift.isCheckedIn()) {
                                hoursWorked = (hoursWorked + shift.getEnd().getHour() - shift.getStart().getHour()) + ((shift.getEnd().getMinute() - shift.getStart().getMinute())/60f);
                            }
                        }
                    }
    
                }
            } catch (Exception exception) {
                exception.printStackTrace();
                return -1f;
            }
            return hoursWorked;
        }
    
    
    eyan_'s avatar
    eyan_ committed
        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;
    
    eyan_'s avatar
    eyan_ committed
            Model client = new Model(hostname, port);
            System.out.print("Retrieving Data");
    
            while(client.employees.isEmpty()){
    
    eyan_'s avatar
    eyan_ committed
                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());
    
    eyan_'s avatar
    eyan_ committed
            }
            System.out.println(result);
            return result;
        }
    
    eyan_'s avatar
    eyan_ committed
    
        public int getIDbyIndex(int index) {
    
            Employee[] employeeList = this.employees.values().toArray(new Employee[0]);
            return employeeList[index].getEmployeeID();
    
    eyan_'s avatar
    eyan_ committed
        }
    
    ArktikHunter's avatar
    ArktikHunter committed
    
        //for publish/subscribe
        public void addSubscriber(ModelSubscriber sub){
            subscribers.add(sub);
        }
    
        public void notifySubscribers(){
            for (ModelSubscriber sub : subscribers){
                sub.modelChanged();
            }
        }
    
    eyan_'s avatar
    eyan_ committed
    }