/* ADTAssignment.java, written for java2
Author: Zach Tomaszewski
Date: 23 Sept 2001
*/
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.StringTokenizer;
import java.util.NoSuchElementException;
/**
* A digital clock ADT.
*
* @author Zach Tomaszewski
*/
class TimeOfDay implements Comparable {
private int hours;
private int minutes;
public static void main(String args[]){
runTests();
}
/**
* Creates a new instance intantiated to midnight (0:00).
*/
protected TimeOfDay() {
hours = 0;
minutes = 0;
}
/**
* Creates a new instance set to the specified time. The time should
* be given in a valid 24-hour format.
*
* @param hours The hour to set this TimeOfDay to
* @param hours The minutes to set this TimeOfDay object to
* @throws InvalidInputException When it is not true that
* 0 <= hours < 24 or 0 <= minutes < 60
*/
protected TimeOfDay(int hours, int minutes) throws InvalidInputException {
this.setTime(hours, minutes);
}
/**
* Sets this instance to the specified time. The time should
* be given in 24-hour format. For example, use
* new TimeOfDay(0,0)
to set the time to midnight.
* new TimeOfDay(15,3)
would set the time to 15:03 (or 3:03pm).
*
* @param hours The hour to set this TimeOfDay to
* @param hours The minutes to set this TimeOfDay object to
*/
protected void setTime(int hours, int minutes) throws InvalidInputException{
if (hours > 23 || hours < 0) {
throw new InvalidInputException("Hours given are not between 0 and 23.");
}else if (minutes >59 || minutes < 0) {
throw new InvalidInputException("Minutes given are not between 0 and 59.");
}else {
this.hours = hours;
this.minutes = minutes;
}
}
/**
* Increase this instance's time a positive number of minutes.
* If more than 60 minutes are given,
* the hours increase. If the time would exceed 23:59, it rolls over to
* 0:00 and the remainder of the minutes are added.
* (In short, behavior models a real clock.)
* This method does not decrease the time if a negative number of minutes
* is given; instead, it simply does not increase the time (does nothing).
*
* @param minutes Number of minutes to increase the time.
*/
protected void increaseTime(int minutes) {
if (minutes < 0) { return; } //don't handle negative input
int minutesToAdd = 0; //initially...
int hoursToAdd = minutes / 60; //integer math; more than one hour here?
if (hoursToAdd > 0) { //avoid divide-by-zero
minutesToAdd = minutes - (60 * hoursToAdd);
}else {
minutesToAdd = minutes;
}
this.minutes += minutesToAdd;
if (this.minutes > 59) {
/* minutesToAdd may exceed 59, but should never reach 120 */
this.minutes -= 60;
hoursToAdd++;
}
this.hours += hoursToAdd;
if (this.hours > 23) {
this.hours %= 24;
}
}
/**
* Returns the this time in 24 hour format, as in "16:19".
*
* @returns The time
*/
protected String get24Time() {
String time = "";
if (hours < 10) {
time = time + "0";
}
time = time + hours + ":";
if (minutes < 10) {
time = time + "0";
}
time = time + minutes;
return time;
}
/**
* Returns the this time in 12-hour format, as in "4:19PM".
*
* @returns The time
*/
protected String get12Time() {
String time = "";
String meridian = "";
if (hours < 10 && hours == 0) {
time = time + "0";
}
if (hours > 12) {
time = time + (hours - 12) + ":";
meridian = "PM";
}else{
if (hours == 0) {
time= time + "12:"; //0:00 == 12:00am
}else {
time = time + hours + ":";
}
meridian = "AM";
}
if (minutes < 10) {
time = time + "0";
}
time = time + minutes;
time = time + meridian;
return time;
}
/**
* Returns this instance's hours
*/
protected int getHours() {
return this.hours;
}
/**
* Returns this instances's minutes
*/
protected int getMinutes() {
return this.minutes;
}
/**
* Determines whether these two TimeOfDay objects are equal
* (whether they have the same time).
*/
public boolean equals(TimeOfDay tod){
if (this.getHours() == tod.getHours() &&
this.getMinutes() == tod.getMinutes()){
return true;
}else {
return false;
}
}
/**
* Returns -1 if this object has an earlier time than the given object,
* 1 if this time is later, or 0 if they are equal.
*/
public int compareTo(Object obj){
TimeOfDay tod = (TimeOfDay) obj;
if (this.getHours() < tod.getHours()) {
return -1;
}else if (this.getHours() > tod.getHours()){
return 1;
}else { //the hours are equal
if (this.getMinutes() < tod.getMinutes()) {
return -1;
}else if (this.getMinutes() > tod.getMinutes()) {
return 1;
}else { //minutes are also equal
return 0;
}
}
}
/**
* A method used to test the other methods of this class.
*/
private static void runTests() {
try {
TimeOfDay clock = null;
StringTokenizer menuChoice;
char firstChar = ' ';
int hours, minutes;
BufferedReader stdin = new BufferedReader(
new InputStreamReader(System.in));
while (firstChar != 'e' && firstChar != 'E'){
if (clock == null) {
System.out.println("\nc \t --Create a new TimeOfDay instance "
+ "with default time.");
System.out.println("c TIME \t --Create a new TimeOfDay instance "
+ "set to this 24-hour time");
System.out.println("e \t --Exit.");
System.out.println("Current time: [No instance created]");
System.out.print("Enter a command: ");
}else {
System.out.println("\nc \t --Create a new TimeOfDay instance "
+ "with default time.");
System.out.println("c TIME \t --Create a new TimeOfDay instance "
+ "set to this 24-hour time.");
System.out.println("s TIME \t --Set the current instance to this "
+ "24-hour time.");
System.out.println("i MINUTES --Increment the current instance "
+ "this many minutes.");
System.out.println("e \t --Exit.");
System.out.println("Current time: [" + clock.get24Time() + "] ||"
+ " [" + clock.get12Time() + "]");
System.out.print("Enter a command: ");
}
menuChoice = new StringTokenizer(stdin.readLine(), " ,:");
if (menuChoice.countTokens() > 0) {
firstChar = menuChoice.nextToken().charAt(0);
}
if (firstChar == 'c' || firstChar == 'C'){
if (menuChoice.hasMoreTokens()){
clock = new TimeOfDay(Integer.parseInt(menuChoice.nextToken()),
Integer.parseInt(menuChoice.nextToken()));
}else {
clock = new TimeOfDay();
}
}else if (firstChar == 's' || firstChar == 'S'){
clock.setTime(Integer.parseInt(menuChoice.nextToken()),
Integer.parseInt(menuChoice.nextToken()));
}else if (firstChar == 'i' || firstChar == 'I'){
clock.increaseTime(Integer.parseInt(menuChoice.nextToken()));
}else if (firstChar == 'e' || firstChar == 'E'){
//do nothing and drop through to the while loop
}else {
throw new InvalidInputException("That is not a valid menu option.");
}
}//end while
}catch (IOException ioe){
}catch (NumberFormatException nfe){
System.out.println("\nYour menu selection did not contain an "
+ "appropriate time. Please try again.");
runTests();
}catch (NoSuchElementException nsee){
System.out.println("\nYour menu selection did not contain an "
+ "appropriate time. Please try again.");
runTests();
}catch (InvalidInputException iie){
System.out.println("\n" + iie.getMessage() + " Please try again.");
runTests();
}
}
}//end class
/**
* Defines a sorted list of Objects. Objects must implement
* java.lang.Comparable for sorting purposes.
*
* @author Zach Tomaszewski
*/
interface SortedList{
/**
* Determines whether a sorted list is empty.
*/
public boolean sortedIsEmpty();
/**
* Returns the number of items that are in a sorted list
*/
public int sortedSize();
/**
* Inserts item into its proper sorted position
* in a sorted list. Throws an exception if the item
* cannot be place in the list (list full)
*/
public void sortedAdd(Comparable item);
/**
* Deletes item from a sorted list.
* Throws an exception if the item is not found.
*/
public void sortedRemove(Comparable item) throws ListItemNotFoundException;
/**
* Returns the item at postion index of a sorted list,
* if 1 <= index <= sortedSite(). The list is left unchanged
* by this operation. Throws an exception if the index is out of range
*/
public Comparable sortedGet(int index) throws IndexOutOfBoundsException;
/**
* Returns the position where item belongs or exists in a sorted list;
* item and the list are unchanged. Items in the list must implement
* java.lang.Comparable.
*/
public int locateIndex(Comparable item);
}//end interface
/**
* A sorted list of Comparable objects; max array size is 50 objects.
* Objects placed in the
* array must implement java.lang.Comparable for sorting purposes.
*
* @author Zach Tomaszewski
*/
class SortedListArrayBased implements SortedList{
static final int MAX_SIZE = 50;
private Comparable[] array;
private int size;
/**
* Creates an empty sorted list
*/
public SortedListArrayBased(){
array = new Comparable[MAX_SIZE];
size = 0;
}
/**
* Determines whether a sorted list is empty.
*
* @returns True if the list contains no items
*/
public boolean sortedIsEmpty(){
return (size == 0) ? true : false;
}
/**
* Returns the number of items that are in a sorted list
*/
public int sortedSize() {
return size;
}
/**
* Inserts item into its proper sorted position
* in a sorted list. Throws an exception if the item
* cannot be place in the list (list full)
*
* @param item The Object to add to the list
* @throws IndexOutOfBoundsException if the list is full
*/
public void sortedAdd(Comparable item) throws IndexOutOfBoundsException{
if (this.sortedSize() >= MAX_SIZE) {
throw new IndexOutOfBoundsException("This sorted list has already "
+ "reached max size; item cannnot be added.");
}else {
int insertIndex = this.locateIndex(item);
for (int i = this.sortedSize() - 1; i >= insertIndex; i--) {
this.array[i+1] = this.array[i];
}
this.array[insertIndex] = item;
size++;
}
}
/**
* Deletes the specified item from a sorted list.
*
* @param item The specified item to remove
* @throws ListItemNotFoundExcption if item does not exist in the list
*/
public void sortedRemove(Comparable item) throws ListItemNotFoundException {
//get the index (not the position)
int removeIndex = this.locateIndex(item) - 1;
if (this.sortedGet(removeIndex + 1).compareTo(item) != 0) { //position again
/* this is not really the item we want; must not be in the list */
throw new ListItemNotFoundException("Cannot delete");
}else {
/* shuffle everything down, covering the unwanted item */
for (int i = removeIndex; i <= this.sortedSize()-1; i++) {
this.array[i] = this.array[i + 1];
}
size--;
}
}
/**
* Returns the item at the specified list postion,
* if 1 <= position <= sortedSize(). The list is left unchanged
* by this operation. Throws an exception if the index is out of range
*
* @param position The position in the list from which to grab an object
* @returns The object so found
*/
public Comparable sortedGet(int position) throws IndexOutOfBoundsException {
if (position < 1 || position > this.sortedSize()){
throw new IndexOutOfBoundsException("Specified position is out of range");
}else {
return this.array[position - 1];
}
}
/**
* Returns the index where item belongs or exists in a sorted list;
* item and the list are unchanged. Items in the list must implement
* java.lang.Comparable.
*
* @param item The object to find in the array
* @returns int The index at which the object can be found
*/
public int locateIndex(Comparable item) {
return this.locateIndex(item, 0, size-1);
}
/**
* Returns the index where item belongs or exists in a sorted list;
* item and the list are unchanged. Items in the list must implement
* java.lang.Comparable.
*
* @param item The object to find in the array
* @param first Index at which to start searching
* @param last Index at which to stop searching
* @returns the index at which the object can be found
*/
private int locateIndex(Comparable item, int first, int last) {
int midpoint = (last + first)/2;
if (first >= last) { //one item array
if (array[midpoint] != null && array[midpoint].compareTo(item) < 0) {
return midpoint + 1;
}else {
return midpoint;
}
}else if (first == last - 1) { //two item array
if (array[midpoint].compareTo(item) > 0) {
return midpoint;
}else if (array[midpoint].compareTo(item) < 0 &&
array[midpoint + 1].compareTo(item) > 0 ) {
return midpoint + 1;
}else {
return midpoint + 2;
}
}else {
if (array[midpoint].compareTo(item) == 0) {
return midpoint;
}else if (array[midpoint].compareTo(item) > 0) {
last = midpoint; /* take lower half of array */
return this.locateIndex(item, first, last);
}else if (array[midpoint].compareTo(item) < 0) {
first = midpoint; /* take upper half of array */
return this.locateIndex(item, first, last);
}else { //should never be needed, but needed to compile
return -1;
}
}
}
}//end class
/**
* An application for testing SortedListArrayBased by using TimeOfDay
* objects. It queries the user for a number of times and adds them
* to their proper places in a sorted list.
*
* @author Zach Tomaszewski
*/
class SortedListTester {
public static void main(String[] args) {
SortedListArrayBased slab = new SortedListArrayBased();
String nextTime = "not an empty string";
StringTokenizer stringT;
int hours, minutes;
try{
BufferedReader stdin = new BufferedReader(
new InputStreamReader(System.in));
while (!nextTime.equals("")) {
System.out.println("Ordered list currently contains: ");
printList(slab);
System.out.print("Add a time to the list or hit Enter to quit: ");
nextTime = stdin.readLine();
try{
if (!nextTime.equals("")){
stringT = new StringTokenizer(nextTime, " ,:");
hours = Integer.parseInt(stringT.nextToken());
minutes = Integer.parseInt(stringT.nextToken());
slab.sortedAdd(new TimeOfDay(hours, minutes));
}
}catch (Exception e) {
System.out.println(e.getClass().getName());
System.out.println("Time format unrecognized. Please try again.");
}
}//end while
}catch (IOException ioe) {
System.err.println("Problem with IO!");
}
}
protected static void printList(SortedListArrayBased slab) {
int index = 1;
while (index <= slab.sortedSize()){
System.out.print("[" +
((TimeOfDay)slab.sortedGet(index)).get24Time() +
"] ");
index++;
}
System.out.println();
}
}//end class
/**
* An exception convenient for when a method recieved parameters it can't
* handle, especially when those parameters are documented in the method's
* description.
*/
class InvalidInputException extends Exception {
public InvalidInputException() {
super();
}
public InvalidInputException(String s) {
super(s);
}
}//end class
/**
* For when a specified item is not in a list.
*/
class ListItemNotFoundException extends Exception {
public ListItemNotFoundException() {
super();
}
public ListItemNotFoundException(String s) {
super(s);
}
}//end class