Sorter.java

package org.troy.capstone.search_engine.sorting;

import java.util.List;

import org.troy.capstone.utils.TableUtils;

import tech.tablesaw.api.Row;
import tech.tablesaw.api.Table;

/**
 * The {@code Sorter} class provides a method to sort a {@code Table} based on a given {@code RowComparator}. It uses Insertion Sort for small tables (25 rows or fewer) and {@code QuickSort} for larger tables. The sorting is performed on a copy of the original table, ensuring that the original data remains unchanged.
 */
public class Sorter {

    /** Threshold for determining when to use {@code Insertion Sort} vs {@code Quick Sort}. If the number of rows is less than or equal to this threshold, {@code Insertion Sort} will be used; otherwise, {@code Quick Sort} will be used. */
    private static final int SORTING_THRESHOLD = 25;
    
    /** Only exists to prevent Jacoco from reporting this class as uncovered and from being instantiated */
    private Sorter() {}
 
    /**
     * Sorts the given table using the specified {@code RowComparator}. If the table has 25 rows or fewer, it uses {@code Insertion Sort}; otherwise, it uses {@code Quick Sort}.
     * 
     * @pre table is not null and contains the necessary columns for the comparator to function properly.
     * 
     * @post The returned table is a new {@code Table} instance that contains the same rows as the input table but sorted according to the order defined by the comparator. The original table remains unchanged.
     * 
     * @param table The {@code Table} to be sorted.
     * @param comparator The {@code RowComparator} that defines the sorting order. This is an Object to make it possible to pass a comparator from another class without the import of the {@code RowComparator} class.
     * @param time An optional {@code LongWrapper} to store the time taken to perform the sort. If null, time will not be recorded.
     * @return A new {@code Table} instance containing the sorted rows from the input table.
     */
    static Table sortTable(Table table, RowComparator comparator, LongWrapper time) {
        if( comparator == null ) {
            System.out.println("Invalid comparator provided to Sorter.sortTable. Was provided: " + comparator + ". Returning original table.");
            return table;
        }
        System.out.println("Sorting using " + comparator.toString() + " comparator...");
        List<Row> rows = TableUtils.tableToRowList(table);

        LongWrapper startTime = new LongWrapper();
        if( time != null )
            startTime = new LongWrapper(System.nanoTime());
        if (rows.size() <= SORTING_THRESHOLD)
            InsertionSort.insertionSort(rows, comparator);
        else
            QuickSort.quickSort(rows, comparator);
        if( time != null )
            time.setValue(System.nanoTime() - startTime.getValue());

        Table sortedTable = table.emptyCopy();
        rows.forEach(sortedTable::append);
        return sortedTable;
    }

    /** Helper method to perform a mixed sort using {@code Insertion Sort} for small lists and {@code Quick Sort} for larger lists, with time measurement. 
     * @pre comparator is a valid {@code RowComparator} that can compare the rows in the list. rows is not null and the rows contain the correct column needed to do the sorting.
     * @post The list of rows is sorted in place based on the order defined by the comparator, and the time taken for sorting is recorded in the provided {@code LongWrapper} if it is not null.
     * @param rows The list of rows to be sorted.
     * @deprecated This is useful for tests and analyzing time taken, but is not part of main program execution.
     * @param comparator The {@code RowComparator} used to determine the order of the rows.
     * @param time An optional {@code LongWrapper} to store the time taken to perform the sort. If null, time will not be recorded.
     */
    @Deprecated
    public static void mixedSort(List<Row> rows, RowComparator comparator, LongWrapper time) {
        mixedSort(rows, 0, rows.size() - 1, comparator, time);
    }

    /**
     * Sorts the rows based on the provided comparator and optionally records the time taken for sorting. Uses {@code Insertion Sort} for small lists and {@code Quick Sort} for larger lists.
      * 
      * @pre comparator is a valid {@code RowComparator} that can compare the rows in the list. rows is not null and the rows contain the correct column needed to do the sorting.
      * @post The list of rows is sorted in place based on the order defined by the comparator, and the time taken for sorting is recorded in the provided {@code LongWrapper} if it is not null.
      * 
      * @deprecated This is useful for tests and analyzing time taken, but is not part of main program execution.
      * 
      * @param rows The list of rows to be sorted.
      * @param comparator The {@code RowComparator} used to determine the order of the rows.
      * @param low The starting index of the portion of the list to be sorted.
      * @param high The ending index of the portion of the list to be sorted.
      * @param time An optional {@code LongWrapper} to store the time taken to perform the sort. If null, time will not be recorded.
     */
    @Deprecated
    private static void mixedSort(List<Row> rows, int low, int high, RowComparator comparator, LongWrapper time) {
        if( low >= high )
            return;
        long start = 0L;
        if( time != null )
            start = System.nanoTime();
        if (rows.size() <= SORTING_THRESHOLD)
            InsertionSort.insertionSort(rows, comparator);
        else{
            int pivot = QuickSort.partition(rows, low, high, comparator);
            mixedSort(rows, low, pivot - 1, comparator, null);
            mixedSort(rows, pivot + 1, high, comparator, null);
        }
        if (time != null)
            time.setValue(System.nanoTime() - start);
    }

    /** Overloaded method to allow calling sortTable without a {@code LongWrapper} for time measurement. 
     * 
     * @pre table is not null and contains the necessary columns for the comparator to function properly.
     * @post The returned {@code Table} is a new {@code Table} instance that contains the same rows as the input table but sorted according to the order defined by the comparator. The original table remains unchanged.
     * @param table The {@code Table} to be sorted.
     * @param comparator The {@code RowComparator} that defines the sorting order.
     * @return A new {@code Table} instance containing the sorted rows from the input table.
    */
    public static Table sortTable(Table table, RowComparator comparator) {
        LongWrapper time = new LongWrapper();
        Table sortedTable = sortTable(table, comparator, time);
        System.out.println("Sorting completed in " + time.getValue() + " nanoseconds.");
        return sortedTable;
    }

}