/*   **********************************************************************  **
 **   Copyright notice                                                       **
 **                                                                          **
 **   (c) 2003-2006 RSSOwl Development Team                                  **
 **   http://www.rssowl.org/                                                 **
 **                                                                          **
 **   All rights reserved                                                    **
 **                                                                          **
 **   This program and the accompanying materials are made available under   **
 **   the terms of the Eclipse Public License 1.0 which accompanies this     **
 **   distribution, and is available at:                                     **
 **   http://www.rssowl.org/legal/epl-v10.html                               **
 **                                                                          **
 **   A copy is found in the file epl-v10.html and important notices to the  **
 **   license from the team is found in the textfile LICENSE.txt distributed **
 **   in this package.                                                       **
 **                                                                          **
 **   This copyright notice MUST APPEAR in all copies of the file!           **
 **                                                                          **
 **   Contributors:                                                          **
 **     RSSOwl - initial API and implementation (bpasero@rssowl.org)         **
 **                                                                          **
 **  **********************************************************************  */

package net.sourceforge.rssowl.controller.sort;

import net.sourceforge.rssowl.controller.NewsTable;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;

import java.util.Collections;
import java.util.Comparator;
import java.util.Hashtable;
import java.util.Vector;

/**
 * SelectionAdapter implementing widgetSelected(...) to sort the table when a
 * header is clicked and update it.
 * 
 * @author <a href="mailto:masterludo@gmx.net">Ludovic Kim-Xuan Galibert </a>
 * @version 1.2.3
 */
public class SortingSelectionAdapter extends SelectionAdapter {

  /** Holds the flag for ascending order for the author column */
  private boolean authorAscending = true;

  /** Holds the flag for ascending order for the category column */
  private boolean categoryAscending = true;

  /** Holds the flag for ascending order for the newsfeed column */
  private boolean newsfeedAscending = true;

  /** Holds the identifiers for the info type */
  private Vector newsItemInfos;

  /** Holds the current ordering of the RSSNewsItems */
  private Vector newsItemOrder;

  /** Holds the Hashtable of RSSNewsItems */
  private Hashtable newsItems;

  /** Holds the flag for performing search */
  private boolean performSearch;

  /** Holds the flag for ascending order for the publisher column */
  private boolean publisherAscending = true;

  /** Holds the flag for ascending order for the publication date column */
  private boolean pudDateAscending = false;

  /** Holds the flag for ascending order for the status column */
  private boolean statusAscending = true;

  /** Holds the table where the RSSNewsItems will be displayed */
  private Table table;

  /** Holds the flag for ascending order for the title column */
  private boolean titleAscending = true;

  /**
   * Creates a new instance of SortingSelectionAdapter.
   * 
   * @param table the Table to fill.
   * @param newsItems the Hashtable of RSSNewsItems to be displayed.
   * @param newsItemOrder the ordering of the RSSNewsItems as keys to retrieve
   * the RSSNewsItems from the Hashtable.
   * @param newsItemInfos a vector of identifiers for the type of info.
   * @param performSearch true if a search should be performed, otherwise false.
   */
  public SortingSelectionAdapter(Table table, Hashtable newsItems, Vector newsItemOrder, Vector newsItemInfos, boolean performSearch) {
    this.table = table;
    this.newsItems = newsItems;
    this.newsItemOrder = newsItemOrder;
    this.newsItemInfos = newsItemInfos;
    this.performSearch = performSearch;
  }

  /**
   * Sort the News using a Sorter that is identified by the given field value.
   * 
   * @param field The identifier of the Sorter to use.
   * @return boolean TRUE if the sort was ascending, FALSE if descending.
   */
  public boolean sort(String field) {
    Comparator sorter = null;
    boolean ascending = true;

    /** Sort by news title */
    if ("TABLE_HEADER_NEWSTITLE".equals(field)) {
      ascending = this.titleAscending;
      this.titleAscending = !this.titleAscending;
      sorter = new TitleSorter();
    }

    /** Sort by publish date */
    else if ("TABLE_HEADER_PUBDATE".equals(field)) {
      ascending = this.pudDateAscending;
      this.pudDateAscending = !this.pudDateAscending;
      sorter = new PubDateSorter(newsItems);
    }

    /** Sort by author */
    else if ("TABLE_HEADER_AUTHOR".equals(field)) {
      ascending = this.authorAscending;
      this.authorAscending = !this.authorAscending;
      sorter = new AuthorSorter(newsItems);
    }

    /** Sort by category */
    else if ("TABLE_HEADER_CATEGORY".equals(field)) {
      ascending = this.categoryAscending;
      this.categoryAscending = !this.categoryAscending;
      sorter = new CategorySorter(newsItems);
    }

    /** Sort by publisher */
    else if ("TABLE_HEADER_PUBLISHER".equals(field)) {
      ascending = this.publisherAscending;
      this.publisherAscending = !this.publisherAscending;
      sorter = new PublisherSorter(newsItems);
    }

    /** Sort by news feed */
    else if ("TABLE_HEADER_FEED".equals(field)) {
      ascending = this.newsfeedAscending;
      this.newsfeedAscending = !this.newsfeedAscending;
      sorter = new NewsFeedSorter(newsItems);
    }

    /** Sort by news status */
    else if ("TABLE_HEADER_STATUS".equals(field)) {
      ascending = this.statusAscending;
      this.statusAscending = !this.statusAscending;
      sorter = new StatusSorter(newsItems);
    }

    /** Sort */
    if (null == sorter)
      Collections.sort(newsItemOrder);
    else
      Collections.sort(newsItemOrder, sorter);

    /** Reverse if not ascending order */
    if (!ascending)
      Collections.reverse(newsItemOrder);

    return ascending;
  }

  /**
   * Handle the sorting corresponding to the header clicked
   * 
   * @param se the SelectionEvent
   */
  public void widgetSelected(SelectionEvent se) {
    widgetSelected((TableColumn) se.getSource());
  }

  /**
   * Handle the sorting corresponding to the header clicked
   * 
   * @param tc The selected TableColumn
   */
  public void widgetSelected(TableColumn tc) {

    /** Sort based on the given TableColumn */
    boolean ascending = sort((String) tc.getData());

    /** Remember the width values of the columns */
    int columnCount = table.getColumnCount();
    int columnWidth[] = new int[columnCount];
    for (int a = 0; a < columnCount; a++)
      columnWidth[a] = table.getColumn(a).getWidth();

    /** Remember selected NewsItem if set */
    String selectedNews = null;
    if (table.getSelectionCount() > 0)
      selectedNews = table.getSelection()[0].getText(1);

    /** Show a Sort Indicator inside the selected TableColumn */
    if (!tc.getData().equals("TABLE_HEADER_STATUS")) {
      table.setSortColumn(tc);

      /** Reset Sort Direction */
      if (table.getSortDirection() != SWT.NONE)
        table.setSortDirection(SWT.NONE);

      /** Apply the new direction */
      table.setSortDirection(ascending ? SWT.UP : SWT.DOWN);

      /**
       * The Indicator requires some space, so pack the TableColumn. In order to
       * avoid flashing, first set the Table to redraw = false before packing.
       */
      table.setRedraw(false);
      tc.pack();
      table.setRedraw(true);

      /** Restore Focus if necessary */
      if (!table.isFocusControl())
        table.setFocus();

      /** Grant the sorted Column its preferred Width */
      int sortColumnIndex = table.indexOf(tc);
      if (columnWidth[sortColumnIndex] < tc.getWidth())
        columnWidth[sortColumnIndex] = tc.getWidth();
    }

    /** Do not show the Indicator in the first, narrow Column */
    else if (table.getSortColumn() != null) {
      table.setSortDirection(SWT.NONE);
      table.setSortColumn(null);
    }

    /** Remove All tableitems */
    table.removeAll();

    /** Create new, sorted table */
    NewsTable.fillTable(table, newsItems, newsItemOrder, newsItemInfos, performSearch, columnWidth);

    /** Restore last selected news if available */
    if (selectedNews != null) {
      int itemCount = table.getItemCount();
      for (int a = 0; a < itemCount; a++) {
        if (table.getItem(a).getText(1).equals(selectedNews)) {
          table.setSelection(a);
          break;
        }
      }
    }
  }
}