// ------------------------------------------------------------------
// Name and ID: Amit Malhotra (5796997)
// Comp 249
// Assignment #3
// Due Date: 22nd of March 2013
//--------------------------------------------------------------------
package warships;
import java.io.BufferedReader;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintWriter;
import java.util.InputMismatchException;
import java.util.Scanner;
/**
* This abstract class contains all our static methods that we will need for our program
* that are not related to any object.
*
* @author Amit Malhotra
*
*/
public abstract class WarshipStaticMethods {
// make a static input scanner object to be used for
// getting input stream from the keyboard
public static Scanner kb = new Scanner(System.in);
/**
* This method will allow a user to enter a file name as requested, check
* the file name to see if the file with that name exists and return the
* file name to the calling method
*
* @return String (returns a string as entered by the user)
*/
public static String getOutputFileName() {
boolean validName = false; // flag to check for validfilename
String name = "";
// ask user for an Output file name
System.out.print("Please Enter a name for the output file:");
// our loop will check if the user entered a valid file name or not
while (!validName) {
try {
name = kb.next();
File n = new File(name); // new File object with the name user provided
if (n.exists()) { // check if a file with that name already exists
System.out.println("Error: There is an existing file called: " + name + ".");
System.out.println("That file already has a size of " + n.length() + " bytes");
// ask again
System.out.print("Please Enter another name for the output file:");
} else {
validName = true; // our flag to end our loop
} // close if-else
} catch (InputMismatchException e) {
kb.nextLine(); // catch remove junk
System.out.println("An error was encountered, please try again.");
} catch (Exception e) {
kb.nextLine(); // catch remove junk
System.out.println("An error was encountered with the file name you entered, please try again.");
}
} // close while loop
return name; // return the name of the file
} // close getOutputFileName() method
/**
* This method will return the number of lines a file contains. It will
* check if the file being passed to it exists and can be read
*
* @param f of the type File (object)
* @return number of lines of the type Int
*/
public static int getNumberOfRecords(File f) {
int nbLines = 0; // we will save our number of lines here
Scanner newFile = null; // declare our Scanner variable outside the try-catch block
if (!f.exists()) {
System.out.println("The file you are attempting to import does not exist.");
System.out.println("The program will now terminate. Goodbye");
System.exit(0);
} else {
try {
// create our new Scanner Object with Input File
System.out.println("\nAttempting to open file: " + f.getName());
newFile = new Scanner(new FileInputStream(f.getName()));
System.out.println("Detecting number of records in the file: " + f.getName());
while (newFile.hasNextLine()) {
newFile.nextLine();
nbLines++;
}
} catch (FileNotFoundException e) {
System.out.println("There was a problem with the file " + f.getName());
e.printStackTrace();
} catch (Exception e) {
System.out.println("There was an error reading from the file " + f.getName());
e.printStackTrace();
} finally {
newFile.close(); // close our file that we just opened
} // close try-catch-finally block
} // close if-else
System.out.println("The file " + f.getName() + " has " + nbLines + " records.");
return nbLines;
} // close getNumberOfRecords
/**
* This method will allow us to compare a Warship Object with an array of
* Warship Objects to see if there is a serial number that is duplicate. The
* comparison is only done on the serialNumber parameter. If a duplicate is found
* the method will inform the user of the record that is duplicate and ask the user
* to enter a new serial number for the duplicate record. It will verify if the newly
* provided serial number has not been previously used and re-prompt till the user provides
* a unique serial number for the record. The method will ensure that the object being passed
* to it is completely unique in the array of Warship objects
*
* @param a array of Warship Objects
* @param obj a warship object that we want to ensure has a unique serial number
*/
public static void fixDuplicateSerials(Warship[] a, Warship obj) {
long newSerial = 0;
int serialIndex = 0;
boolean isUnique = true;
// check to see if the object being passed exists
if (obj == null) {
System.out.println("Problem correcting duplicate serials. Warship does not exist.");
System.out.println("Program will now terminate. Goodbye.");
System.exit(0);
}
// let's run a loop and compare
for (int i = 0; i < a.length; i++) {
if (a[i] != obj && a[i].getSerialNumber() == obj.getSerialNumber()) {
isUnique = false; //there is a dupe!
while (!isUnique) {
System.out.print("Duplicate serial number "
+ obj.getSerialNumber()
+ " detected in record # " + (i + 1)
+ ". Please enter the correct serial number:");
newSerial = kb.nextLong();
// let's check if the newly entered serial also exists and
// if it does, let's throw an exception
try {
serialIndex = WarshipStaticMethods.findSerial(a, newSerial);
if (serialIndex != -1) {
throw new DuplicateSerialNumberException();
} else {
a[i].setSerialNumber(newSerial);
isUnique = true; //ok this serial s finally safe let's break our loop
}
} catch (DuplicateSerialNumberException e) {
System.out.println("Attempt of Duplicate Entry to a previous record.");
System.out.println("Initial appearance of serial number " + newSerial
+ " was found at record #: " + serialIndex + ".");
System.out.println(e.getMessage());
} //end try-catch
} //end while
} //end if
} // end for
}// end isSerialUnique()
/**
* This method will traverse a warship array and attempt to find a match on
* a provided serial number. If the serial number exists in any of the
* objects in the array, it will return the record number which contains the
* serial number. Otherwise, it will return -1 to indicate that the serial
* number was not found.
*
* @param a
* an array of Warship objects
* @param serial
* the serial number to find in the array of objects
* @return an integer as a result.
*/
public static int findSerial(Warship[] a, long serial) {
int result = -1;
for (int i = 0; i < a.length; i++) {
if (a[i].getSerialNumber() == serial) {
return i + 1;
}
}
return result;
}
/**
* This method will write to a PrintWriter output file in the format of the
* Warship input file. It will use the get methods in the warship objects
* and then write each attribute to the output file
*
* @param a
* an array of Warship Objects
* @param outputFile
* an object of the PrintWriter class (a file to write to)
*/
public static void writeToFile(Warship[] a, PrintWriter outputFile) {
// Serial No.; Name; Year; Owner_Country; Price; Speed (format to write)
for (int i = 0; i < a.length; i++) {
outputFile.println(a[i].getSerialNumber() + " " + a[i].getName()
+ " " + a[i].getYear() + " " + a[i].getCountry() + " "
+ a[i].getPrice() + " " + a[i].getSpeed());
}
}
/**
* This method will output the content of a Scanner file object onto the screen.
* It will read every line n an object and simply output it to the screen.
*
* @param in an object of the Scanner class (a file to read)
*/
public static void displayFile(Scanner in) {
while (in.hasNextLine()) { //to check for EOF
System.out.println(in.nextLine());
}
}
//methods used for part 2 below
/**
* This method will prompt user for new ships to be added to the mission. The user
* is given a choice to add as many ships as he/she wants. It will take an object of the
* class File, create a new PrintWriter with that object and then add new ships to it
*
* @param f Object of the class File
*/
public static void addRecords(File f){
// Serial No.; Name; Year; Owner_Country; Price; Speed
long serialNumber = 0;
String name = null, country = null;
int year = 0, speed = 0, counter = 0;
double price = 0;
boolean doneOuter = false;
boolean doneInner = false;
PrintWriter in = null;
try{
in = new PrintWriter(new FileOutputStream(f, true));
} catch (FileNotFoundException e){
System.out.println("There was a problem with the creation of PrintWriter object with file " + f.getName());
e.printStackTrace();
}
//outer loop checks if user wants to send new ships with a y or n
while (!doneOuter){
try{
System.out.println("Would you like to send new ships to missions? (y/n) ");
char response = kb.next().toUpperCase().charAt(0);
if(response == 'Y') //user wants to add ships
{
while (!doneInner) //the inner loop gives a choice to keep adding ships
{
System.out.println("Please enter new ship's serial number: ");
serialNumber = kb.nextLong();
System.out.println("Please enter the name of the ship: ");
name = kb.next();
System.out.println("Please enter the year " + name + " was built: ");
year = kb.nextInt();
System.out.println("Please enter the name of the country that owns " + name + ":");
country = kb.next();
System.out.println("Please enter the price (in dollars) of the " + name + ":");
price = kb.nextDouble();
System.out.println("Please enter the speed (in knots) of the " + name + ":");
speed = kb.nextInt();
//add our new ship to the file
in.println();
in.print(serialNumber + " " + name + " " + year + " " + country + " " + price + " " + speed);
in.flush(); //clear our buffer and write without closing our file
counter++; //increase the number of ships we added
System.out.println("Ship added.");
boolean exit = false;
while(!exit){ //ask user does he want to exit now?
System.out.println("Would you like to continue adding ships? (y/n)");
response = kb.next().toUpperCase().charAt(0);
if(response == 'Y'){
exit = true;
} else if (response == 'N'){
System.out.println("\n" + counter + " new ship(s) deployed.");
doneInner = true;
doneOuter = true;
exit = true;
} else {
System.out.println("\nPlease enter your answer with a 'y' or 'n' ");
} //end if-else
}//end While all the way inside
}//end while (Inner)
} else if(response == 'N'){
System.out.println("\nNo new ships have been added.");
doneOuter = true;
} else {
System.out.println("\nPlease respond with a 'y' or a 'n' only ");
}
} catch (InputMismatchException e){ //in case there's a mismatch on type and what user enters
System.out.println("There was an error capturing your input, please ensure " +
"that you are entering the value in the correct format");
System.out.println("Here is the expected format for each attribute of our ship: ");
System.out.println("Serial Number: long\n" +
"Year: Integer\n" +
"Price: Double\n" +
"Speed: Integer\n ");
System.out.println("Try entering your ships again.");
System.out.println("So far, " + counter + " ship(s) have been added to the file.");
System.out.println("Restarting program.");
} catch (Exception e){
System.out.println("An exception occured while carrying out the add problem");
e.printStackTrace();
} finally {
in.close();
} //end try-catch
} //end while (Outer)
}//end method
/**
* This method displays the content of the File Object being called using the BufferedReader class
*
* @param f and object of the File class
*/
public static void displayBufferedFile(File f){
BufferedReader in = null;
try {
in = new BufferedReader(new FileReader(f));
String line = null;
boolean eof = false;
System.out.println("\nHere is the content of our file containing ships out on missions: ");
System.out.println("==================================================================");
while(!eof) //while eof file is not reached
{
line = in.readLine();
if (line == null){ //did we reach the EOF?
eof = true;
} else {
System.out.println(line);
}
}
} catch (FileNotFoundException e){
System.out.println("There was a problem reading the file " + f.getName());
e.printStackTrace();
} catch (IOException e){
System.out.println("An error was encountered while reading from the file " + f.getName());
e.printStackTrace();
} finally { //close our bufferedReader file
try{
in.close();
} catch (IOException e){
System.out.println("There was a problem closing the file " + f.getName());
e.printStackTrace();
}
}
}//end displayBufferedFile method
/**
* This method allows one to create an array of warship objects based on the number
* being passed to it in the parameters. It also accepts a File which is passed
* as an Scanner object and the information in that file is used to fill the newly
* created array of Warship Objects.
*
* @param f Object of the class File
* @param n of the type Integer - indicates the length of the array
* @return an array of Warship objects
*/
public static Warship[] createFillArray(File f, int n){
Warship[] a = new Warship[n];
// use our FILE object to create a Scanner object now and read each line
// to create our warship objects
// Our file has a fixed format:
// Serial No.; Name; Year; Owner_Country; Price; Speed
Scanner myFile = null;
try {
myFile = new Scanner(new FileInputStream(f));
int i = 0; //this will be our local array index
System.out.println("\nCreating a temporary array from file " + f.getName() + " with " + n + " records.");
while (myFile.hasNextLine()) { //to check for EOF
//fill up our array
a[i] = new Warship(myFile.nextLong(), myFile.next(), myFile.nextInt(),
myFile.next(), myFile.nextDouble(), myFile.nextInt());
i++; //increment the index
}
} catch (FileNotFoundException e) {
System.out.println("There was an error creating the Scanner object from file " + f.getName());
e.printStackTrace();
} catch (InputMismatchException e) {
System.out.println("There was an error while reading from the file " + f.getName());
e.printStackTrace();
} catch (Exception e) {
System.out.println("An exception occured while filling up the array");
e.printStackTrace();
} finally {
myFile.close(); //close our inputFile
}
return a; //return our array
}
/**
* This method conducts a binary search on an array of objects of the class Warship.
* It tries to find the serial number provided in the parameters to see if the number belongs
* to any Warship object. For the binary search, the method looks for the key in a lower and
* upper end of the array, always splitting it in half and discarding the other half. It will return
* the index (if found) of the object that has the serial number being looked up along with the
* number of iterations the method had to do to find the key. It returns -1 as the index if the
* serial number is not found in the array.
*
* @param a an array of Warship objects
* @param key of the type long, this is the serial number that is being looked up
* @return an array of Integers. The number at index 0 represents the index of key (if found) and the
* number at index 1 represents the counter, or the number of loops it took the method
* to find the key being searched for.
*/
public static int[] binarySearch(Warship[] a, long key){
int low = 0, mid = 0, counter = 0, foundIndex = -1;
int high = a.length;
boolean found = false;
int[] result = new int[2];
while (low <= high && !found){
mid = (low + high)/2;
if (key == a[mid].getSerialNumber()){
foundIndex = mid;
found = true; //break out of the loop if we found a match
} else if (key < a[mid].getSerialNumber()) {
high = mid-1;
} else if (key > a[mid].getSerialNumber()){
low = mid+1;
}
counter++;
} //end while
result[0] = foundIndex; //the index where we found the search term
result[1] = counter; //our counter for the number of iterations
return result;
}
/**
* This method searches for a provided serial number in an array of Warship Objects.
* The search is conducted sequentially and an index value (-1 if not found) is returned
* in an array of integers along with the counter to show how many iterations of the loop
* were needed to find the searched index.
*
* @param a an array of Warship Objects
* @param key the key being searched for (of the type long for serial number)
* @return an array of integers. At index 0 is the index of the number being searched
* for if found. -1 is returned if the key is not found. At index 1 is the
* counter to show how many times the loop ran to find the key.
*/
public static int[] sequentialSearch(Warship[] a, long key){
int i = 0, counter = 0, foundIndex = -1;
boolean found = false;
int[] result = new int[2];
for (i = 0; i<a.length; i++){
if (a[i].getSerialNumber() == key){ //ah a match!
foundIndex = i;
found = true;
}
counter++;
if (found){break;} //break out of the loop if we found a match
}
result[0] = foundIndex; //return our index where we found it
result[1] = counter; //how many iterations?
return result;
} //end sequentialSearch()
/**
* This method takes a Warship array and writes every object to a binary file
* called Warships.dat
* @param a takes an array of Warship Objects
* @throws IOException
*/
public static void exportBinary(Warship[] a) throws IOException{
ObjectOutputStream binaryOut = new ObjectOutputStream(new FileOutputStream("Warships.dat"));
for (int i = 0; i<a.length; i++){
binaryOut.writeObject(a[i]);
}
binaryOut.close();
} //end exportBinary
/**
* This method allows us to output the display of a binary file with Warship Objects
* to the standard Output.
*
* @param f Object of the type File (the name of the file we want to read and display)
*/
public static void testBinary(File f){
try{
ObjectInputStream binaryIn = null;
binaryIn = new ObjectInputStream(new FileInputStream(f));
Warship warship = null;
int counter = 1;
System.out.println("Displaying all objects located in " + f.getName());
try{
while(true){
warship = (Warship) binaryIn.readObject();
System.out.println("Here is the informaton of the Warship #: " + counter++);
System.out.println(warship);
}
} catch (ClassNotFoundException e){
System.out.println("Error occured while reading from the file");
e.printStackTrace();
} catch (EOFException e){
System.out.println("End of File " + f.getName() + " reached, all objects have been displayed");
}
binaryIn.close(); //close our file
} catch (FileNotFoundException e){
e.printStackTrace();
} catch (IOException e){
e.printStackTrace();
}
} //end testBinary
}