/* 
 ______________________________________________________________________
 *
 * Copyright (c) 1996-2004 QUEST SOFTWARE INC.  All Rights Reserved.
 * http://java.quest.com
 *
 * This software is the confidential and proprietary information of
 * Quest Software Inc. ("Confidential Information").  You shall not disclose
 * such Confidential Information and shall use it only in accordance with the
 * terms of the license agreement you entered into with Quest Software.
 *
 * QUEST SOFTWARE MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY
 * OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
 * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
 * PURPOSE, OR NON-INFRINGEMENT. QUEST SOFTWARE SHALL NOT BE LIABLE FOR ANY
 * DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
 * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
 * ______________________________________________________________________
 */
//   RCSID -- $RCSfile: Sort.java,v $ $Revision: 1.2 $
//            $Date: 2006-03-17 21:13:34 $  $Locker:  $  Quest Software Inc.
// modified by max erdwien on november 6, 2013
// I fixed an error in how the comparator is called.
// The table DataView passed in is actually a TableMeta.
// TableMeta overrides some key methods, breaking this sort method.
// Basically, I manipulate the data to work with these overridden methods.
package usda.weru.wmrm;

import java.util.Arrays;
import java.util.Comparator;
import com.klg.jclass.table.*;

/**
 * Static methods to process column sorting.
 */
public class Sort {

    public static final int ASCENDING = 0;
    public static final int DESCENDING = 1;

    /**
     * Sorts a table by column and direction.
     * @param table
     * @param column
     * @param direction
     * @param comparator
     * @return 
     */
    public static boolean sortByColumn(JCTable table, int column,
            int direction, Comparator<Object> comparator) {
        return sortByColumn(table, column, direction, table.getFrozenRows(),
                table.getNumRows() - 1, comparator);
    }

    /**
     * Sorts a table by column and direction for a range of rows.
     * @param table
     * @param column
     * @param direction
     * @param start_row
     * @param end_row
     * @param comparator
     * @return 
     */
    public static boolean sortByColumn(JCTable table, int column, int direction,
            int start_row, int end_row,
            Comparator<Object> comparator) {
        int columns[] = {column};
        int directions[] = {direction};
        return sortByColumn(table, columns, directions,
                start_row, end_row, comparator);
    }

    /**
     * Sorts a table by multiple columns.
     * @param table
     * @param columns
     * @param directions
     * @param comparator
     * @return 
     */
    public static boolean sortByColumn(JCTable table, int columns[],
            int directions[], Comparator<Object> comparator) {
        return sortByColumn(table, columns, directions, table.getFrozenRows(),
                table.getNumRows() - 1, comparator);
    }

    /**
     * Sorts a table by multiple columns for a range of rows.
     * @param table
     * @param columns
     * @param directions
     * @param start_row
     * @param end_row
     * @param comparator
     * @return 
     */
    @SuppressWarnings("unchecked")
    public static boolean sortByColumn(JCTable table, int columns[],
            int directions[], int start_row, int end_row,
            Comparator<Object> comparator) {
        if (comparator == null) {
            comparator = new TableDataComparator();
        }

        DataViewModel dataView = table.getDataView();
        if (!(dataView instanceof SortableDataViewModel)) {
            throw new JCTableException(dataView + " does not support the "
                    + "SortableDataViewModel interface");
        }
        SortableDataViewModel sortableDataView = (SortableDataViewModel) dataView;

        int rows = table.getNumRows();

        if (start_row < 0) {
            start_row = 0;
        }
        if (end_row >= rows) {
            end_row = rows - 1;
        }

        ObjectComparator c = new ObjectComparator(sortableDataView.getDataSource(),
                columns, directions, comparator);
        // beginning of edited code
        Integer[] dataRowIndicies = new Integer[end_row - start_row + 1];
        for (int i = start_row; i < end_row + 1; i++) {
            dataRowIndicies[i - start_row] = (sortableDataView.getDataRow(i) - start_row);
        }
        synchronized (dataRowIndicies) {
            Arrays.sort(dataRowIndicies, 0, end_row - start_row + 1, c);
            Integer[] allIndicies = new Integer[rows];
            // add the header row indicies to allIndicies
            for (int i = 0; i < start_row; i++) {
                allIndicies[i] = (sortableDataView.getDataRow(i));
            }
            // add the data row indicies
            for (int i = start_row; i < end_row + 1; i++) {
                allIndicies[i] = dataRowIndicies[i - start_row] + start_row;
            }
/**
                 * Note:  Assertions are not enabled.  These will be useless items
                 * unless assertions are enabled.  Thus, they will be commented out unless
                 * the user wishes to enable specific assertions (feed the virtual machine 
                 * the -ea argument).
                 */
//            assert allIndicies.length == rows;
            int idx[] = new int[rows];
            for (int r = 0; r < rows; r++) {
                idx[r] = allIndicies[r].intValue();
            }
        // end of edited code
            // original version
        /*
             Integer[] o = new Integer[rows];
             for (int i = 0; i < rows; i++) {
             o[i] = new Integer(sortableDataView.getDataRow(i));
             }
             synchronized (o) {
             Arrays.sort(o, start_row, end_row + 1, c);
             int idx[] = new int[rows];
             for (int r = 0; r < rows; r++) {
             idx[r] = o[r].intValue();
             }
             */

            sortableDataView.setRowMap(idx);  // replaces the current array
        }

        return (true);
    }

} // Sort

class ObjectComparator implements Comparator<Object> {

    protected TableDataModel tableData;
    protected int[] columns;
    protected int[] directions;
    protected Comparator<Object> comparator;

    ObjectComparator(TableDataModel tableData, int[] columns, int[] directions,
            Comparator<Object> comparator) {
        this.tableData = tableData;
        this.columns = columns;
        this.directions = directions;
        this.comparator = comparator;
    }

    /**
     * A method that compares the provided object to the current object
     * @param o1 the first object to be compared.
     * @param o2 the second object to be compared.
     * @return 1 if o1 > o2, 0 if o1 == o2, -1 if o1 < o2
     */
    @Override
    public int compare(Object o1, Object o2) {
        int result = 0;
        for (int level = 0; level < columns.length && result == 0; level++) {
            int column = columns[level];
            Object item1 = tableData.getTableDataItem(((Integer) o1).intValue(),
                    column);
            Object item2 = tableData.getTableDataItem(((Integer) o2).intValue(),
                    column);
            result = comparator.compare(item1, item2);
            if (directions[level] == Sort.DESCENDING) {
                result = -result;
            }
        }
        return (result);
    }

} // ObjectComparator