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

import net.sourceforge.rssowl.controller.thread.ImageLoader;
import net.sourceforge.rssowl.model.Channel;
import net.sourceforge.rssowl.model.ChannelImage;
import net.sourceforge.rssowl.util.DateParser;
import net.sourceforge.rssowl.util.GlobalSettings;
import net.sourceforge.rssowl.util.i18n.Dictionary;
import net.sourceforge.rssowl.util.shop.BrowserShop;
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.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.FocusAdapter;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Text;

import java.util.Locale;
import java.util.Vector;

/**
 * If a channel has some informations like title, language, url... the
 * ChannelInfo will display them in a Group that is clickable to expand it and
 * show all informations that are available.
 * 
 * @author <a href="mailto:bpasero@rssowl.org">Benjamin Pasero </a>
 * @version 1.2.3
 */
public class ChannelInfo {
  private boolean additionalFeedInfos;
  private MenuItem copyItem;
  private Menu linkMenu;
  private Composite newsChannelInfo;
  private Label newsFeedTitle;
  private Composite newsFeedTitleHolder;
  private Composite newsHeaderHolderAll;
  Display display;
  EventManager eventManager;
  ViewForm newsChannelHeader;
  Channel rssChannel;

  /**
   * Instantiate a new ChannlInfo widget
   * 
   * @param display The display
   * @param newsHeaderHolderAll The newsHeader holder
   * @param rssChannel A Channel
   * @param eventManager The event manager
   */
  public ChannelInfo(Display display, Composite newsHeaderHolderAll, Channel rssChannel, EventManager eventManager) {
    this.display = display;
    this.newsHeaderHolderAll = newsHeaderHolderAll;
    this.rssChannel = rssChannel;
    this.eventManager = eventManager;
    additionalFeedInfos = false;
    initComponents();
  }

  /** Init all components */
  private void initComponents() {

    /** Composite holding the Newschannel informations */
    newsChannelHeader = new ViewForm(newsHeaderHolderAll, SWT.BORDER | SWT.FLAT);
    newsChannelHeader.setBackground(display.getSystemColor(SWT.COLOR_WHITE));
    newsChannelHeader.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));

    /** Composite containing the title */
    newsFeedTitleHolder = new Composite(newsChannelHeader, SWT.NONE);
    newsFeedTitleHolder.setBackground(PaintShop.grayViewFormColor);
    newsFeedTitleHolder.setLayout(LayoutShop.createGridLayout(1, 0, 3));
    newsFeedTitleHolder.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
    newsFeedTitleHolder.setCursor(display.getSystemCursor(SWT.CURSOR_HAND));

    /** Popup the ViewForm if one clicks on the title holder of the news channel */
    newsFeedTitleHolder.addMouseListener(new MouseAdapter() {
      public void mouseDown(MouseEvent e) {

        /** Reveil / Hide control holding the channel info */
        setShowChannelInfos((newsChannelHeader.getContent() == null));
      }
    });

    /** Apply label holder to ViewForm */
    newsChannelHeader.setTopLeft(newsFeedTitleHolder, true);

    /** Title of the newsfeed - is clickable to reveal channel infos */
    newsFeedTitle = new Label(newsFeedTitleHolder, SWT.CENTER);
    newsFeedTitle.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, false));
    newsFeedTitle.setBackground(PaintShop.grayViewFormColor);
    newsFeedTitle.setFont(FontShop.textBoldFont);
    newsFeedTitle.setCursor(display.getSystemCursor(SWT.CURSOR_HAND));
    if (StringShop.isset(rssChannel.getTitle()))
      newsFeedTitle.setText(StringShop.escapeAmpersands(rssChannel.getTitle()));

    /** Composite holding the informations about the news channel */
    newsChannelInfo = new Composite(newsChannelHeader, SWT.NONE);
    newsChannelInfo.setLayout(LayoutShop.createGridLayout(2, 5, 5, false));
    newsChannelInfo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
    newsChannelInfo.setBackground(display.getSystemColor(SWT.COLOR_WHITE));
    newsChannelInfo.setVisible(false);

    /** Popup the ViewForm if one clicks on the title of the news channel */
    newsFeedTitle.addMouseListener(new MouseAdapter() {
      public void mouseDown(MouseEvent e) {

        /** Reveil / Hide control holding the channel info */
        setShowChannelInfos((newsChannelHeader.getContent() == null));
      }
    });

    /** Set the channel infos if available */
    setChannelInfos();

    /** Display information if no additional infos were available */
    if (!additionalFeedInfos) {
      Label noAddionalInfos = new Label(newsChannelInfo, SWT.NONE);
      noAddionalInfos.setBackground(display.getSystemColor(SWT.COLOR_WHITE));
      noAddionalInfos.setFont(FontShop.textFont);
      noAddionalInfos.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false, 2, 1));
      noAddionalInfos.setText(GUI.i18n.getTranslation("LABEL_NO_INFOS"));
    }
  }

  /**
   * Write all channel infos into the NewsChannel Info composite
   */
  private void setChannelInfos() {

    /** Try do display the RSS Channel Image */
    if (rssChannel.getImage() != null) {
      ChannelImage rssChannelImage = rssChannel.getImage();
      additionalFeedInfos = true;

      /** Use a CLabel to display the image */
      Label imgHolder = new Label(newsChannelInfo, SWT.CENTER);
      imgHolder.setBackground(display.getSystemColor(SWT.COLOR_WHITE));
      imgHolder.setLayoutData(new GridData(SWT.CENTER, SWT.BEGINNING, true, false, 2, 1));

      /** Thread to load the channel image */
      new ImageLoader(rssChannelImage, imgHolder, newsHeaderHolderAll).start();
    }

    /** Show the description for this news channel */
    if (StringShop.isset(rssChannel.getDescription())) {
      additionalFeedInfos = true;

      /** Label */
      Label newsFeedDescriptionLabel = new Label(newsChannelInfo, SWT.NONE);
      newsFeedDescriptionLabel.setBackground(display.getSystemColor(SWT.COLOR_WHITE));
      newsFeedDescriptionLabel.setFont(FontShop.textFont);
      newsFeedDescriptionLabel.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false));
      newsFeedDescriptionLabel.setText(GUI.i18n.getTranslation("LABEL_DESCRIPTION") + ": ");

      /** Text displaying the description */
      Text newsFeedDescription = new Text(newsChannelInfo, SWT.BORDER | SWT.READ_ONLY);
      newsFeedDescription.setBackground(display.getSystemColor(SWT.COLOR_WHITE));
      newsFeedDescription.setFont(FontShop.textFont);
      newsFeedDescription.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));
      newsFeedDescription.setText(rssChannel.getDescription());

      /** Remove selection on focus lost */
      newsFeedDescription.addFocusListener(new FocusAdapter() {
        public void focusLost(FocusEvent e) {
          ((Text) e.getSource()).setSelection(0);
        }
      });
    }

    /** Display the Link to the news feed if existing */
    if (StringShop.isset(rssChannel.getHomepage())) {
      additionalFeedInfos = true;

      /** Label */
      Label newsFeedHomepageLabel = new Label(newsChannelInfo, SWT.NONE);
      newsFeedHomepageLabel.setBackground(display.getSystemColor(SWT.COLOR_WHITE));
      newsFeedHomepageLabel.setFont(FontShop.textFont);
      newsFeedHomepageLabel.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false));
      newsFeedHomepageLabel.setText(GUI.i18n.getTranslation("CHANNEL_INFO_HOMEPAGE") + ": ");

      /** Text to display the newsfeed's homepage */
      final Text newsFeedHomepage = new Text(newsChannelInfo, SWT.READ_ONLY | SWT.BORDER);
      newsFeedHomepage.setBackground(display.getSystemColor(SWT.COLOR_WHITE));
      newsFeedHomepage.setForeground(PaintShop.linkColor);
      newsFeedHomepage.setFont(FontShop.textFont);
      newsFeedHomepage.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));
      newsFeedHomepage.setText(rssChannel.getHomepage());
      newsFeedHomepage.setCursor(display.getSystemCursor(SWT.CURSOR_HAND));
      newsFeedHomepage.setToolTipText(GUI.i18n.getTranslation("TOOLTIP_URLOPEN"));

      /** Remove selection on focus lost */
      newsFeedHomepage.addFocusListener(new FocusAdapter() {
        public void focusLost(FocusEvent e) {
          ((Text) e.getSource()).setSelection(0);
        }
      });

      /** Menu to copy or open the link external */
      linkMenu = new Menu(newsFeedHomepage);

      /** Copy link */
      copyItem = new MenuItem(linkMenu, SWT.NONE);
      copyItem.setText(GUI.i18n.getTranslation("POP_COPY"));
      if (!GlobalSettings.isMac())
        copyItem.setImage(PaintShop.iconCopy);
      copyItem.addSelectionListener(new SelectionAdapter() {
        public void widgetSelected(SelectionEvent e) {

          /** Selection is either a range of the text, or the complete url */
          String selection = (newsFeedHomepage.getSelectionCount() > 0) ? newsFeedHomepage.getSelectionText() : rssChannel.getHomepage();

          /** Copy selection to clipboard */
          eventManager.getClipBoard().setContents(new Object[] { selection }, new Transfer[] { TextTransfer.getInstance() });
        }
      });

      /** Offer the user the possibility to open the link external */
      if (GlobalSettings.useInternalBrowser() && !GlobalSettings.openBrowserExtern) {

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

        /** Open link in external browser */
        MenuItem openExternalItem = new MenuItem(linkMenu, SWT.NONE);
        openExternalItem.setText(GUI.i18n.getTranslation("POP_OPEN_EXTERN"));
        openExternalItem.addSelectionListener(new SelectionAdapter() {
          public void widgetSelected(SelectionEvent e) {
            if (StringShop.isset(rssChannel.getHomepage()))
              BrowserShop.openLink(rssChannel.getHomepage());
          }
        });
      }

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

      /** Apply menu to the newsFeedHomepage control */
      newsFeedHomepage.setMenu(linkMenu);

      /** URL openes after click on it */
      newsFeedHomepage.addMouseListener(new MouseAdapter() {

        /** Open link if selection is empty */
        public void mouseUp(MouseEvent e) {

          /** User has clicked on the link with not selecting it */
          if (e.button == 1 && newsFeedHomepage.getSelectionCount() == 0) {

            /** The homepage link is given */
            if (StringShop.isset(newsFeedHomepage.getText()))
              eventManager.actionOpenURL(rssChannel.getHomepage());
          }
        }
      });
    }

    /** Give out some additional informations in a Label */
    Vector newsChannelInfos = rssChannel.getAvailableNewsChannelInfos();

    /** For each additional channel info */
    for (int a = 0; a < newsChannelInfos.size(); a++) {
      additionalFeedInfos = true;

      /** Label */
      Label newsFeedInfoLabel = new Label(newsChannelInfo, SWT.NONE);
      newsFeedInfoLabel.setBackground(display.getSystemColor(SWT.COLOR_WHITE));
      newsFeedInfoLabel.setFont(FontShop.textFont);
      newsFeedInfoLabel.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false));
      newsFeedInfoLabel.setText(GUI.i18n.getTranslation((String) newsChannelInfos.get(a)) + ": ");

      /** Create a composite to display the info */
      Text newsFeedInfo = new Text(newsChannelInfo, SWT.READ_ONLY | SWT.BORDER);
      newsFeedInfo.setBackground(display.getSystemColor(SWT.COLOR_WHITE));
      newsFeedInfo.setFont(FontShop.textFont);
      newsFeedInfo.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));

      /** Channel Info: pubDate */
      if (newsChannelInfos.get(a).equals("CHANNEL_INFO_PUBDATE")) {

        /** Date was not found */
        if (rssChannel.getPubDateParsed() == null)
          newsFeedInfo.setText(rssChannel.getPubDate());

        /** Date was found */
        else
          newsFeedInfo.setText(DateParser.formatDate(rssChannel.getPubDateParsed(), true, true));
      }

      /** Channel Info: lastBuildDate */
      if (newsChannelInfos.get(a).equals("CHANNEL_INFO_LASTBUILDDATE")) {

        /** Date was not found */
        if (rssChannel.getLastBuildDateParsed() == null)
          newsFeedInfo.setText(rssChannel.getLastBuildDate());

        /** Date was found */
        else
          newsFeedInfo.setText(DateParser.formatDate(rssChannel.getLastBuildDateParsed(), true, true));
      }

      /** Channel Info: managingEditor */
      if (newsChannelInfos.get(a).equals("CHANNEL_INFO_MANAGINGEDITOR"))
        newsFeedInfo.setText(rssChannel.getManagingEditor());

      /** Channel Info: webmaster */
      if (newsChannelInfos.get(a).equals("CHANNEL_INFO_WEBMASTER"))
        newsFeedInfo.setText(rssChannel.getWebmaster());

      /** Channel Info: category */
      if (newsChannelInfos.get(a).equals("CHANNEL_INFO_CATEGORY"))
        newsFeedInfo.setText(rssChannel.getCategory());

      /** Channel Info: docs */
      if (newsChannelInfos.get(a).equals("CHANNEL_INFO_DOCS"))
        newsFeedInfo.setText(rssChannel.getDocs());

      /** Channel Info: time to live */
      if (newsChannelInfos.get(a).equals("CHANNEL_INFO_TTL"))
        newsFeedInfo.setText(rssChannel.getTtl());

      /** Channel Info: rss version */
      if (newsChannelInfos.get(a).equals("CHANNEL_INFO_RSSVERSION"))
        newsFeedInfo.setText(rssChannel.getFormat());

      /** Channel Info: publisher */
      if (newsChannelInfos.get(a).equals("CHANNEL_INFO_PUBLISHER"))
        newsFeedInfo.setText(rssChannel.getPublisher());

      /** Channel Info: language */
      if (newsChannelInfos.get(a).equals("CHANNEL_INFO_LANGUAGE")) {
        if (rssChannel.getLanguage().split("-").length == 2)
          newsFeedInfo.setText(new Locale(rssChannel.getLanguage().split("-")[0]).getDisplayLanguage(Dictionary.selectedLocale));
        else
          newsFeedInfo.setText(new Locale(rssChannel.getLanguage()).getDisplayLanguage(Dictionary.selectedLocale));
      }

      /** Channel Info: creator */
      if (newsChannelInfos.get(a).equals("CHANNEL_INFO_CREATOR"))
        newsFeedInfo.setText(rssChannel.getCreator());

      /** Channel Info: generator */
      if (newsChannelInfos.get(a).equals("CHANNEL_INFO_GENERATOR"))
        newsFeedInfo.setText(rssChannel.getGenerator());

      /** Channel Info: update period */
      if (newsChannelInfos.get(a).equals("CHANNEL_INFO_UPDATE_PERIOD")) {

        /** Also display the update frequency if available */
        if (rssChannel.getUpdateFrequency() != null)
          newsFeedInfo.setText(rssChannel.getUpdateFrequency() + " " + GUI.i18n.getTranslation("CHANNEL_INFO_UPDATE_FREQUENCY") + " (" + rssChannel.getUpdatePeriod() + ")");
        else
          newsFeedInfo.setText(rssChannel.getUpdatePeriod());
      }
    }

    /** Display the copyright informations of the news feed if existing */
    if (rssChannel.getCopyright() != null) {
      additionalFeedInfos = true;

      /** Label */
      Label newsFeedCopyrightLabel = new Label(newsChannelInfo, SWT.NONE);
      newsFeedCopyrightLabel.setBackground(display.getSystemColor(SWT.COLOR_WHITE));
      newsFeedCopyrightLabel.setFont(FontShop.textFont);
      newsFeedCopyrightLabel.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false));
      newsFeedCopyrightLabel.setText("Copyright: ");

      /** Control to display the copyright */
      Text newsFeedCopyright = new Text(newsChannelInfo, SWT.READ_ONLY | SWT.BORDER);
      newsFeedCopyright.setBackground(display.getSystemColor(SWT.COLOR_WHITE));
      newsFeedCopyright.setFont(FontShop.textFont);
      newsFeedCopyright.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false));
      newsFeedCopyright.setText(rssChannel.getCopyright());

      /** Remove selection on focus lost */
      newsFeedCopyright.addFocusListener(new FocusAdapter() {
        public void focusLost(FocusEvent e) {
          ((Text) e.getSource()).setSelection(0);
        }
      });
    }
  }

  /**
   * Set wether the control displaying the channel infos should be shown or
   * hidden
   * 
   * @param show TRUE if the channel info control should become visible
   */
  void setShowChannelInfos(boolean show) {

    /** Set / Remove content to ViewForm */
    newsChannelHeader.setContent((show == true) ? newsChannelInfo : null, true);

    /** Set visibility */
    newsChannelInfo.setVisible(show);

    /** Layout */
    newsChannelHeader.redraw();
    newsChannelHeader.update();
    newsChannelInfo.layout();
    newsHeaderHolderAll.layout();
  }
}