/******************************************************** * Copyright (C) 2008 Course Scheduler Team * * 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. * * 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, write to: * Free Software Foundation, Inc. * 59 Temple Place, Suite 330, * Boston, MA 02111-1307 USA ********************************************************/ /********************************************************* * Course Scheduler * File: Period.java * * Contains classes: * * Course: * * Purpose: To store course time periods * * @author Mike Reinhold *********************************************************/ package Scheduler; //Define class as member of Scheduler package /******************************************************** * Import Serializable class to allow for class to be * serialized for storage * Import Scanner for parsing strings *********************************************************/ import java.io.Serializable; //Import Serializable class, Scanner, and Pattern import java.util.Scanner; //to allow serializing the data, scanning and parsing text /******************************************************** * Class: Period * * @purpose To store the time period that the course uses * * @see Cloneable, Serializeable, Comparable *********************************************************/ public class Period implements Cloneable, Serializable, Comparable<Period> { //define Period to use clone, compareTo, serialize, and deserialize /******************************************************** * The following are private fields for use within Period *********************************************************/ private Time startTime; //the start time of the period private Time endTime; //the end time of the period private String period; //the period as a string private String duration; //the duration of the period private boolean[] days; //period days /******************************************************** * The following are private static constants for use within Period *********************************************************/ private static Time nullTime = new Time(); private static int hour = 60; /******************************************************** * UPDATE SERIAL VERSION IN VERSION WHEN THIS FILE CHANGES ********************************************************/ protected static final long versionID = 2013010900051L;//object ID protected static final long serialVersionUID = 1L + Version.period.id;//serial ID /******************************************************** * (Constructor) * * @purpose Creates a new Period and initializes its fields *********************************************************/ public Period(){ startTime = new Time(); //initializes and sets the endTime = new Time(); //fields to default values period = (startTime.toString() + "-" + endTime.toString() + ( endTime.getAm() ? "am" : "pm") ); //for the new Period duration = startTime.timeDifference(endTime).toString(); nullTime.setAm(true); nullTime.setHour(12); nullTime.setMinute(0); days = new boolean[Day.values().length]; } /******************************************************** * (Constructor) * * @purpose Create a new string and initializes the fields * based on a string in the format HH:MM-HH:MMam or * HH:MM-HH:MMpm * * @param String period: tje period in the format HH:MM-HH:MMam or * HH:MM-HH:MMpm *********************************************************/ public Period(String period){ this.period = new String(period); //create new string with same if (days == null){ days = new boolean[Day.values().length]; //text and set string value } setTimes(period); //to new string, set other } //fields /******************************************************** * (Constructor) * * @purpose Create a new string and initializes the fields * based on a string in the format HH:MM-HH:MMam or * HH:MM-HH:MMpm * * @param int minutes: the duration of the period in minutes *********************************************************/ public Period(int minutes){ String duration = new String(); //new string for the duration duration = Integer.toString(minutes/hour); //get the hours String min = Integer.toString(minutes%hour); //get the minutes duration += (":" + ((min.length() == 1) ? ("0" + min) : min));//build the period string this.period = new String("0:00-" + duration + "am"); days = new boolean[Day.values().length]; setTimes(period); } /********************************************************* * @purpose Returns an exact copy of this instance at a * separate memory location * * @return Period: the copy of the period *********************************************************/ @Override public Period clone(){ Period item = new Period(); //return a clone of this instance item.setDays(this.getDays()); item.setStartTime(startTime); item.setEndTime(endTime); item.setDuration(duration); item.period = (startTime.toString() + "-" + endTime.toString() + (endTime.getAm() ? "am" : "pm")); return item; } /********************************************************* * @purpose Compares two Periods and returns if this instance * is LESS than, EQUAL to, or MORE than the other object * * @param Object other: the object to compare this instance to * * @return int: the result of the comparison, standard compareTo *********************************************************/ public int compareTo(Period item){ //if start times are equal, return if (this.startTime.compareTo(item.getStartTime()) == Compare.equal.value()) {//comparison of end times return this.endTime.compareTo(item.getEndTime());//else return the comparison of } //the start times as the comparison of the periods. If object cannot be cast return this.startTime.compareTo(item.getStartTime());//return LESS to make valid period LESS than the invalid Period } /********************************************************* * @purpose Returns the Period as a string * * @return String: The period as a string *********************************************************/ @Override public String toString(){ return new String(this.period); //return this Period as a new string } /********************************************************* * @purpose sets the fields of the period to the correct values * based on the parameter String in the form HH:MM-HH:MMam * or HH:MM-HH:MMpm * * @return boolean: If the change was successful *********************************************************/ public boolean setPeriod(String period){ this.period = new String(period); //set period string to new string //based on the input string return setTimes(period); //return the result of attempting } //to set the times based on the input /********************************************************* * @purpose Determines if this period conflicts with another * period * * @param Period other: the period to check for a conflict * * @return boolean: if the two periods conflict *********************************************************/ public boolean conflictsWith(Period other){ Time oStart = other.getStartTime(); //get other's start time and end time Time oEnd = other.getEndTime(); //check if this instance's start or boolean[] otherDays = other.getDays(); if((this.days[Day.monday.value()] && otherDays[Day.monday.value()]) || (this.days[Day.tuesday.value()] && otherDays[Day.tuesday.value()]) || (this.days[Day.wednesday.value()] && otherDays[Day.wednesday.value()]) || (this.days[Day.thursday.value()] && otherDays[Day.thursday.value()]) || (this.days[Day.friday.value()] && otherDays[Day.friday.value()])){ //end is between other's start and end if (startTime.isBetween(oStart, oEnd) || //if either case then return true for endTime.isBetween(oStart, oEnd)) //conflicting. Then check if other's return true; //start or end is between is between else if(oStart.isBetween(startTime, endTime) || //this instance's start and end, if either oEnd.isBetween(startTime, endTime)) //case return true for conflicting. O return true; //Otherwise periods do not overlap, return false; //return false } return false; } /********************************************************* * @purpose Determines if this period contains another * period * * @param Period other: the period to check for containment * * @return boolean: if this period contains the other *********************************************************/ public boolean contains(Period other){ Time oStart = other.getStartTime(); //get the other period's start and end time Time oEnd = other.getEndTime(); if(oStart.isBetween(startTime, endTime)){ //check if the other's start is inside this if(oEnd.isBetween(startTime, endTime)){ //period and if the other's end is inside this return true; //period. if so return true, else return false } } return false; } /********************************************************* * @purpose Return the start Time of the period * * @return Time: the start Time of the Period *********************************************************/ protected Time getStartTime(){ return startTime.clone(); //return a startTime clone } /********************************************************* * @purpose Return the end Time of the Period * * @return Time: the end Time of the Period *********************************************************/ protected Time getEndTime(){ return endTime.clone(); //return an endTime clone } /********************************************************* * @purpose Returns the duration of the Period * * @return String: the duration as a string *********************************************************/ public String getDuration(){ return new String(duration); //return a duration clone } /********************************************************* * @purpose Returns the days for the period * * @return boolean[]: the days for the period *********************************************************/ public boolean[] getDays(){ return this.days.clone(); //return the days for the period } /********************************************************* * @purpose Sets the fields of this Period to the correct * values based on the input string in the format * HH:MM-HH:MMam or HH:MM-HH:MMpm * * @param String period: the input string to set the fields based on * * @return boolean: if the field setting was successful *********************************************************/ private boolean setTimes(String period){ try{ Scanner times = new Scanner(period); //create a scanner to parse the input times.useDelimiter(" - "); //with a delimiter of "-" to separate //the two times. Store the two times String first = times.next(); //to two string, first and second String second = times.next(); //Create two new Time instances to //hold the start and end times. startTime = new Time(); endTime = new Time(); times.close(); times = new Scanner(first); //reset scanner to read from the first times.useDelimiter(":"); //time and parse by ":" to separate //hours from minutes. Store the hours startTime.setHour(times.nextInt()); //and minutes to the hour and minute String temp = times.next(); times.close(); times = new Scanner(temp); startTime.setMinute(times.nextInt()); //fields of the start time String startAm = first.substring(first.length() - 2); times.close(); times = new Scanner(second); //substringing, create a new scanner times.useDelimiter(":"); //on the new string parsing by ":" //get the hours and the minutes from endTime.setHour(times.nextInt()); //the substring and store to the end temp = times.next(); times.close(); times = new Scanner(temp); endTime.setMinute(times.nextInt()); //time's hour and minute fields. //get the am/pm from the second time String endAm = second.substring(second.length() - 2);//set the end Time's am field to //the text read from the string times.close(); startTime.setAm((startAm.compareTo("am") == Compare.equal.value()) ? true : false); endTime.setAm((endAm.compareTo("am") == Compare.equal.value()) ? true : false); duration = startTime.timeDifference(endTime).toString();//duration as the difference //final - initial as a string return true; //return successful } catch(Exception ex){ duration = new String("0:00"); //set appropriate null time for startTime = nullTime.clone(); //TBA class times endTime = nullTime.clone(); return false; //return false if unable to parse } } /********************************************************* * @purpose Returns the percent outside the specified period * this period is * * @param Period other: the period that this is outside of * * @return double: the percent outside the other period * this period is *********************************************************/ public double percentOutside(Period other){ final int percent = 100; //define percent constant final int none = 0; //define none constant Time oStart = other.getStartTime(); //get other start time Time oEnd = other.getEndTime(); //get other end time if (oStart == null || oEnd == null){ return none; } double thisVal = Time.toMinutes(this.duration); //get minute duration if (startTime.isBetween(oStart, oEnd)){ //check start time containment if (endTime.isBetween(oStart, oEnd)){ //check end time containment return none; //no percent outside } Period overFlow = new Period(); //get new period overFlow.setTimes(oEnd.toString() + "-" +//set new period to the time outside this period is endTime.toString() + (endTime.getAm() ? "am" : "pm")); double overTime = Time.toMinutes(overFlow.duration);//convert the outside time to a double return overTime/thisVal * percent; //calculate and return overflow } if (endTime.isBetween(oStart, oEnd)){ //check end time containment Period overFlow = new Period(); //get new period and set to the time outside this period overFlow.setTimes(startTime.toString() + "-" + oStart.toString() + (startTime.getAm() ? "am" : "pm")); double overTime = Time.toMinutes(overFlow.duration);//get outside time as a double return overTime/thisVal * percent; //calculate and return overflow } return percent; //return 100% } /********************************************************* * @purpose Returns the duration of the period in minutes as * a double * * @return double: the number of minutes this period lasts *********************************************************/ public double getDurationMin(){ double result = 0; //create result placeholder Scanner parse = new Scanner(this.duration); //create scanner to parse the string parse.useDelimiter(":"); //use the ":" delimiter for "8:00" etc result = 60 * parse.nextDouble(); //get hour and mult by 60 minutes result += parse.nextDouble(); //get the minutes and adds to result parse.close(); return result; //return the result } /********************************************************* * @purpose Sets the periods days field * * @param boolean[] days: sets the period's days field *********************************************************/ public void setDays(boolean[] days){ this.days = days; //set the days } public void setStartTime(Time startTime) { this.startTime = startTime; } public void setEndTime(Time endTime) { this.endTime = endTime; } public void setDuration(String duration) { this.duration = duration; } }