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

import net.sourceforge.rssowl.controller.DisposeListenerImpl;
import net.sourceforge.rssowl.controller.GUI;
import net.sourceforge.rssowl.controller.dialog.FavoriteDialog;
import net.sourceforge.rssowl.controller.dialog.SelectCategoryDialog;
import net.sourceforge.rssowl.controller.thread.FeedAutoUpdater;
import net.sourceforge.rssowl.model.Category;
import net.sourceforge.rssowl.model.Favorite;
import net.sourceforge.rssowl.util.shop.FontShop;
import net.sourceforge.rssowl.util.shop.LayoutDataShop;
import net.sourceforge.rssowl.util.shop.LayoutShop;
import net.sourceforge.rssowl.util.shop.PaintShop;
import net.sourceforge.rssowl.util.shop.ProxyShop;
import net.sourceforge.rssowl.util.shop.RegExShop;
import net.sourceforge.rssowl.util.shop.StringShop;
import net.sourceforge.rssowl.util.shop.WidgetShop;
import net.sourceforge.rssowl.util.shop.XMLShop;

import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.Clipboard;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
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.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;

import java.io.IOException;

/**
 * This property page allows to modify settings of the edited favorite
 * 
 * @author <a href="mailto:bpasero@rssowl.org">Benjamin Pasero </a>
 * @version 1.2.3
 */
public class EditFavoriteProperties extends FavoritePropertyPage {
  private Composite errorContainer;
  private Label errorIconLabel;
  private Label errorMessageLabel;
  private Group generalGroup;
  private ToolItem grabTitleButton;
  private boolean isEdit;
  Text inputCategory;
  Text inputTitle;
  Text inputUrl;

  /**
   * Instatiate a new EditFavoriteProperties PropertyPage
   * 
   * @param parent Composite's parent
   * @param rssOwlFavorite The favorite that is currently edited
   */
  public EditFavoriteProperties(Composite parent, Favorite rssOwlFavorite) {
    super(parent, rssOwlFavorite);
  }

  /**
   * Return an updated favorite from the given favorite and the settings the
   * user has made
   * 
   * @return Favorite The updated favorite containing all settings
   */
  public Favorite getUpdatedFavorite() {

    /** The updated favorite does not yet belong to a real category */
    Favorite updatedFavorite = new Favorite(inputUrl.getText(), inputTitle.getText(), null);

    /** Clone settings */
    rssOwlFavorite.clone(updatedFavorite);

    /** Set the catPath to implicitly specify the category */
    updatedFavorite.setCatPath((String) inputCategory.getData());

    return updatedFavorite;
  }

  /**
   * Set / unset the message on the Dialog.
   * 
   * @param message The Message to display.
   * @param isError If TRUE, show as error. Show warning otherwise.
   */
  public void setMessage(String message, boolean isError) {
    errorIconLabel.setImage(message == null ? null : isError ? PaintShop.iconError : PaintShop.iconWarning);
    errorIconLabel.redraw();
    errorIconLabel.update();
    errorMessageLabel.setText(message == null ? "" : message);
  }

  /**
   * @see net.sourceforge.rssowl.controller.properties.PropertyPage#initComponents()
   */
  protected void initComponents() {

    /** Indicator if an existing favorite is being edited */
    isEdit = FavoriteDialog.isEditFavorite;

    /** Group for general settings of the favorite */
    generalGroup = new Group(composite, SWT.NONE);
    generalGroup.setLayoutData(LayoutDataShop.createGridData(GridData.VERTICAL_ALIGN_BEGINNING | GridData.FILL_HORIZONTAL, 2));
    generalGroup.setText(GUI.i18n.getTranslation("GROUP_GENERAL"));
    generalGroup.setLayout(new GridLayout(3, false));
    generalGroup.setFont(FontShop.dialogFont);

    /** URL / Path Label */
    Label urlLabel = new Label(generalGroup, SWT.NONE);
    urlLabel.setText(GUI.i18n.getTranslation("LABEL_URL_PATH") + ": ");
    urlLabel.setLayoutData(LayoutDataShop.createGridData(GridData.HORIZONTAL_ALIGN_BEGINNING, 1));
    urlLabel.setFont(dialogFont);

    /** Input for the URL */
    inputUrl = new Text(generalGroup, SWT.SINGLE | SWT.BORDER);
    inputUrl.setLayoutData(LayoutDataShop.createGridData(GridData.FILL_HORIZONTAL, 2));
    inputUrl.setFont(dialogFont);
    inputUrl.setText(rssOwlFavorite.getUrl());
    inputUrl.setFocus();

    /** Select All if in Edit Mode */
    if (isEdit)
      inputUrl.selectAll();

    /** Check filling with Clipboard contents if in New Mode */
    else if (!StringShop.isset(rssOwlFavorite.getUrl())) {
      Clipboard cb = GUI.rssOwlGui.getEventManager().getClipBoard();
      TextTransfer transfer = TextTransfer.getInstance();
      String data = (String) cb.getContents(transfer);

      /** Data is a valid URL and not yet a Favorite already */
      data = (data != null) ? data.trim() : null;
      if (StringShop.isset(data) && !Category.linkExists(data)) {

        /** Replace any feed-Pseudoprotocol with the real one */
        data = StringShop.replaceAll(data, "feed://", "http://");

        /** Set it if its a valid URL now */
        if (RegExShop.isValidURL(data)) {
          inputUrl.setText(data);
          inputUrl.selectAll();
        }
      }
    }

    /** Tweak Text Widget */
    WidgetShop.tweakTextWidget(inputUrl);

    /** Validate input on each change */
    inputUrl.addModifyListener(new ModifyListener() {
      public void modifyText(ModifyEvent e) {
        validateInput();
      }
    });

    /** Title Label */
    Label titleLabel = new Label(generalGroup, SWT.NONE);
    titleLabel.setText(GUI.i18n.getTranslation("LABEL_TITLE") + ": ");
    titleLabel.setLayoutData(LayoutDataShop.createGridData(GridData.HORIZONTAL_ALIGN_BEGINNING, 1));
    titleLabel.setFont(dialogFont);

    /** Composite to hold title input and grab title button */
    Composite titleSelectHolder = new Composite(generalGroup, SWT.NONE);
    titleSelectHolder.setLayoutData(LayoutDataShop.createGridData(GridData.FILL_HORIZONTAL, 2));
    titleSelectHolder.setLayout(LayoutShop.createGridLayout(2, 0, 0));

    /** Title input field */
    inputTitle = new Text(titleSelectHolder, SWT.SINGLE | SWT.BORDER);
    inputTitle.setLayoutData(LayoutDataShop.createGridData(GridData.FILL_HORIZONTAL, 1));
    inputTitle.setFont(dialogFont);
    inputTitle.setText(rssOwlFavorite.getTitle());

    /** Tweak Text Widget */
    WidgetShop.tweakTextWidget(inputTitle);

    /** Validate input on each change */
    inputTitle.addModifyListener(new ModifyListener() {
      public void modifyText(ModifyEvent e) {
        validateInput();
      }
    });

    /** Grab title from newsfeed */
    ToolBar toolBar = new ToolBar(titleSelectHolder, SWT.FLAT);
    toolBar.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_END));
    grabTitleButton = new ToolItem(toolBar, SWT.PUSH);
    grabTitleButton.setImage(PaintShop.loadImage("/img/icons/grab_title.gif"));
    grabTitleButton.addDisposeListener(DisposeListenerImpl.getInstance());
    grabTitleButton.setToolTipText(GUI.i18n.getTranslation("TOOLTIP_GRAB_TITLE"));
    grabTitleButton.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent event) {

        /** Return if URL is not given */
        if (inputUrl.getText().equals(""))
          return;

        /** Reset status message */
        setMessage(null, false);

        /** Show wait cursor and load title from the URL */
        try {
          composite.getShell().setCursor(GUI.display.getSystemCursor(SWT.CURSOR_WAIT));
          String title = XMLShop.getTitleFromFeed(inputUrl.getText(), rssOwlFavorite.isUseProxy());

          /** Display warning if no title could be retrieved */
          if (title.equals("")) {
            setMessage(GUI.i18n.getTranslation("ERROR_GRABTITLE_FAILED"), true);
          }

          /** Set the title to the inputTitle field */
          else {
            inputTitle.setText(title);
            inputTitle.setFocus();
            inputTitle.selectAll();
          }
        }

        /** Show error */
        catch (IOException e) {
          setMessage(GUI.i18n.getTranslation("ERROR_CONNECTION_FAILED"), true);
        }

        /** Restore the normal cursor in any case */
        finally {
          composite.getShell().setCursor(null);
        }
      }
    });

    /** Category label */
    Label catLabel = new Label(generalGroup, SWT.NONE);
    catLabel.setText(GUI.i18n.getTranslation("LABEL_CATEGORY") + ": ");
    catLabel.setLayoutData(LayoutDataShop.createGridData(GridData.HORIZONTAL_ALIGN_BEGINNING, 1));
    catLabel.setFont(dialogFont);

    /** Composite to hold input for category and change button */
    Composite categorySelectHolder = new Composite(generalGroup, SWT.NONE);
    categorySelectHolder.setLayoutData(LayoutDataShop.createGridData(GridData.FILL_HORIZONTAL, 2));
    categorySelectHolder.setLayout(LayoutShop.createGridLayout(2, 0, 0));

    /** Text to select the category */
    inputCategory = new Text(categorySelectHolder, SWT.READ_ONLY | SWT.BORDER);
    inputCategory.setLayoutData(LayoutDataShop.createGridData(GridData.FILL_HORIZONTAL, 1));
    inputCategory.setFont(dialogFont);
    inputCategory.setText(rssOwlFavorite.getCatPath().replaceAll(StringShop.CAT_TOKENIZER, " | "));
    inputCategory.setData(rssOwlFavorite.getCatPath());

    /** Button to open a dialog for category selection */
    Button selectCategory = new Button(categorySelectHolder, SWT.NONE);
    selectCategory.setFont(dialogFont);
    selectCategory.setText(GUI.i18n.getTranslation("BUTTON_CHANGE") + "...");
    selectCategory.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_END));
    selectCategory.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent e) {

        /** Create a new select category dialog */
        SelectCategoryDialog selectCatDialog = new SelectCategoryDialog(parent.getShell(), GUI.i18n.getTranslation("DIALOG_TITLE_CATEGORY"));
        selectCatDialog.setCatPath((String) inputCategory.getData());

        /** If user has pressed OK, retrieve category path */
        if (selectCatDialog.open() == Window.OK) {
          inputCategory.setText((selectCatDialog.getCatPath() != null) ? selectCatDialog.getCatPath().replaceAll(StringShop.CAT_TOKENIZER, " | ") : "");
          inputCategory.setData((selectCatDialog.getCatPath() != null) ? selectCatDialog.getCatPath() : "");
          setMessage(null, false);
        }
      }
    });

    /** Container for the Error/Warning Labels */
    errorContainer = new Composite(generalGroup, SWT.NONE);
    errorContainer.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false, 3, 1));
    errorContainer.setLayout(LayoutShop.createGridLayout(2, 0, 0));

    /** Error / Warning Icon */
    errorIconLabel = new Label(errorContainer, SWT.NONE);

    /** Apply minimal Size for the Icon */
    GridData grid = new GridData(SWT.BEGINNING, SWT.CENTER, false, false);
    grid.widthHint = 16;
    grid.heightHint = 16;
    errorIconLabel.setLayoutData(grid);

    /** Error / Warning Message */
    errorMessageLabel = new Label(errorContainer, SWT.NONE);
    errorMessageLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
    errorMessageLabel.setFont(FontShop.dialogFont);

    /** Composite containing the two groups for update and misc. settings */
    Composite groupHolder = new Composite(composite, SWT.NONE);
    groupHolder.setLayoutData(LayoutDataShop.createGridData(GridData.FILL_HORIZONTAL, 2));
    groupHolder.setLayout(LayoutShop.createGridLayout(2, 0, 0, 5, 15, false));

    /** Group for the auto-reload components */
    Group autoReloadGroup = new Group(groupHolder, SWT.NONE);
    autoReloadGroup.setLayoutData(LayoutDataShop.createGridData(GridData.FILL_VERTICAL | GridData.HORIZONTAL_ALIGN_BEGINNING, 1));
    autoReloadGroup.setText(GUI.i18n.getTranslation("POP_AUTO_UPDATE"));
    autoReloadGroup.setLayout(LayoutShop.createGridLayout(1, 5, 5, 15, 0, false));
    autoReloadGroup.setFont(FontShop.dialogFont);

    /** Combo to select an auto-update interval */
    final Combo autoReloadCombo = new Combo(autoReloadGroup, SWT.READ_ONLY);
    autoReloadCombo.setFont(FontShop.dialogFont);
    autoReloadCombo.setVisibleItemCount(FeedAutoUpdater.updateInterval.length);
    autoReloadCombo.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent e) {

        /** Set update interval */
        rssOwlFavorite.setUpdateInterval(FeedAutoUpdater.updateInterval[autoReloadCombo.getSelectionIndex()]);
      }
    });

    /** For each supported auto update interval */
    int selectIndex = 0;
    for (int a = 0; a < FeedAutoUpdater.updateInterval.length; a++) {

      /** Add supported interval into Combo */
      autoReloadCombo.add(GUI.i18n.getTranslation(FeedAutoUpdater.updateIntervalNames[a]));

      /** Remember update-interval of current favorite */
      if (FeedAutoUpdater.updateInterval[a] == rssOwlFavorite.getUpdateInterval())
        selectIndex = a;
    }

    /** Select the interval of the current favorite */
    autoReloadCombo.select(selectIndex);

    /** Update on startup checkbutton */
    final Button reloadOnStartupCheck = new Button(autoReloadGroup, SWT.CHECK);
    reloadOnStartupCheck.setText(GUI.i18n.getTranslation("POP_UPDATE_ONSTARTUP"));
    reloadOnStartupCheck.setLayoutData(LayoutDataShop.createGridData(GridData.FILL_HORIZONTAL, 2));
    reloadOnStartupCheck.setFont(dialogFont);
    reloadOnStartupCheck.setSelection(rssOwlFavorite.isLoadOnStartup());
    reloadOnStartupCheck.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent e) {
        rssOwlFavorite.setLoadOnStartup(reloadOnStartupCheck.getSelection());
      }
    });

    /** Group holding the misc. settings */
    Group settingsGroup = new Group(groupHolder, SWT.NONE);
    settingsGroup.setLayoutData(LayoutDataShop.createGridData(GridData.FILL_VERTICAL | GridData.FILL_HORIZONTAL, 1));
    settingsGroup.setText(GUI.i18n.getTranslation("MENU_MISC"));
    settingsGroup.setLayout(new GridLayout());
    settingsGroup.setFont(FontShop.dialogFont);

    /** Open on startup checkbutton */
    final Button openOnStartupCheck = new Button(settingsGroup, SWT.CHECK);
    openOnStartupCheck.setLayoutData(LayoutDataShop.createGridData(GridData.FILL_HORIZONTAL, 1));
    openOnStartupCheck.setSelection(rssOwlFavorite.isOpenOnStartup());
    openOnStartupCheck.setText(GUI.i18n.getTranslation("POP_OPEN_STARTUP"));
    openOnStartupCheck.setFont(dialogFont);
    openOnStartupCheck.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent e) {
        rssOwlFavorite.setOpenOnStartup(openOnStartupCheck.getSelection());
      }
    });

    /** Use proxy checkbutton */
    final Button useProxyCheck = new Button(settingsGroup, SWT.CHECK);
    useProxyCheck.setLayoutData(LayoutDataShop.createGridData(GridData.FILL_HORIZONTAL, 1));
    useProxyCheck.setText(GUI.i18n.getTranslation("POP_USEPROXY"));
    useProxyCheck.setFont(dialogFont);
    useProxyCheck.setSelection(rssOwlFavorite.isUseProxy());
    useProxyCheck.setEnabled(ProxyShop.isUseProxy());
    useProxyCheck.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent e) {
        rssOwlFavorite.setUseProxy(useProxyCheck.getSelection());
      }
    });

    /** Validate Title if given */
    if (!rssOwlFavorite.getTitle().equals("") && !isEdit)
      validateInput();

    /** Set Mnemonics to Buttons */
    WidgetShop.initMnemonics(new Button[] { selectCategory, reloadOnStartupCheck, openOnStartupCheck, useProxyCheck });
  }

  /**
   * Validates the input.
   * <p>
   * The default implementation of this framework method delegates the request
   * to the supplied input validator object; if it finds the input invalid, the
   * warning dialogMessage is displayed in the dialog's dialogMessage line. This
   * hook method is called whenever the text changes in the input field.
   * </p>
   */
  protected void validateInput() {
    String warningMessage = null;

    /** Warning: URL of favorite is existing */
    if ((!isEdit || (!inputUrl.getText().equalsIgnoreCase(rssOwlFavorite.getUrl()))) && Category.linkExists(inputUrl.getText()))
      warningMessage = GUI.i18n.getTranslation("ERROR_FAV_URL_EXISTS");

    /** Warning: Title of favorite is existing */
    else if ((!isEdit || (!inputTitle.getText().equalsIgnoreCase(rssOwlFavorite.getTitle()))) && Category.titleExists(inputTitle.getText()))
      warningMessage = GUI.i18n.getTranslation("ERROR_FAV_TITLE_EXISTS");

    /** Reset warning dialogMessage */
    if (warningMessage == null)
      setMessage(null, false);

    /** Display warning dialogMessage */
    else
      setMessage(warningMessage, false);
  }
}