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

import net.sourceforge.rssowl.controller.GUI;
import net.sourceforge.rssowl.controller.thread.SettingsManager;
import net.sourceforge.rssowl.dao.Importer;
import net.sourceforge.rssowl.model.Category;
import net.sourceforge.rssowl.util.GlobalSettings;
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.StringShop;
import net.sourceforge.rssowl.util.shop.WidgetShop;

import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.IMessageProvider;
import org.eclipse.jface.dialogs.TitleAreaDialog;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.jdom.JDOMException;

import java.io.IOException;

/**
 * Dialog prompts for a OPML file to import favorites to RSSOwl from a Blogroll.
 * The list of newsfeeds from the Blogroll will synchronize with RSSOwl on
 * startup.
 * 
 * @author <a href="mailto:bpasero@rssowl.org">Benjamin Pasero </a>
 * @version 1.2.3
 */
public class BlogrollDialog extends TitleAreaDialog {

  /** Min. width of the dialog in DLUs */
  private static final int dialogMinWidth = 320;

  private String dialogTitle;
  private Text inputTitle;
  private Text inputUrl;
  private boolean isEdit;
  private GUI rssOwlGui;
  Category blogrollCategory;
  String dialogMessage;
  Button okButton;

  /**
   * Dialog is in "New Blogroll" Mode. Creates an input dialog with OK and
   * Cancel buttons. Prompts for a url / path and a title for a new blogroll.
   * Note that the dialog will have no visual representation (no widgets) until
   * it is told to open.
   * <p>
   * Note that the <code>open</code> method blocks for input dialogs.
   * </p>
   * 
   * @param rssOwlGui The Main Controller
   * @param parentShell the parent shell
   * @param dialogTitle the dialog title
   * @param dialogMessage the dialog dialogMessage
   */
  public BlogrollDialog(GUI rssOwlGui, Shell parentShell, String dialogTitle, String dialogMessage) {
    super(parentShell);
    this.rssOwlGui = rssOwlGui;
    this.dialogTitle = dialogTitle;
    this.dialogMessage = dialogMessage;
    isEdit = false;
  }

  /**
   * Dialog is in "Edit Blogroll" Mode. Creates an input dialog with OK and
   * Cancel buttons. Prompts for a url / path and a title for a new blogroll.
   * Note that the dialog will have no visual representation (no widgets) until
   * it is told to open.
   * <p>
   * Note that the <code>open</code> method blocks for input dialogs.
   * </p>
   * 
   * @param rssOwlGui The Main Controller
   * @param parentShell the parent shell
   * @param dialogTitle the dialog title
   * @param dialogMessage the dialog dialogMessage
   * @param blogrollCategory The existing blogroll to edit
   */
  public BlogrollDialog(GUI rssOwlGui, Shell parentShell, String dialogTitle, String dialogMessage, Category blogrollCategory) {
    super(parentShell);
    this.rssOwlGui = rssOwlGui;
    this.dialogTitle = dialogTitle;
    this.dialogMessage = dialogMessage;
    this.blogrollCategory = blogrollCategory;
    isEdit = true;
  }

  /**
   * @see org.eclipse.jface.dialogs.Dialog#close()
   */
  public boolean close() {

    /** Dispose dialogTitle image */
    getTitleImageLabel().getImage().dispose();

    return super.close();
  }

  /**
   * Try to import the OPML file. Shows an error in the Dialog if any exception
   * occurs.
   * 
   * @return boolean TRUE on success, FALSE on fail
   */
  private boolean importBlogroll() {

    /** Check changes to the Blogroll in case of an Edit */
    if (isEdit) {

      /** No change at all */
      if (blogrollCategory.getPathToBlogroll().equals(inputUrl.getText()) && blogrollCategory.getName().equals(inputTitle.getText()))
        return true;

      /** Only Change of Name */
      if (!blogrollCategory.getName().equals(inputTitle.getText()) && blogrollCategory.getPathToBlogroll().equals(inputUrl.getText())) {
        String title = StringShop.isset(inputTitle.getText()) ? inputTitle.getText() : inputUrl.getText();
        blogrollCategory.getParent().editCategory(blogrollCategory.getName(), title);

        /** Update Selection */
        GlobalSettings.selectedTreeItem = blogrollCategory.toCatPath();

        /** Build Tree */
        rssOwlGui.getRSSOwlFavoritesTree().buildFavoritesTree();

        /** Request Save of Settings */
        SettingsManager.getInstance().requestSave();

        /** Return Success */
        return true;
      }
    }

    /** Import Blogroll file into tree */
    try {
      getShell().setCursor(GUI.display.getSystemCursor(SWT.CURSOR_WAIT));
      String title = StringShop.isset(inputTitle.getText()) ? inputTitle.getText() : inputUrl.getText();
      Importer importer = new Importer(inputUrl.getText(), title, (blogrollCategory != null) ? blogrollCategory : Category.getRootCategory());
      importer.importNewsfeeds(true);

      /** Update Selection */
      GlobalSettings.selectedTreeItem = (blogrollCategory != null) ? blogrollCategory.toCatPath() + StringShop.CAT_TOKENIZER + title : title;

      /** Build Tree */
      rssOwlGui.getRSSOwlFavoritesTree().buildFavoritesTree();
      return true;
    } catch (IOException e) {
      setMessage(GUI.i18n.getTranslation("ERROR_FILE_NOT_FOUND"), IMessageProvider.ERROR);
    } catch (JDOMException e) {
      setMessage(e.getLocalizedMessage(), IMessageProvider.ERROR);
    } catch (IllegalArgumentException e) {
      setMessage(e.getLocalizedMessage(), IMessageProvider.ERROR);
    }

    /** Restore normal cursor */
    finally {
      getShell().setCursor(null);
    }

    /** Import failed */
    return false;
  }

  /**
   * @see org.eclipse.jface.dialogs.Dialog#buttonPressed(int)
   */
  protected void buttonPressed(int buttonId) {

    /** If OK was pressed, try to import the Blogroll file */
    if (buttonId != Window.OK || importBlogroll())
      super.buttonPressed(buttonId);
  }

  /**
   * @see org.eclipse.jface.window.Window#configureShell(org.eclipse.swt.widgets.Shell)
   */
  protected void configureShell(Shell shell) {
    super.configureShell(shell);

    /** On Mac do not set Shell Image since it will change the Dock Image */
    if (!GlobalSettings.isMac())
      shell.setImages(PaintShop.iconOwl);

    shell.setText(dialogTitle);
  }

  /**
   * @see org.eclipse.jface.dialogs.Dialog#createButtonsForButtonBar(org.eclipse.swt.widgets.Composite)
   */
  protected void createButtonsForButtonBar(Composite parent) {

    /** Button order on Mac is different */
    if (GUI.display.getDismissalAlignment() == SWT.RIGHT) {

      /** Create Cancel Button */
      createButton(parent, IDialogConstants.CANCEL_ID, GUI.i18n.getTranslation("BUTTON_CANCLE"), false).setFont(FontShop.dialogFont);

      /** Create OK Button */
      okButton = createButton(parent, IDialogConstants.OK_ID, GUI.i18n.getTranslation("BUTTON_OK"), true);
    } else {

      /** Create OK Button */
      okButton = createButton(parent, IDialogConstants.OK_ID, GUI.i18n.getTranslation("BUTTON_OK"), true);

      /** Create Cancel Button */
      createButton(parent, IDialogConstants.CANCEL_ID, GUI.i18n.getTranslation("BUTTON_CANCLE"), false).setFont(FontShop.dialogFont);
    }

    /** Set Focus to URL/Path input field */
    inputUrl.setFocus();

    /** Disable OK Button since input field is empty on open (if non-edit) */
    okButton.setEnabled(isEdit);
    okButton.setFont(FontShop.dialogFont);
  }

  /**
   * @see org.eclipse.jface.dialogs.Dialog#createDialogArea(org.eclipse.swt.widgets.Composite)
   */
  protected Control createDialogArea(Composite parent) {

    /** Composite to hold all components */
    Composite composite = new Composite((Composite) super.createDialogArea(parent), SWT.NONE);
    composite.setLayout(LayoutShop.createGridLayout(2, 5, 20));
    composite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

    /** Title Image */
    setTitleImage(PaintShop.loadImage("/img/icons/newsub_big.gif"));

    /** Title Message */
    setMessage(dialogMessage, IMessageProvider.INFORMATION);

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

    /** URL / Path input field */
    inputUrl = new Text(composite, SWT.SINGLE | SWT.BORDER);
    inputUrl.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
    inputUrl.setFont(FontShop.dialogFont);
    inputUrl.setText((blogrollCategory != null) ? blogrollCategory.getPathToBlogroll() : "");
    inputUrl.setFocus();

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

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

    /** Title label */
    Label titleLabel = new Label(composite, SWT.NONE);
    titleLabel.setText(GUI.i18n.getTranslation("LABEL_TITLE") + ": ");
    titleLabel.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING));
    titleLabel.setFont(FontShop.dialogFont);

    /** Title input field */
    inputTitle = new Text(composite, SWT.SINGLE | SWT.BORDER);
    inputTitle.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
    inputTitle.setFont(FontShop.dialogFont);
    inputTitle.setText((blogrollCategory != null) ? blogrollCategory.getName() : "");

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

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

    /** Holder for the separator to the OK and Cancel buttons */
    Composite sepHolder = new Composite(parent, SWT.NONE);
    sepHolder.setLayoutData(LayoutDataShop.createGridData(GridData.FILL_HORIZONTAL, 2));
    sepHolder.setLayout(LayoutShop.createGridLayout(1, 0, 0));

    /** Separator */
    Label separator = new Label(sepHolder, SWT.SEPARATOR | SWT.HORIZONTAL);
    separator.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

    return composite;
  }

  /**
   * @see org.eclipse.jface.window.Window#getShellStyle()
   */
  protected int getShellStyle() {
    int style = SWT.TITLE | SWT.BORDER | SWT.APPLICATION_MODAL | getDefaultOrientation();

    /** Follow Apple's Human Interface Guidelines for Application Modal Dialogs */
    if (!GlobalSettings.isMac())
      style |= SWT.CLOSE;

    return style;
  }

  /**
   * @see org.eclipse.jface.dialogs.Dialog#initializeBounds()
   */
  protected void initializeBounds() {
    super.initializeBounds();
    Point bestSize = getShell().computeSize(convertHorizontalDLUsToPixels(dialogMinWidth), SWT.DEFAULT);
    Point location = getInitialLocation(bestSize);
    getShell().setBounds(location.x, location.y, bestSize.x, bestSize.y);
  }

  /**
   * Set the layout data of the button to a GridData with appropriate widths
   * This method was slightly modified so that it is not setting a heightHint.
   * 
   * @param button The button to layout
   */
  protected void setButtonLayoutData(Button button) {
    GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
    int widthHint = convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH);
    data.widthHint = Math.max(widthHint, button.computeSize(SWT.DEFAULT, SWT.DEFAULT, true).x);
    button.setLayoutData(data);
  }

  /**
   * 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 errorMessage = null;

    /** If blogroll is already existing */
    if ((isEdit && !blogrollCategory.getPathToBlogroll().equals(inputUrl.getText())) || !isEdit) {
      if (Category.blogrollExists(inputUrl.getText()))
        errorMessage = GUI.i18n.getTranslation("ERROR_SUB_EXISTS");
    }

    /** If a category with that name is already existing */
    if ((isEdit && !blogrollCategory.getName().equals(inputTitle.getText())) || !isEdit) {
      if (Category.getRootCategory().getSubCategories().containsKey(inputTitle.getText()))
        errorMessage = GUI.i18n.getTranslation("ERROR_CAT_EXISTS");
    }

    /** Reset error dialogMessage */
    if (errorMessage == null) {
      setMessage(dialogMessage, IMessageProvider.INFORMATION);
      okButton.setEnabled(true);
    }

    /** Display error dialogMessage */
    else {
      setMessage(errorMessage, IMessageProvider.ERROR);
      okButton.setEnabled(false);
    }

    /** Input URL must have a value */
    if (inputUrl.getText().equals(""))
      okButton.setEnabled(false);
  }
}