/*   **********************************************************************  **
 **   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.panel;

import net.sourceforge.rssowl.controller.ChannelInfo;
import net.sourceforge.rssowl.controller.DisposeListenerImpl;
import net.sourceforge.rssowl.controller.EventManager;
import net.sourceforge.rssowl.controller.GUI;
import net.sourceforge.rssowl.controller.MenuManager;
import net.sourceforge.rssowl.controller.NewsTable;
import net.sourceforge.rssowl.controller.ViewForm;
import net.sourceforge.rssowl.model.Channel;
import net.sourceforge.rssowl.model.TabItemData;
import net.sourceforge.rssowl.model.TableData;
import net.sourceforge.rssowl.util.GlobalSettings;
import net.sourceforge.rssowl.util.shop.FontShop;
import net.sourceforge.rssowl.util.shop.LayoutShop;
import net.sourceforge.rssowl.util.shop.PaintShop;
import net.sourceforge.rssowl.util.shop.StringShop;

import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CTabItem;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;

import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Vector;

/**
 * The newsfeed panel is showing all news-title from the given Channel inside a
 * Table. A selection on a newstitle will open it inside the Newstext panel.
 * 
 * @author <a href="mailto:bpasero@rssowl.org">Benjamin Pasero </a>
 * @version 1.2.3
 */
public class NewsfeedPanel {
  private int[] columnWidths;
  private Composite newsHeaderHolderAll;
  private boolean performSearch;
  private Channel rssChannel;
  private String searchPattern;
  private String selectedNews;
  private String title;
  private String url;
  EventManager eventManager;
  GUI rssOwlGui;

  /**
   * Instantiate a new NewsfeedPanel
   * 
   * @param rssOwlGui The maincontroller
   * @param feedTabItem The tabitem this newsfeedpanel will be placed in
   * @param rssChannel The channel to display news from
   * @param url The URL of the newsfeed
   * @param title The Title of the newsfeed
   * @param searchPattern The search pattern that was used, if set
   * @param selectedNews The previous selected news, if set, to restore
   * selection
   * @param columnWidths The previoud column widths, if set, to restore them
   */
  public NewsfeedPanel(GUI rssOwlGui, CTabItem feedTabItem, Channel rssChannel, String url, String title, String searchPattern, String selectedNews, int[] columnWidths) {
    this.rssChannel = rssChannel;
    this.searchPattern = searchPattern;
    this.rssOwlGui = rssOwlGui;
    this.selectedNews = selectedNews;
    this.url = url;
    this.title = title;
    this.columnWidths = columnWidths;
    eventManager = rssOwlGui.getEventManager();
    performSearch = StringShop.isset(searchPattern);
    initComponents(feedTabItem);
  }

  /**
   * Get the newsfeed panel
   * 
   * @return Composite The newsfeed panel
   */
  public Composite getNewsfeedPanel() {
    return newsHeaderHolderAll;
  }

  /**
   * Create the popup that is shown when no news where found or are available to
   * display
   * 
   * @param control The control for the popup
   */
  private void createEmptyNewsPopup(Control control) {

    /** Popup menuStructure for the label */
    Menu labelMenu = new Menu(control);

    /** Add feed to favorits */
    MenuItem addFeedToFav = new MenuItem(labelMenu, SWT.NONE);
    rssOwlGui.getRSSOwlMenu().updateAccelerator(addFeedToFav, "BUTTON_ADDTO_FAVORITS", true, false);
    if (!GlobalSettings.isMac())
      addFeedToFav.setImage(PaintShop.iconAddToFavorites);
    addFeedToFav.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent e) {
        eventManager.actionAddToFavorites();
      }
    });

    /** Separator */
    new MenuItem(labelMenu, SWT.SEPARATOR);

    /** Not enabled */
    MenuItem markUnreadItem = new MenuItem(labelMenu, SWT.NONE);
    rssOwlGui.getRSSOwlMenu().updateAccelerator(markUnreadItem, "POP_MARK_UNREAD", false, false);
    markUnreadItem.setEnabled(false);

    /** Not enabled */
    MenuItem markAllReadItem = new MenuItem(labelMenu, SWT.NONE);
    rssOwlGui.getRSSOwlMenu().updateAccelerator(markAllReadItem, "POP_MARK_ALL_READ", false, false);
    markAllReadItem.setEnabled(false);

    /** Separator */
    new MenuItem(labelMenu, SWT.SEPARATOR);

    /** Reload newsfeed */
    MenuItem reloadFeed = new MenuItem(labelMenu, SWT.NONE);
    rssOwlGui.getRSSOwlMenu().updateAccelerator(reloadFeed, "MENU_RELOAD", false, false);
    if (!GlobalSettings.isMac())
      reloadFeed.setImage(PaintShop.iconReload);
    reloadFeed.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent e) {
        rssOwlGui.getRSSOwlNewsTabFolder().reloadFeed();
      }
    });

    /** Separator */
    new MenuItem(labelMenu, SWT.SEPARATOR);

    /** Search in feed */
    MenuItem searchFeed = new MenuItem(labelMenu, SWT.NONE);
    rssOwlGui.getRSSOwlMenu().updateAccelerator(searchFeed, "BUTTON_SEARCH", true, false);
    if (!GlobalSettings.isMac())
      searchFeed.setImage(PaintShop.iconFind);
    searchFeed.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent e) {
        rssOwlGui.getRSSOwlNewsTabFolder().searchInSelectedFeed();
      }
    });

    /** Separator */
    new MenuItem(labelMenu, SWT.SEPARATOR);

    /** Not enabled */
    MenuItem mailLinkToFriend = new MenuItem(labelMenu, SWT.NONE);
    rssOwlGui.getRSSOwlMenu().updateAccelerator(mailLinkToFriend, "POP_MAIL_LINK", false, false);
    if (!GlobalSettings.isMac())
      mailLinkToFriend.setImage(PaintShop.iconMail);
    mailLinkToFriend.setEnabled(false);

    /** Not enabled */
    MenuItem copyUrlItem = new MenuItem(labelMenu, SWT.NONE);
    rssOwlGui.getRSSOwlMenu().updateAccelerator(copyUrlItem, "POP_COPY_NEWS_URL", false, false);
    copyUrlItem.setEnabled(false);

    /** Separator */
    new MenuItem(labelMenu, SWT.SEPARATOR);

    /** Export */
    MenuItem exportItem = new MenuItem(labelMenu, SWT.CASCADE);
    exportItem.setText(GUI.i18n.getTranslation("BUTTON_EXPORT"));
    if (!GlobalSettings.isMac())
      exportItem.setImage(PaintShop.iconExport);
    exportItem.setEnabled(false);

    /** Separator */
    new MenuItem(labelMenu, SWT.SEPARATOR);

    /** Not enabled */
    MenuItem blogNews = new MenuItem(labelMenu, SWT.NONE);
    rssOwlGui.getRSSOwlMenu().updateAccelerator(blogNews, "POP_BLOG_NEWS", false, false);
    blogNews.setEnabled(false);

    /** Init the Mnemonics */
    MenuManager.initMnemonics(labelMenu);

    /** Apply menu */
    control.setMenu(labelMenu);
  }

  /**
   * Create a small info area on top of the newsheader table. This info area is
   * used after a search to GUI.display the search results and in case no news
   * are there to GUI.display.
   * 
   * @param parent The parent Composite of the info area
   * @param text The info text to GUI.display
   * @param url In case the URL is given, a toolitem will allow to close the
   * search and return to all items of the newsfed
   */
  private void createInfoArea(Composite parent, String text, final String url) {

    /** ViewForm header to GUI.display the info controls */
    ViewForm infoViewForm = new ViewForm(parent, SWT.BORDER);
    infoViewForm.set3DBorderState(false);
    infoViewForm.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));
    infoViewForm.setBackground(GUI.display.getSystemColor(SWT.COLOR_WHITE));

    /** Container for the left header */
    Composite infoViewFormHeaderLeft = new Composite(infoViewForm, SWT.NONE);
    infoViewFormHeaderLeft.setLayout(LayoutShop.createGridLayout(2, 5, 0, 5, 6, false));
    infoViewFormHeaderLeft.setBackground(GUI.display.getSystemColor(SWT.COLOR_WHITE));

    /** Info Icon */
    Label infoIcon = new Label(infoViewFormHeaderLeft, SWT.NONE);
    infoIcon.setImage(PaintShop.iconInfo);
    infoIcon.setBackground(GUI.display.getSystemColor(SWT.COLOR_WHITE));
    infoIcon.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, true));

    /** Info Label */
    Label infoLabel = new Label(infoViewFormHeaderLeft, SWT.WRAP);
    infoLabel.setFont(FontShop.textFont);
    infoLabel.setBackground(GUI.display.getSystemColor(SWT.COLOR_WHITE));
    infoLabel.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, true, true));

    /** Print a formatted message (localized) */
    infoLabel.setText(text);

    /** Apply to ViewForm */
    infoViewForm.setTopLeft(infoViewFormHeaderLeft, url == null);

    /** In case URL is given, show close button to return to the feed */
    if (url != null) {

      /** Container for the right header */
      Composite infoViewFormHeaderRight = new Composite(infoViewForm, SWT.NONE);
      infoViewFormHeaderRight.setLayout(LayoutShop.createGridLayout(1, 0, 0));
      infoViewFormHeaderRight.setBackground(GUI.display.getSystemColor(SWT.COLOR_WHITE));

      /** Search Toolbar */
      ToolBar searchBar = new ToolBar(infoViewFormHeaderRight, SWT.FLAT);
      searchBar.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, true));
      searchBar.setBackground(GUI.display.getSystemColor(SWT.COLOR_WHITE));

      /** Close search button and show all news again */
      ToolItem closeSearch = new ToolItem(searchBar, SWT.PUSH);
      closeSearch.setImage(PaintShop.loadImage("/img/icons/closesearch.gif"));
      closeSearch.setToolTipText(GUI.i18n.getTranslation("MENU_CLOSE"));
      closeSearch.addDisposeListener(DisposeListenerImpl.getInstance());
      closeSearch.addSelectionListener(new SelectionAdapter() {
        public void widgetSelected(SelectionEvent e) {
          eventManager.actionOpenFeed(url);
          rssOwlGui.getRSSOwlQuickview().clearLiveSearch();
        }
      });

      /** Apply to ViewForm */
      infoViewForm.setTopRight(infoViewFormHeaderRight, true);
    }
  }

  /**
   * Init the components of the newsfeed panel
   */
  private void initComponents(CTabItem feedTabItem) {

    /** Composite holding all elements in this tab */
    newsHeaderHolderAll = new Composite(rssOwlGui.getRSSOwlNewsTabFolder().getNewsHeaderTabFolder(), SWT.NONE);
    newsHeaderHolderAll.setLayout(LayoutShop.createGridLayout(1, 2, 2, 4, 0, true));
    newsHeaderHolderAll.setBackground(GUI.display.getSystemColor(SWT.COLOR_WHITE));

    /** Layout on Mac is different (Table draws no Border) */
    if (GlobalSettings.isMac()) {
      newsHeaderHolderAll.setLayout(LayoutShop.createGridLayout(1, 0, 0, 2, 0, true));
      ((GridLayout) newsHeaderHolderAll.getLayout()).marginTop = GlobalSettings.showChannelInfo ? 2 : 0;
    }

    /** User wants to see the channel info control */
    if (GlobalSettings.showChannelInfo && StringShop.isset(rssChannel.getTitle()))
      new ChannelInfo(GUI.display, newsHeaderHolderAll, rssChannel, eventManager);

    /** If search was performed */
    Hashtable newsItems = rssChannel.getItems();
    Vector newsItemOrder = rssChannel.getNewsItemOrder();
    if (performSearch) {
      newsItems = rssChannel.getSearchResultsItems();
      newsItemOrder = rssChannel.getSearchResultsItemOrder();
    }

    /** There are news to GUI.display */
    if (newsItemOrder.size() > 0) {

      /** Composite holding the Table that GUI.displays the news header */
      Composite newsHeaderTableHolder = new Composite(newsHeaderHolderAll, SWT.NONE);
      newsHeaderTableHolder.setLayout(LayoutShop.createGridLayout(1, 0, 0));
      newsHeaderTableHolder.setBackground(GUI.display.getSystemColor(SWT.COLOR_WHITE));
      newsHeaderTableHolder.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));

      /** Show a ViewForm with the number of search results and a close button */
      if (performSearch)
        createInfoArea(newsHeaderTableHolder, StringShop.printf(GUI.i18n.getTranslation("LABEL_SEARCH_RESULTS"), new String[] { "%TERM%", "%NUM%" }, new String[] { StringShop.escapeAmpersands(searchPattern), String.valueOf(rssChannel.getItemCount()) }) + ": ", url);

      /** Create a new table holding the news */
      NewsTable rssOwlNewsTable = new NewsTable(rssOwlGui, feedTabItem, eventManager);
      Table newsTable = rssOwlNewsTable.createNewsTable(newsHeaderTableHolder);

      /** Save table in tabitem */
      feedTabItem.setData(TabItemData.createFeedData(url, title, rssChannel, rssOwlNewsTable, newsTable));

      /** Check what infos are available for the news items */
      Vector newsItemInfos = rssChannel.getAvailableNewsItemInfos();

      /** Create the Table Columns */
      NewsTable.fillTableColumns(newsTable, newsItems, newsItemOrder, newsItemInfos, performSearch);

      /** Auto-Sort table if the settings tell so */
      if (GlobalSettings.autoSortNews) {
        ArrayList sortOrder = GlobalSettings.sortOrder;
        TableData tableData = (TableData) newsTable.getData();

        /** Go through sortOrder from beginning to end */
        for (int a = 0; a < sortOrder.size(); a++) {
          String sortOrderItem = (String) sortOrder.get(a);

          /** Sort Column if sortOrderItem is available */
          if (tableData.hasColumnSorter(sortOrderItem)) {

            /** Sort based on the given TableColumn */
            boolean ascending = tableData.getColumnSorter(sortOrderItem).sort(sortOrderItem);

            /** Show a Sort Indicator inside the selected TableColumn */
            if (!"TABLE_HEADER_STATUS".equals(sortOrderItem)) {
              newsTable.setSortColumn(tableData.getColumn(sortOrderItem));
              newsTable.setSortDirection(ascending ? SWT.UP : SWT.DOWN);
            }

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

            break;
          }
        }
      }

      /** Fill table with news - Use the existing column widhts */
      if (columnWidths != null && columnWidths.length == newsItemInfos.size())
        NewsTable.fillTable(newsTable, newsItems, newsItemOrder, newsItemInfos, performSearch, columnWidths);

      /** Fill table with news - Pack the table columns */
      else
        NewsTable.fillTable(newsTable, newsItems, newsItemOrder, newsItemInfos, performSearch);

      /** Restore last selected news if available */
      String key = "TABLE_HEADER_PUBDATE";
      if (selectedNews != null) {
        int itemCount = newsTable.getItemCount();
        for (int a = 0; a < itemCount; a++)
          if (newsTable.getItem(a).getText(1).equals(selectedNews)) {

            /** Only select but do not scroll item to visible */
            if (newsItemInfos.contains(key) && GlobalSettings.sortOrder.indexOf(key) == 0)
              newsTable.select(a);

            /** Select and scroll item to visible */
            else
              newsTable.setSelection(a);

            break;
          }
      }
    }

    /** No news are there to display */
    else {

      /** Save some data in TabItem */
      feedTabItem.setData(TabItemData.createFeedData(url, rssChannel.getTitle(), rssChannel, null, null));

      /** GUI.display that now news were found in the search */
      if (performSearch)
        createInfoArea(newsHeaderHolderAll, StringShop.printf(GUI.i18n.getTranslation("LABEL_SEARCH_EMPTY"), new String[] { "%TERM%" }, new String[] { StringShop.escapeAmpersands(searchPattern) }), url);

      /** GUI.display that now news were found in the feed at all */
      else
        createInfoArea(newsHeaderHolderAll, GUI.i18n.getTranslation("ERROR_NO_NEWS_FOUND"), null);

      /** Create a popup menu for this control */
      createEmptyNewsPopup(newsHeaderHolderAll);
    }
  }
}