import java.util.Comparator;

/**
 * Class for performing "instrumented" bubble sort.
 * (See source code at <a href="../source/BubbleSort.java">BubbleSort.java</a>.)
 */
public class BubbleSort extends Sorter {

    // ---- methods ----

    /**
     * Sorts array.
     * @param a array to sort (in compareTo orter)
     * @return counters showing number of comparisons and number of swaps
     */
    public static SortResult sort(Comparable[] a) {
        return sort(a, null);
    }

    /**
     * Sorts array.
     * @param a array to sort 
     * @param c comparator, or null to use array's compareTo method (in which 
     *   case its elements should be Comparable)
     * @return counters showing number of comparisons and number of swaps
     */
    public static SortResult sort(Object[] a, Comparator c) {
        Counters counters = new Counters();
        boolean sorted = false;
        for (int lastIndex = a.length-1; (lastIndex > 0) && !sorted; 
                --lastIndex) {
            sorted = true;
            for (int j = 0; j < lastIndex; ++j) {
                if (counters.compare(a[j], a[j+1], c) > 0) {
                    sorted = false;
                    counters.swap(a, j, j+1);
                }
            }
        }
        return new SortResult(counters.numCompares(), counters.numSwaps());
    }

    /**
     * Tests sort:
     *   Performs sort, tests result, and prints values of counters, preceded 
     *   by header message.
     * @param testName "test name" for header message
     * @param a array to sort
     * @param c comparator, or null to use compareTo
     */
    public static void testSort(String testName, Object[] a, Comparator c) {
        SortResult r = sort(a, c);
        printSortResult(testName, "bubble sort", a, c, r);
    }

    // ---- main method ----

    /**
     * Performs simple tests.
     * @param args command-line arguments -- data to sort, or none to use
     *   default data
     */
    public static void main(String[] args) {

        if (args.length < 1) {
            // Make some test data.
            args = new String[] {
                "hello", "bye", "HELLO", "abcd", "100", "!@#$" 
            };
        }

        // Make a comparator object to compare two Strings, ignoring case.
        Comparator ciCompare = new Comparator() {
            public int compare(Object o1, Object o2) {
                if ((o1 instanceof String) && (o2 instanceof String))
                    return ((String) o1).toUpperCase().compareTo(
                            ((String) o2).toUpperCase());
                else throw new ClassCastException();
            }
        };

        // Make "test names".
        String rName = "strings (regular)";
        String ciName = "strings (case-insensitive)";

        // Print test data.
        printArray("Input data:", args);

        // Try out sort.
        String[] copyOfData = (String[]) args.clone();
        System.out.println("");
        testSort(rName, copyOfData, null);
        printArray("Result:", copyOfData);
        testSort(ciName, copyOfData, ciCompare);
        printArray("Result:", copyOfData);
    }
}
