/*   **********************************************************************  **
 **   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.util.CryptoManager;
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.swt.SWT;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
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 java.net.MalformedURLException;
import java.net.URL;

/**
 * Class displays a Dialog prompting for a username and a password. Will return
 * a BASE64 encoded inputValue that can be used to auth to a webserver.
 * 
 * @author <a href="mailto:bpasero@rssowl.org">Benjamin Pasero </a>
 * @version 1.2.3
 */
public class LoginDialog extends TitleAreaDialog {

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

  /** Divider between Protocol and Host */
  private static final String PROTOCOL_SEPARATOR = "://";

  /** Count number of opened dialogs */
  static int openDialogsCount = 0;

  private String dialogMessage;
  private Text domain;
  private String domainValue;
  private boolean isNtlm;
  private Text password;
  private String passwordValue;
  private String pathOrUrl;
  private Button saveData;
  private String title;
  private Text username;
  private String usernameValue;

  /**
   * Creates an input dialog with OK and Cancel buttons. Prompts for Username
   * Password and Domain (if Authentication is NTLM). 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 parentShell the parent shell
   * @param dialogTitle the dialog title, or <code>null</code> if none
   * @param dialogMessage the dialog dialogMessage, or <code>null</code> if
   * none
   * @param pathOrUrl The URL where the auth happens
   * @param isNtlm TRUE if required Authentication is NTLM (requires Domain)
   */
  public LoginDialog(Shell parentShell, String dialogTitle, String dialogMessage, String pathOrUrl, boolean isNtlm) {
    super(parentShell);
    this.pathOrUrl = pathOrUrl;
    this.title = dialogTitle;
    this.dialogMessage = dialogMessage;
    this.isNtlm = isNtlm;
  }

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

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

    return super.close();
  }

  /**
   * Get the entered Domain
   * 
   * @return String The entered domain
   */
  public String getDomain() {
    return domainValue;
  }

  /**
   * Get the entered password
   * 
   * @return String The entered password
   */
  public String getPassword() {
    return passwordValue;
  }

  /**
   * Get the entered username
   * 
   * @return String The entered username
   */
  public String getUsername() {
    return usernameValue;
  }

  /**
   * @see org.eclipse.jface.window.Window#open()
   */
  public int open() {
    openDialogsCount++;
    return super.open();
  }

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

    /** Set the inputValue if OK is pressed */
    if (buttonId == IDialogConstants.OK_ID) {
      usernameValue = username.getText();
      passwordValue = password.getText();

      /** NTLM Authentication requires Domain */
      if (isNtlm)
        domainValue = domain.getText();
    }

    /** Store Data in crypta if set so */
    if (buttonId == IDialogConstants.OK_ID && saveData.getSelection()) {
      String authValue = usernameValue + StringShop.AUTH_TOKENIZER + passwordValue;

      /** NTLM requires Domain */
      if (isNtlm && StringShop.isset(domainValue))
        authValue += StringShop.AUTH_TOKENIZER + domainValue;

      CryptoManager.getInstance().addItem(pathOrUrl, authValue);
    }

    /** Remove Data in crypta if set so */
    else if (buttonId == IDialogConstants.OK_ID && !saveData.getSelection())
      CryptoManager.getInstance().removeItem(pathOrUrl);

    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(title);
  }

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

    /** Override parent, DLU dependant margins */
    ((GridLayout) parent.getLayout()).marginHeight = 10;
    ((GridLayout) parent.getLayout()).marginWidth = 10;

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

      /** Create Buttons */
      createButton(parent, IDialogConstants.CANCEL_ID, GUI.i18n.getTranslation("BUTTON_CANCLE"), false).setFont(FontShop.dialogFont);
      createButton(parent, IDialogConstants.OK_ID, GUI.i18n.getTranslation("BUTTON_OK"), true).setFont(FontShop.dialogFont);
    } else {

      /** Create Buttons */
      createButton(parent, IDialogConstants.OK_ID, GUI.i18n.getTranslation("BUTTON_OK"), true).setFont(FontShop.dialogFont);
      createButton(parent, IDialogConstants.CANCEL_ID, GUI.i18n.getTranslation("BUTTON_CANCLE"), false).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(new GridLayout(2, false));
    composite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

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

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

    /** Spacer */
    new Label(composite, SWT.NONE);

    /** Host to authenticate to */
    Label hostLabel = new Label(composite, SWT.WRAP);
    hostLabel.setLayoutData(LayoutDataShop.createGridData(GridData.HORIZONTAL_ALIGN_BEGINNING, 1));
    hostLabel.setFont(FontShop.dialogFont);

    /** Try to parse as URL */
    try {
      URL url = new URL(pathOrUrl);
      StringBuffer hostLabelValue = new StringBuffer();

      /** Read Protocol */
      if (StringShop.isset(url.getProtocol()))
        hostLabelValue.append(url.getProtocol()).append(PROTOCOL_SEPARATOR);

      /** Read Host */
      hostLabelValue.append(url.getHost());

      /** Show Value */
      hostLabel.setText(hostLabelValue.toString());
    }

    /** URL not valid, just show it right the way */
    catch (MalformedURLException e) {
      hostLabel.setText(pathOrUrl);
    }

    /** Username Label */
    Label usernameLabel = new Label(composite, SWT.NONE);
    usernameLabel.setText(GUI.i18n.getTranslation("LABEL_USERNAME") + ": ");
    usernameLabel.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING));
    usernameLabel.setFont(FontShop.dialogFont);

    /** Username input field */
    username = new Text(composite, SWT.SINGLE | SWT.BORDER);
    username.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
    username.setFont(FontShop.dialogFont);
    username.setFocus();

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

    /** Password Label */
    Label passwordLabel = new Label(composite, SWT.NONE);
    passwordLabel.setText(GUI.i18n.getTranslation("LABEL_PASSWORD") + ": ");
    passwordLabel.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING));
    passwordLabel.setFont(FontShop.dialogFont);

    /** Password input field */
    password = new Text(composite, SWT.SINGLE | SWT.BORDER | SWT.PASSWORD);
    password.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
    password.setFont(FontShop.dialogFont);

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

    /** NTLM Domain Input Label */
    if (isNtlm) {
      Label domainLabel = new Label(composite, SWT.NONE);
      domainLabel.setText(GUI.i18n.getTranslation("LABEL_DOMAIN") + ": ");
      domainLabel.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING));
      domainLabel.setFont(FontShop.dialogFont);
    }

    /** NTLM Domain Input Field */
    if (isNtlm) {
      domain = new Text(composite, SWT.SINGLE | SWT.BORDER);
      domain.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
      domain.setFont(FontShop.dialogFont);

      /** Tweak Text Widget */
      WidgetShop.tweakTextWidget(domain);
    }

    /** Spacer */
    new Label(composite, SWT.NONE);

    /** Check to save username and password */
    saveData = new Button(composite, SWT.CHECK);
    saveData.setFont(FontShop.dialogFont);
    saveData.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING));
    saveData.setText(GUI.i18n.getTranslation("LABEL_REMEMBER_AUTH"));

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

    /** Spacer */
    new Label(sepHolder, SWT.NONE);

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

    /** Set Mnemonics to Buttons */
    WidgetShop.initMnemonics(new Button[] { saveData });

    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);

    /** The URL Label might need more space than 320 DLUs */
    int bestSizeWidth = getShell().computeSize(SWT.DEFAULT, SWT.DEFAULT).x;
    if (bestSizeWidth > bestSize.x)
      bestSize.x = bestSizeWidth;

    getShell().setSize(bestSize.x, bestSize.y);
    LayoutShop.positionShell(getShell(), true, openDialogsCount);
  }

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