//COMPLETELY CHECKED package flights; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; import java.util.Hashtable; import java.util.Vector; import messages.FeedBackManager; import org.prevayler.*; import planes.Airplane; import bookings.Booking; /** * This class if responsible for managing the Flights provided by the Company. * @author Daniela Fontes, Ivo Correia, Jo�o Penetra, Jo�o Barbosa, Ricardo Bernardino * */ public class FlightsManager { FeedBackManager feedBackManager; FlightsCleaner flightsCleaner; private Vector<Flight> flightsList; private Vector<Flight> finishedFlights; public int idCreator = 0; private Prevayler prevayler; private Prevayler prevaylerFinished; private Prevayler prevaylerRegular; private Hashtable<Integer, Vector<RFlight>> regularFlights; public Prevayler getPrevayler() { return prevayler; } public Prevayler getPrevaylerFinished() { return prevaylerFinished; } public Prevayler getPrevaylerRegular() { return prevaylerRegular; } /* The constructor. */ @SuppressWarnings("unchecked") public FlightsManager(FeedBackManager feed) { super(); try { prevayler = PrevaylerFactory.createPrevayler(new Vector<Flight>(), "FlightsList"); prevaylerFinished = PrevaylerFactory.createPrevayler( new Vector<Flight>(), "FinishedFlightsList"); prevaylerRegular = PrevaylerFactory.createPrevayler( new Hashtable<Integer, Vector<RFlight>>(), "RegularFlightsList"); } catch (Exception e) { System.out.println("Prevayler error, exiting."); System.exit(-1); } flightsList = (Vector<Flight>) (prevayler.prevalentSystem()); finishedFlights = (Vector<Flight>) (prevaylerFinished.prevalentSystem()); regularFlights = (Hashtable<Integer, Vector<RFlight>>) (prevaylerRegular .prevalentSystem()); /* Gets the last id saved on the proper file. */ idCreator = getLastID(); feedBackManager = feed; /* Calendar.SUNDAY = 1 (...) Calendar.SATURDAY = 7 */ if (regularFlights.size() == 0) { for (int i = 1; i < 8; i++) { Vector<RFlight> regularFlightsList = new Vector<RFlight>(); this.putRegularFlight(i, regularFlightsList); } } flightsCleaner = new FlightsCleaner(this); } private int getLastID() { int id = 0; FileInputStream fis = null; DataInputStream dis = null; File file = new File("idflight.bin"); try { fis = new FileInputStream(file); dis = new DataInputStream(fis); id = dis.readInt(); fis.close(); } catch (IOException e) { id = 0; } return id; } /** * Adds a flight in the flight list * @param index * @param flight Flight Object to add to the list */ private void addFlight(int index, Flight flight) { prevayler.execute(new addFlight(index, flight)); } /** * Removes a flight from the flight list */ private void removeFlight(Flight flight) { prevayler.execute(new removeFlight(flight)); } /** * * Adds a new Booking */ public void addBookingFlight(Flight id, Booking booking) { prevayler.execute(new addBookingFlight(id, booking)); feedBackManager.sendNotificationUser( booking.getClient().getEmail(), "NEW BOOKING", "Reservation under the name of: " + booking.getClient().getName() + "\nBooking Number: " + booking.getBookingNumber() + "\n Flight: " +booking.getIdFlight()); } public void putRegularFlight(int id, Vector<RFlight> rfs) { prevaylerRegular.execute(new putRegularFlight(id, rfs)); } public void addRegularFlight(int id, RFlight rf) { prevaylerRegular.execute(new addRegularFlight(id, rf)); } public void removeRegularFlight(int id, RFlight rf) { prevaylerRegular.execute(new removeRegularFlight(id, rf)); } /** * * Cancels a booking */ public void removeBookingFlight(Flight id, Booking booking) { prevayler.execute(new removeBookingFlight(id, booking)); } public Flight removeFlight(int index) { Flight flight = flightsList.get(index); prevayler.execute(new removeFlight(flightsList.get(index))); return flight; } /** * Schedules a new flight. * @param plane Plane of the Flight * @param date Date of the flight * @param origin Origin of the flight * @param destination Destination of the flight * @param isRegular True if it is a Regular Flight, False otherwise * @param isCharter True if it is a charter, False otherwise * @return Returns the rescheduled Flight */ public Flight scheduleFlight(Airplane plane, GregorianCalendar date, String origin, String destination, boolean isRegular, boolean isCharter) { Flight flight = new Flight(plane, date, origin, destination, isRegular, isCharter, idCreator); int i; FileOutputStream fos = null; DataOutputStream dos = null; File file = new File("idflight.bin"); idCreator++; try { fos = new FileOutputStream(file); dos = new DataOutputStream(fos); dos.writeInt((idCreator)); fos.close(); } catch (IOException e) { } /* First, we check if we can insert in this specific plane. */ plane.associateFlight(flight); if (isRegular) { RFlight rflight = new RFlight(plane, origin, destination, date.get(Calendar.DAY_OF_WEEK), date.get(Calendar.HOUR_OF_DAY), date.get(Calendar.MINUTE), plane.getId(), flight.getId(), isCharter); Vector<RFlight> aux = regularFlights.get(date .get(Calendar.DAY_OF_WEEK)); for (i = 0; i < aux.size(); i++) { if (aux.get(i).getOrigin() == origin && aux.get(i).getDestination() == destination) return null; } this.addRegularFlight(date.get(Calendar.DAY_OF_WEEK), rflight); } /* Inserts the flight ordered by date. */ for (i = 0; i < flightsList.size(); i++) { if (flightsList.get(i).getDate().after(flight.getDate())) { this.addFlight(i, flight); return flight; } } /* We insert it in the last position. */ addFlight(i, flight); return flight; } /** * Schedules a flight, given a regular flight that hasn't been booked yet. * @param plane Plane of the flight * @param idRFlight Id of the Regular Flight * @param date Date of the flight * @param origin Origin of the flight * @param destination Destination of the flight * @param isCharter True if it is a charter, False otherwise * @return Returns the rescheduled Flight */ public Flight reScheduleRFlight(Airplane plane, int idRFlight, GregorianCalendar date, String origin, String destination, boolean isCharter) { Flight flight = new Flight(plane, date, origin, destination, true, isCharter, idRFlight); int i; /* First, we check if we can insert in this specific plane. */ plane.associateFlight(flight); /* Inserts the flight ordered by date. */ for (i = 0; i < flightsList.size(); i++) { if (flightsList.get(i).getDate().after(flight.getDate())) { this.addFlight(i, flight); return flight; } } /* We insert it in the last position. */ addFlight(i, flight); return flight; } /** * Cancels a specific flight and warns all the respective clients * @param flight Flight that is going to be canceled */ public void cancelFlight(Flight flight) { GregorianCalendar calendar = flight.getDate(); for (Booking r : flight.getBookings()) { feedBackManager .sendNotificationUser( r.getClient().getEmail(), "Notification", "The Flight " + flight.getId() + " with destination to " + flight.getDestination() + ", in " + calendar.get(Calendar.DAY_OF_MONTH) + "/" + (calendar.get(Calendar.MONTH) + 1) + "/" + calendar.get(Calendar.YEAR) + " at " + calendar.get(Calendar.HOUR_OF_DAY) + ":" + (calendar.get(Calendar.MINUTE) + 1) + ", was cancelled.\nWe are deeply sorry for all the trouble that might incur."); } this.removeFlight(flight); /* After removing it, we need to add it to the finished list. */ flight.setFinishedReason("Cancelled"); this.addFinished(flight); } public void cancelRegularFlight (RFlight flight){ this.removeRegularFlight(flight.getWeekDay(), flight); } /** * Re-schedules the Flight to the given date and plane * @param flight Desired Flight * @param date New date for the Flight * @param plane Plane in which the Flight will be available. */ public void reScheduleFlight(Flight flight, GregorianCalendar date, Airplane plane) { Flight temp = flight; int i; if (date != null) { temp.setDate(date); this.removeFlight(flight); /* Inserts the flight ordered by date. */ for (i = 0; i < flightsList.size(); i++) { if (flightsList.get(i).getDate().after(flight.getDate())) { this.addFlight(i, temp); break; } } /* We insert it in the last position. */ if (i == flightsList.size()) { addFlight(i, temp); } GregorianCalendar calendar = temp.getDate(); for (Booking r : temp.getBookings()) { feedBackManager .sendNotificationUser( r.getClient().getEmail(), "Notification", "The Flight " + flight.getId() + " with destination to " + flight.getDestination() + ", in " + calendar.get(Calendar.DAY_OF_MONTH) + "/" + (calendar.get(Calendar.MONTH) + 1) + "/" + calendar.get(Calendar.YEAR) + " at " + calendar.get(Calendar.HOUR_OF_DAY) + ":" + (calendar.get(Calendar.MINUTE) + 1) + ", was rescheduled.\nWe are deeply sorry for all the trouble that might incur."); } } } /** * Lists all of the Flights. * @return Returns a String with the information of each Flight. */ public String listFlights() { String text = ""; /* Prints the flights. */ text += "FLIGHTS\n"; for (int i = 0; i < flightsList.size(); i++) { Flight flight = flightsList.get(i); text += flight.getId() + "\t" + flight.getAirplane().getId() + "\t" + flight.getOrigin() + "/" + flight.getDestination() + "\t" + flight.getData().toString() + " " + flight.getOccupiedSeats() + "/" + flight.getAirplane().getNoSeats() + (flight.isCharter() ? " Charter" : " Normal")+ "\n"; } /* Prints the regular flights. */ text += "\nREGULAR FLIGHTS\n"; for (int i = 1; i < 8; i++) { Vector<RFlight> aux = regularFlights.get(i); for (int z = 0; z < aux.size(); z++) { RFlight rFlight = aux.get(z); text += rFlight.getIdFlight() + "\t" + rFlight.getIdPlane() + "\t" + rFlight.getOrigin() + "/" + rFlight.getDestination() + "\t" + rFlight.getData() + (rFlight.isCharter() ? " Charter" : " Normal") + "\n"; } } return text; } /** * Lists all of the finished Flights. * @return Returns a String with the information of each Flight. */ public String listFinishedFlights() { String text = ""; /* Prints the finished flights. */ text += "FINISHED FLIGHTS\n"; for (int i = 0; i < finishedFlights.size(); i++) { Flight flight = finishedFlights.get(i); text += flight.toFinishedString(); } return text; } /** * Function responsible for searching the Flights List. * @param year * @param month * @param day * @param origin * @param destination * @return Returns the String with the results of the search. */ public String findFlights(int year, int month, int day, String origin, String destination) { String text = ""; GregorianCalendar data = new GregorianCalendar(year, month - 1, day); int weekDay = data.get(Calendar.DAY_OF_WEEK); int i = 0; data.set(Calendar.HOUR_OF_DAY, 23); data.set(Calendar.MINUTE, 59); data.set(Calendar.SECOND, 59); while (i < flightsList.size() && flightsList.get(i).getDate().before(data)) { Flight flight = flightsList.get(i); GregorianCalendar flightDate = flight.getDate(); /* First, gets the normal flights. */ if (flightDate.get(Calendar.YEAR) == year && flightDate.get(Calendar.MONTH) + 1 == month && flightDate.get(Calendar.DAY_OF_MONTH) == day) { /* * If the flight is regular, it will be joined to the list * later. */ if (flight.getOrigin().equals(origin) && flight.getDestination().equals(destination) && !flight.isFull() && !flight.isRegular()) { /* * This flight matches all the criteria and consequently can * be added to the list. */ text += flight.toString() + "\n"; } } i++; } /* Then, the regular ones. */ Vector<RFlight> rFlights = regularFlights.get(weekDay); for (i = 0; i < rFlights.size(); i++) { text += "FLIGHT ID: " + rFlights.get(i).getIdFlight() + "\n"; } if (text.equals("")) { text += "There are no flights for this pair origin/destination in this date."; } return text; } /** * Search a flight by Date and plane * @param plane * @param date * @return Returns the Flight or null if it is not found. */ public Flight searchFlightByDate(Airplane plane, GregorianCalendar date) { for (int i = 0; i < flightsList.size(); i++) { if (flightsList.get(i).getAirplane().equals(plane) && flightsList.get(i).getDate().equals(date)) return flightsList.get(i); } return null; } /** * Search a normal flight by ID * @param id ID of the Flight * @return Returns the Flight object or null if it is not found. */ public Flight searchFlightById(int id) { for (int i = 0; i < flightsList.size(); i++) { if (flightsList.get(i).getId() == id) return flightsList.get(i); } return null; } /** * Search a regular flight by ID * @param id ID of the Regular Flight * @return Returns the Flight object or null if it is not found. */ public RFlight searchRFlightById(int id) { for (int i = 1; i < 8; i++) { Vector<RFlight> aux = regularFlights.get(i); for (int z = 0; z < aux.size(); z++) { RFlight rFlight = aux.get(z); if (rFlight.getIdFlight() == id) return rFlight; } } return null; } public Vector<Flight> getFlightsList() { return flightsList; } public Vector<Flight> getFinishedFlights() { return finishedFlights; } public int[] getNumFlights() { /* In the first field, we registered the finished flights. * In the second, goes the cancelled number. */ int [] outcome = new int[2]; outcome[0] = 0; outcome[1] = 0; for (Flight flight : finishedFlights){ if (flight.getFinishedReason().equals("Finished")){ outcome[0]++; } else{ outcome[1]++; } } return outcome; } public int[] getNumFlights(GregorianCalendar beginning, GregorianCalendar end) { /* In the first field, we registered the finished flights. * In the second, goes the cancelled number. */ int [] outcome = new int[2]; outcome[0] = 0; outcome[1] = 0; for (Flight flight : finishedFlights){ if (flight.getDate().after(beginning) && flight.getDate().before(end)) { if (flight.getFinishedReason().equals("Finished")){ outcome[0]++; } else{ outcome[1]++; } } } return outcome; } /** * Function used to calculate the percentage of occupied seats in all the Flights of the company. * @return Returns the percentage of occupied seats. */ public int getOccupation() { int sum = 0; int total = flightsList.size(); for (Flight f : flightsList) { sum += f.getOccupiedSeats() / f.getAirplane().getNoSeats() * 100; } if (total == 0) return 0; return sum / total; } /** * Function used to calculate the percentage of occupied seats in all the Flights of the company, that happened between the given dates. * @param beginning Beginning Date * @param end End Date * @return Returns the percentage of occupied seats. */ public int getOccupation(GregorianCalendar beginning, GregorianCalendar end) { int sum = 0; int total = 0; Flight aux; for (int i = 0; i < flightsList.size(); i++) { aux = flightsList.get(i); if (aux.getDate().before(beginning)) { } else if (aux.getDate().after(beginning) && aux.getDate().before(end)) { total++; sum += aux.getOccupiedSeats() / aux.getAirplane().getNoSeats() * 100; } else if (aux.getDate().after(end)) { break; } } if (total == 0) return 0; return sum / total; } public FlightsCleaner getFlightsCleaner() { return flightsCleaner; } public void addFinished(Flight flight) { prevaylerFinished.execute(new addFinished(flight)); return; } } class addFlight implements Transaction { /** * */ private static final long serialVersionUID = 1L; /** * */ private Flight flight; private int index; public addFlight(int index, Flight flight) { this.flight = flight; this.index = index; } @SuppressWarnings("unchecked") @Override public void executeOn(Object arg0, Date arg1) { ((Vector<Flight>) arg0).add(index, flight); } } class removeFlight implements Transaction { /** * */ private static final long serialVersionUID = 1L; /** * */ private Flight flight; public removeFlight(Flight flight) { this.flight = flight; } @SuppressWarnings("unchecked") @Override public void executeOn(Object arg0, Date arg1) { ((Vector<Flight>) arg0).remove(flight); } } class addBookingFlight implements Transaction { /** * */ private static final long serialVersionUID = 1L; /** * */ private Flight id; private Booking booking; public addBookingFlight(Flight id, Booking booking) { this.id = id; this.booking = booking; } @SuppressWarnings("unchecked") @Override public void executeOn(Object arg0, Date arg1) { ((Vector<Flight>) arg0).get(((Vector<Flight>) arg0).indexOf(id)) .newBooking(booking); ((Vector<Flight>) arg0).get(((Vector<Flight>) arg0).indexOf(id)) .increaseOccupied(booking.getNoSeats()); } } class removeBookingFlight implements Transaction { /** * */ private static final long serialVersionUID = 1L; /** * */ private Flight id; private Booking booking; public removeBookingFlight(Flight id, Booking booking) { this.id = id; this.booking = booking; } @SuppressWarnings("unchecked") @Override public void executeOn(Object arg0, Date arg1) { ((Vector<Flight>) arg0).get(((Vector<Flight>) arg0).indexOf(id)) .removeBooking(booking); ((Vector<Flight>) arg0).get(((Vector<Flight>) arg0).indexOf(id)) .decreaseOccupied(booking.getNoSeats()); } } class addFinished implements Transaction { /** * */ private static final long serialVersionUID = 1L; /** * */ private Flight flight; public addFinished(Flight flight) { this.flight = flight; } @SuppressWarnings("unchecked") @Override public void executeOn(Object arg0, Date arg1) { ((Vector<Flight>) arg0).add(flight); } } class putRegularFlight implements Transaction { /** * */ private static final long serialVersionUID = 1L; /** * */ private Vector<RFlight> rfs; private int id; public putRegularFlight(int id, Vector<RFlight> rfs) { this.id = id; this.rfs = rfs; } @SuppressWarnings("unchecked") @Override public void executeOn(Object arg0, Date arg1) { ((Hashtable<Integer, Vector<RFlight>>) arg0).put((Integer) id, rfs); } } class addRegularFlight implements Transaction { /** * */ private static final long serialVersionUID = 1L; /** * */ private RFlight rfs; private int id; public addRegularFlight(int id, RFlight rfs) { this.id = id; this.rfs = rfs; } @SuppressWarnings("unchecked") @Override public void executeOn(Object arg0, Date arg1) { ((Hashtable<Integer, Vector<RFlight>>) arg0).get((Integer) id).add(rfs); } } class removeRegularFlight implements Transaction { /** * */ private static final long serialVersionUID = 1L; /** * */ private RFlight rfs; private int id; public removeRegularFlight(int id, RFlight rfs) { this.id = id; this.rfs = rfs; } @SuppressWarnings("unchecked") @Override public void executeOn(Object arg0, Date arg1) { ((Hashtable<Integer, Vector<RFlight>>) arg0).get((Integer) id).remove(rfs); } }