// SortingDemoAssertions2.java
// Demonstrates selection sort using file of short integers.
// Uses assertions to detect possible programmer errors.
//
// To compile this program in Java 1.4, type:
//    javac -source 1.4 SortingDemoAssertions2.java
// (Compile it normally in Java 1.5 or later.)
//
// To run this program with assertions enabled, type:
//    java -ea SortingDemoAssertions2
// (Otherwise, assertions are disabled.)


/**
 * Program which sorts the numbers in a text file
 * containing short integers, one number per line,
 * and then prints them to another text file whose
 * filename is the input file's name prefixed
 * by "sorted-".
 *
 * @author Dorothy L. Nixon
 */
public class SortingDemoAssertions2
{
   /**
    * Main method.
    *
    * @param args command-line arguments.
    *             Just one command-line argument
    *             is needed for the input file.
    */
   public static void main(String[] args)
   {
      final int MAX_NUMBER_OF_NUMBERS = 40;

      if ( args.length == 0 )
      {
         System.out.println("This program sorts short integers");
         System.out.println("from the file specified by a");
         System.out.println("command-line argument.");
         System.exit(0);
      } // if

      final String inputFileName = args[0];
      final String outputFileName = "sorted-" + inputFileName;

      short[] numbersArray = new short[MAX_NUMBER_OF_NUMBERS];

      // Read numbers into numbersArray from input file:
      int subArrayLength = inputFromFile(inputFileName, numbersArray);

      // Sort the numbers in ascending order:
      selectionSort(numbersArray, subArrayLength);

      // Write numbers in numbersArray to output file:
      outputToFile(outputFileName, numbersArray, subArrayLength);

      // Print message indicating successful completion:
      System.out.println("File " + outputFileName
                                 + " has been created.");
   }  // method main

   /**
    * Reads short integers from the specified
    * file to the specified array.  Returns the
    * number of numbers that have been read,
    * if successful.
    *
    * If the number of numbers in the file
    * exceeds the length of the array, then a 
    * user-friendly error message is printed
    * to the console, and the program is
    * terminated with error code 1.
    *
    * @param filename name of file containing
    *                 short integers, one per line.
    *                 The number of numbers in the
    *                 file is not known in advance.
    * @param numbers array into which numbers in 
    *                 the file are read.
    *
    * @return length of subarray of <code>numbers</code>
    *         containing actual numbers read from the file.
    */
   private static int inputFromFile(String filename,
                                    short[] numbers)
   {
      TextFileInput in = new TextFileInput(filename);

      // Read numbers into array:
      int lengthFilled = 0;
      String line = in.readLine();   // read first line in file
      while ( lengthFilled < numbers.length && line != null )
      {
         numbers[lengthFilled] = Short.parseShort(line);
         line = in.readLine();       // read next line in file
         lengthFilled++;
      } // while

      // Check to see if all the numbers in the file were read.
      // If not, then the array wasn't big enough to hold them all.
      // In that case, print an error message and quit.
      if ( line != null )            // i.e. if end-of-file not reached
      {
         System.out.println("File contains too many numbers.");
         System.out.println("This program can process only "
                             + numbers.length + " numbers.");
         System.exit(1);
      }  // if

      // Release file for re-use:
      in.close();

      return lengthFilled;
   }  // method inputFromFile

   /**
    * Writes short integers from the specified
    * subarray to the specified file.
    *
    * @param filename name of output file
    * @param numbers partially-filled array of short
    *                integers
    * @param lengthFilled length of subarray of
    *                <code>numbers</code> containing
    *                the numbers to be output to file
    */
   private static void outputToFile(String fileName,
                                    short[] numbers,
                                    int lengthFilled)
   {
      TextFileOutput out = new TextFileOutput(fileName);

      // Print numbers to output text file buffer:
      for ( int i = 0; i < lengthFilled; i++ )
         out.println(numbers[i]);

      // Make sure the output finds its way to the file:
      out.flush();

      // Release file for re-use:
      out.close();
   }  // method outputToFile

   /**
    * Sorts a partially-filled array of short
    * integers using selection sort.
    *
    * @param array the array to be sorted
    * @param length length of filled portion of array
    *               Must be between 0 and the length
    *               of <code>array</code>, inclusive.
    */
   private static void selectionSort(short[] array,
                                     int length)
   {
      // Does array exist?
      assert ( array != null ) : "parameter array is null";

      // Is length within range?
      assert ( length >= 0 && length <= array.length ) :
             "length " + length + " not in range [0, "
                       + array.length + "]";

      // Sort the array:
      for ( int i = 0; i < length - 1; i++ )
      {
         // Find the lowest-valued element in
         // the subarray from index i up to
         // index length - 1
         int indexLowest = i;
         for ( int j = i + 1; j < length; j++ )
            if ( array[j] < array[indexLowest] )
               indexLowest = j;

         // Put the lowest-valued element at
         // index i, swapping if necessary:
         if ( array[indexLowest] < array[i] )
         {
            short temp = array[indexLowest];
            array[indexLowest] = array[i];
            array[i] = temp;
         }
      }  // for i

      // Has the array been sorted successfully?
      assert ( isSorted(array, length) ): "Array not sorted.";
   }  // method selectionSort

   /**
    * Detects whether the specified subarray is sorted
    * in ascending order.
    *
    * @param array an array containing the subarray to be checked.
    *            Assume that the subarray starts at index 0.
    * @param length length of the subarray.
    *               Must be between 0 and the length
    *               of <code>array</code>, inclusive.
    */
   private static boolean isSorted(short[] array,
                                   int length)
   {
      // Does array exist?
      assert ( array != null ) : "parameter array is null";

      // Is length within range?
      assert ( length >= 0 && length <= array.length ) :
             "length " + length + " not in range [0, "
                       + array.length + "]";

      // If any element in the array is less than
      // the preceding element, then it is not sorted.
      // Otherwise, it is sorted.
      for ( int i = 1; i < length; i++ )
         if ( array[i] < array[i-1] )
            return false;
      return true;
   }  // method isSorted
}  // class SortingDemoAssertions2