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

import org.eclipse.swt.SWT;
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.graphics.Font;
import org.eclipse.swt.graphics.FontData;
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.FontDialog;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.List;

import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.SortedMap;

/**
 * Class displays a PropertyPage to set the Font and Encoding for RSSOwl
 * 
 * @author <a href="mailto:bpasero@rssowl.org">Benjamin Pasero </a>
 * @version 1.2.3
 */
public class FontProperties extends PropertyPage {
  private static final int DIALOG_FONT = 1;
  private static final int HEADER_FONT = 4;
  private static final int TABLE_FONT = 3;
  private static final int TEXT_FONT = 0;
  private static final int TREE_FONT = 2;

  /** Flag to indicate a possible font change */
  static boolean possibleFontChange = false;

  private Label catDescription;
  private Combo encodingsCombo;
  private Label fontHeightLabel;
  private Label fontNameLabel;
  private Label fontStyleLabel;
  private Group selectedFont;
  private FontData[] selectedFontData;
  List selectCatList;

  /**
   * Instatiate a new FontProperties PropertyPage
   * 
   * @param parent Composite's parent
   * @param rssOwlGui The MainController
   */
  public FontProperties(Composite parent, GUI rssOwlGui) {
    super(parent, rssOwlGui);
  }

  /**
   * Boolean flag to set if a font change has been made.
   * 
   * @param possibleFontChange TRUE if a possible font change happend.
   */
  public static void setPossibleFontChange(boolean possibleFontChange) {
    FontProperties.possibleFontChange = possibleFontChange;
  }

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

    /** Set the new fonts */
    if (possibleFontChange) {
      FontShop.textFont = propertyChangeManager.getTextFont();
      FontShop.dialogFont = propertyChangeManager.getDialogFont();
      FontShop.treeFont = propertyChangeManager.getTreeFont();
      FontShop.tableFont = propertyChangeManager.getTableFont();
      FontShop.headerFont = propertyChangeManager.getHeaderFont();
      FontShop.updateFonts();
      FontShop.setFontForAll(rssOwlGui);
      possibleFontChange = false;
    }

    /** Set the encoding */
    GlobalSettings.charEncoding = propertyChangeManager.getSelectedEncoding();

    updatePropertiesChangeManager();
  }

  /**
   * @see net.sourceforge.rssowl.controller.properties.PropertyPage#updatePropertiesChangeManager()
   */
  public void updatePropertiesChangeManager() {
    saveFontData();
    propertyChangeManager.setSelectedEncoding(encodingsCombo.getText());
  }

  /**
   * Display informations about a selected font
   * 
   * @param font Selected font
   */
  private void creteSelectedFontGroup(Font font) {

    /** Show default font if font is null */
    if (font == null) {
      creteSelectedFontGroup(FontShop.getFontData()[0]);
      selectedFontData = FontShop.getFontData();
    } else {
      creteSelectedFontGroup(font.getFontData()[0]);
      selectedFontData = font.getFontData();
    }
  }

  /**
   * Write informations about the given Font
   * 
   * @param fontData Describes the selected font
   */
  private void creteSelectedFontGroup(FontData fontData) {

    /** Informations */
    String name = fontData.getName();
    String height = String.valueOf(fontData.getHeight());
    String style = "-";

    int styleInt = fontData.getStyle();

    if (styleInt == SWT.BOLD)
      style = GUI.i18n.getTranslation("FONT_STYLE_BOLD");
    else if (styleInt == SWT.ITALIC)
      style = GUI.i18n.getTranslation("FONT_STYLE_ITALIC");
    else if (styleInt == SWT.NORMAL)
      style = GUI.i18n.getTranslation("FONT_STYLE_NORMAL");

    fontNameLabel.setText(name);
    fontHeightLabel.setText(height);
    fontStyleLabel.setText(style);

    selectedFont.layout();
  }

  /** Save selected fontdata to property change manager */
  private void saveFontData() {
    Font newFont;

    /** Create Font from selected FontData */
    if (selectedFontData != null)
      newFont = new Font(GUI.display, selectedFontData);

    /** Use default font */
    else
      newFont = FontShop.createFont();

    /** Set Font for selected font area */
    switch (selectCatList.getSelectionIndex()) {
      case TEXT_FONT:
        propertyChangeManager.setTextFont(newFont);
        break;

      case DIALOG_FONT:
        propertyChangeManager.setDialogFont(newFont);
        break;

      case TREE_FONT:
        propertyChangeManager.setTreeFont(newFont);
        break;

      case TABLE_FONT:
        propertyChangeManager.setTableFont(newFont);
        break;

      case HEADER_FONT:
        propertyChangeManager.setHeaderFont(newFont);
        break;
    }
  }

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

    /** Group for a category to choose */
    Group selectCategory = new Group(composite, SWT.NONE);
    selectCategory.setText(GUI.i18n.getTranslation("GROUP_FONT_AREA"));
    selectCategory.setLayoutData(LayoutDataShop.createGridData(GridData.FILL_HORIZONTAL, 2));
    selectCategory.setLayout(new GridLayout(2, true));
    selectCategory.setFont(FontShop.dialogFont);

    /** Chose a font category */
    selectCatList = new List(selectCategory, SWT.SINGLE | SWT.BORDER);
    selectCatList.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
    selectCatList.setFont(dialogFont);
    selectCatList.add(GUI.i18n.getTranslation("FONT_AREA_TEXT"));
    selectCatList.add(GUI.i18n.getTranslation("FONT_AREA_DIALOG"));
    selectCatList.add(GUI.i18n.getTranslation("FONT_AREA_TREE"));
    selectCatList.add(GUI.i18n.getTranslation("FONT_AREA_TABLE"));
    selectCatList.add(GUI.i18n.getTranslation("FONT_AREA_HEADER"));
    selectCatList.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent e) {
        handleListSelect();
      }
    });
    selectCatList.setSelection(0);

    /** Select Font on Double-Click */
    selectCatList.addMouseListener(new MouseAdapter() {
      public void mouseDoubleClick(MouseEvent e) {
        if (selectCatList.getSelectionCount() > 0)
          selectFont();
      }
    });

    /** Font category description */
    catDescription = new Label(selectCategory, SWT.WRAP);
    catDescription.setFont(dialogFont);
    catDescription.setLayoutData(new GridData(GridData.FILL_BOTH));

    /** Group holding informations about selected font */
    selectedFont = new Group(composite, SWT.NONE);
    selectedFont.setText(GUI.i18n.getTranslation("GROUP_SELECTED_FONT"));
    selectedFont.setFont(dialogFont);
    selectedFont.setLayoutData(LayoutDataShop.createGridData(GridData.FILL_HORIZONTAL, 2));
    selectedFont.setLayout(new GridLayout(2, false));
    selectedFont.setFont(FontShop.dialogFont);

    /** Font-Information: Name */
    Label nameLabel = new Label(selectedFont, SWT.NONE);
    nameLabel.setText(GUI.i18n.getTranslation("LABEL_NAME") + ": ");
    nameLabel.setFont(dialogFont);

    fontNameLabel = new Label(selectedFont, SWT.NONE);
    fontNameLabel.setFont(dialogFont);

    /** Font-Information: Height */
    Label heightLabel = new Label(selectedFont, SWT.NONE);
    heightLabel.setText(GUI.i18n.getTranslation("LABEL_SIZE") + ": ");
    heightLabel.setFont(dialogFont);

    fontHeightLabel = new Label(selectedFont, SWT.NONE);
    fontHeightLabel.setFont(dialogFont);

    /** Font-Information: Style */
    Label styleLabel = new Label(selectedFont, SWT.NONE);
    styleLabel.setText(GUI.i18n.getTranslation("LABEL_STYLE") + ": ");
    styleLabel.setFont(dialogFont);

    fontStyleLabel = new Label(selectedFont, SWT.NONE);
    fontStyleLabel.setFont(dialogFont);

    /** Select a new font */
    GridData gridData = new GridData(GridData.HORIZONTAL_ALIGN_END);
    gridData.grabExcessHorizontalSpace = true;
    gridData.horizontalSpan = 2;

    /** Composite to hold the buttons */
    Composite buttonHolder = new Composite(selectedFont, SWT.NONE);
    buttonHolder.setLayoutData(gridData);
    buttonHolder.setLayout(new GridLayout(2, false));

    /** Select the default system font */
    Button selectDefaultFont = new Button(buttonHolder, SWT.NONE);
    selectDefaultFont.setText(GUI.i18n.getTranslation("LABEL_USE_SYSTEM_FONT"));
    selectDefaultFont.setFont(dialogFont);
    selectDefaultFont.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent e) {
        selectDefaultFont();
        possibleFontChange = true;
      }
    });

    /** Select a font... */
    Button selectFontButton = new Button(buttonHolder, SWT.NONE);
    selectFontButton.setText(GUI.i18n.getTranslation("BUTTON_CHANGE_FONT") + "...");
    selectFontButton.setFont(dialogFont);
    selectFontButton.addSelectionListener(new SelectionAdapter() {
      public void widgetSelected(SelectionEvent e) {
        selectFont();
      }
    });

    /** Group holding the encoding */
    Group encodingGroup = new Group(composite, SWT.NONE);
    encodingGroup.setLayoutData(LayoutDataShop.createGridData(GridData.FILL_HORIZONTAL, 2));
    encodingGroup.setText(GUI.i18n.getTranslation("MENU_ENCODING"));
    encodingGroup.setLayout(new GridLayout(2, false));
    encodingGroup.setFont(FontShop.dialogFont);

    /** Select encoding */
    Label selectEncoding = new Label(encodingGroup, SWT.NONE);
    selectEncoding.setText(GUI.i18n.getTranslation("LABEL_SELECT_ENCODING") + ": ");
    selectEncoding.setFont(dialogFont);

    encodingsCombo = new Combo(encodingGroup, SWT.READ_ONLY);
    encodingsCombo.setFont(dialogFont);

    /** Fill combo with all supported encodings */
    SortedMap encodings = Charset.availableCharsets();
    Iterator encodingsIt = encodings.keySet().iterator();
    while (encodingsIt.hasNext()) {

      String encoding = (String) encodingsIt.next();
      encodingsCombo.add(encoding);

      if (encoding.equals(propertyChangeManager.getSelectedEncoding()))
        encodingsCombo.select(encodingsCombo.getItemCount() - 1);
    }

    /** Select first item in list */
    handleListSelect();

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

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

    /** Restore default fonts */
    propertyChangeManager.setTextFont(FontShop.createFont(GUI.display.getSystemFont().getFontData()[0].getHeight() + 1));
    propertyChangeManager.setDialogFont(FontShop.createFont());
    propertyChangeManager.setTreeFont(FontShop.createFont());
    propertyChangeManager.setTableFont(FontShop.createFont());
    propertyChangeManager.setHeaderFont(FontShop.createFont(GUI.display.getSystemFont().getFontData()[0].getHeight() + 1));

    /** Restore selected font area */
    switch (selectCatList.getSelectionIndex()) {
      case TEXT_FONT:
        selectedFontData = FontShop.getFontData(GUI.display.getSystemFont().getFontData()[0].getHeight() + 1);
        saveFontData();
        creteSelectedFontGroup(selectedFontData[0]);
        break;

      case DIALOG_FONT:
        selectedFontData = FontShop.getFontData();
        saveFontData();
        creteSelectedFontGroup(GUI.display.getSystemFont().getFontData()[0]);
        break;

      case TREE_FONT:
        selectedFontData = FontShop.getFontData();
        saveFontData();
        creteSelectedFontGroup(GUI.display.getSystemFont().getFontData()[0]);
        break;

      case TABLE_FONT:
        selectedFontData = FontShop.getFontData();
        saveFontData();
        creteSelectedFontGroup(GUI.display.getSystemFont().getFontData()[0]);
        break;

      case HEADER_FONT:
        selectedFontData = FontShop.getFontData(GUI.display.getSystemFont().getFontData()[0].getHeight() + 1);
        saveFontData();
        creteSelectedFontGroup(selectedFontData[0]);
        break;
    }

    /** Restore default encoding */
    int itemCount = encodingsCombo.getItemCount();
    for (int a = 0; a < itemCount; a++)
      if (encodingsCombo.getItem(a).equals("UTF-8"))
        encodingsCombo.select(a);

    /** Default encoding */
    propertyChangeManager.setSelectedEncoding(encodingsCombo.getText());

    /** Reselect list item */
    handleListSelect();
    possibleFontChange = true;
  }

  /** Perform action when the list is selected */
  void handleListSelect() {
    switch (selectCatList.getSelectionIndex()) {

      /** Font area: Text */
      case TEXT_FONT:
        catDescription.setText(GUI.i18n.getTranslation("FONT_AREA_TEXT_DESCRIPTION"));
        creteSelectedFontGroup(propertyChangeManager.getTextFont());
        break;

      /** Font area: Dialog */
      case DIALOG_FONT:
        catDescription.setText(GUI.i18n.getTranslation("FONT_AREA_DIALOG_DESCRIPTION"));
        creteSelectedFontGroup(propertyChangeManager.getDialogFont());
        break;

      /** Font area: Tree */
      case TREE_FONT:
        catDescription.setText(GUI.i18n.getTranslation("FONT_AREA_TREE_DESCRIPTION"));
        creteSelectedFontGroup(propertyChangeManager.getTreeFont());
        break;

      /** Font area: Table */
      case TABLE_FONT:
        catDescription.setText(GUI.i18n.getTranslation("FONT_AREA_TABLE_DESCRIPTION"));
        creteSelectedFontGroup(propertyChangeManager.getTableFont());
        break;

      /** Font area: Header */
      case HEADER_FONT:
        catDescription.setText(GUI.i18n.getTranslation("FONT_AREA_HEADER_DESCRIPTION"));
        creteSelectedFontGroup(propertyChangeManager.getHeaderFont());
        break;
    }
  }

  /** Set the default font for the selected font area */
  void selectDefaultFont() {
    selectedFontData = FontShop.getFontData();
    saveFontData();
    creteSelectedFontGroup(FontShop.getFontData()[0]);
  }

  /** Select a font for RSSOwl */
  void selectFont() {
    FontDialog fontDialog = new FontDialog(composite.getShell());

    /** Preselect font in Dialog */
    if (selectedFontData != null)
      fontDialog.setFontList(selectedFontData);

    FontData fontData = fontDialog.open();

    /** Set fontData to selected font area */
    if (fontData != null) {
      selectedFontData[0] = fontData;
      saveFontData();
      creteSelectedFontGroup(selectedFontData[0]);
      possibleFontChange = true;
    }
  }
}