/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is mozilla.org code.
 *
 * The Initial Developer of the Original Code is
 * Netscape Communications Corporation.
 * Portions created by the Initial Developer are Copyright (C) 1998
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *   Gervase Markham <gerv@gerv.net>
 *   Tuukka Tolvanen <tt@lament.cjb.net>
 *   Stefan Borggraefe <Stefan.Borggraefe@gmx.de>
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either of the GNU General Public License Version 2 or later (the "GPL"),
 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */

var fontEnumerator = null;
var globalFonts = null;
var fontTypes   = ["serif", "sans-serif", "cursive", "fantasy", "monospace"];
var defaultFont, variableSize, fixedSize, minSize, languageList;
var languageData = [];
var currentLanguage;
var gPrefutilitiesBundle;

// manual data retrieval function for PrefWindow
function GetFields()
  {
    var dataObject = parent.hPrefWindow.wsm.dataManager.pageData["chrome://communicator/content/pref/pref-fonts.xul"];

    // store data for language independent widgets
    if( !( "dataEls" in dataObject ) )
      dataObject.dataEls = [];
    dataObject.dataEls[ "selectLangs" ] = [];
    dataObject.dataEls[ "selectLangs" ].value = document.getElementById( "selectLangs" ).value;

    dataObject.useDocFonts = document.getElementById( "browserUseDocumentFonts" ).checked ? 1 : 0;

    // save current state for language dependent fields and store
    saveState();
    dataObject.languageData = languageData;

    return dataObject;
  }

// manual data setting function for PrefWindow
function SetFields( aDataObject )
  {
    languageData = "languageData" in aDataObject ? aDataObject.languageData : languageData ;
    currentLanguage = "currentLanguage" in aDataObject ? aDataObject.currentLanguage : null ;

    var element = document.getElementById( "selectLangs" );
    if( "dataEls" in aDataObject )
      {
        element.selectedItem = element.getElementsByAttribute( "value", aDataObject.dataEls[ "selectLangs" ].value )[0];
      }
    else
      {
        var prefstring = element.getAttribute( "prefstring" );
        var preftype = element.getAttribute( "preftype" );
        if( prefstring && preftype )
          {
            var prefvalue = parent.hPrefWindow.getPref( preftype, prefstring );
            element.selectedItem = element.getElementsByAttribute( "value", prefvalue )[0];
          }
      }

    var useDocFontsCheckbox = document.getElementById( "browserUseDocumentFonts" );
    if( "useDocFonts" in aDataObject && aDataObject.useDocFonts != undefined )
      useDocFontsCheckbox.checked = aDataObject.useDocFonts ? true : false;
    else
      {
        prefvalue = parent.hPrefWindow.getPref( "int", "browser.display.use_document_fonts" );
        if( prefvalue != "!/!ERROR_UNDEFINED_PREF!/!" )
          useDocFontsCheckbox.checked = prefvalue ? true : false ;
      }
    if ( parent.hPrefWindow.getPrefIsLocked( "browser.display.use_document_fonts" ) ) {
        useDocFontsCheckbox.disabled = true;
    }
  }

function Startup()
  {
    defaultFont  = document.getElementById( "proportionalFont" );
    variableSize = document.getElementById( "sizeVar" );
    fixedSize    = document.getElementById( "sizeMono" );
    minSize      = document.getElementById( "minSize" );
    languageList = document.getElementById( "selectLangs" );

    gPrefutilitiesBundle = document.getElementById("bundle_prefutilities");

    // register our ok callback function
    parent.hPrefWindow.registerOKCallbackFunc( saveFontPrefs );

    // eventually we should detect the default language and select it by default
    selectLanguage();
    
    // This prefstring is a contrived pref whose sole purpose is to lock some
    // elements in this panel.  The value of the pref is not used and does not matter.
    if ( parent.hPrefWindow.getPrefIsLocked( "browser.display.languageList" ) ) {
      disableAllFontElements();
    }
  }

function getFontEnumerator()
  {
    if (!fontEnumerator)
      {
        fontEnumerator = Components.classes["@mozilla.org/gfx/fontenumerator;1"]
                        .createInstance()
                        .QueryInterface(Components.interfaces.nsIFontEnumerator);
      }
    return fontEnumerator;
  }

function listElement( aListID )
  {
    this.listElement = document.getElementById( aListID );
  }

listElement.prototype =
  {
    clearList:
      function ()
        {
          // remove the menupopup node child of the menulist.
          this.listElement.removeChild( this.listElement.firstChild );
        },

    appendFontNames: 
      function ( aLanguage, aFontType )
        {
          var i;
          var defaultFont = null;
          var count = { value: 0 };
          var fonts = getFontEnumerator().EnumerateFonts( aLanguage, aFontType, count );
          if (fonts.length > 0)
            {
              defaultFont = getFontEnumerator().getDefaultFont( aLanguage, aFontType );
            }
          else
            {
              // if no specific fonts, relax 'aFontType' and try to get other
              // fonts for this language so that we can group them on top
              fonts = getFontEnumerator().EnumerateFonts( aLanguage, "", count );
              if (fonts.length > 0)
                {
                  defaultFont = getFontEnumerator().getDefaultFont( aLanguage, "" );
                }
            }

          var itemNode = null;
          var separatorNode = null;
          var popupNode = document.createElement( "menupopup" ); 

          if (fonts.length > 0)
            {
              // always put the default font at the front of the list
              if (defaultFont)
                {
                  var label = gPrefutilitiesBundle
                    .getString("labelDefaultFont")
                    .replace(/%font_family%/, defaultFont);
                  itemNode = document.createElement( "menuitem" );
                  itemNode.setAttribute( "label", label );
                  itemNode.setAttribute( "value", "" ); // special blank value
                  popupNode.appendChild( itemNode );

                  separatorNode = document.createElement( "menuseparator" );
                  popupNode.appendChild( separatorNode );
                }

              for (i = 0; i < fonts.length; i++)
                {
                  itemNode = document.createElement( "menuitem" );
                  itemNode.setAttribute( "value", fonts[i] );
                  itemNode.setAttribute( "label", fonts[i] );
                  popupNode.appendChild( itemNode );
                }
            }

            // get all the fonts to complete the font lists
            if (!globalFonts)
              {
                globalFonts = getFontEnumerator().EnumerateAllFonts( count );
              }

          // since the lists are sorted, we can get unique entries by just walking
          // both lists linearly side-by-side, skipping those values already in
          // the popup list
          if (globalFonts.length > fonts.length)
            {
              var menuItem = separatorNode ? separatorNode.nextSibling : popupNode.firstChild; 
              var menuValue = menuItem ? menuItem.getAttribute( "value" ) : null;

              separatorNode = document.createElement( "menuseparator" );
              popupNode.appendChild( separatorNode );

              for (i = 0; i < globalFonts.length; i++)
                {
                  if (globalFonts[i] != menuValue)
                    {
                      itemNode = document.createElement( "menuitem" );
                      itemNode.setAttribute( "value", globalFonts[i] );
                      itemNode.setAttribute( "label", globalFonts[i] );
                      popupNode.appendChild( itemNode );
                    }
                  else
                    {
                      menuItem = menuItem.nextSibling;
                      menuValue = menuItem ? menuItem.getAttribute( "value" ) : null;
                    }
                }
            }

          this.listElement.appendChild( popupNode ); 

          return popupNode.firstChild;
        } 
  };

function lazyAppendFontNames( i )
  {
     // schedule the build of the next font list
     if (i+1 < fontTypes.length)
       {
         window.setTimeout(lazyAppendFontNames, 100, i+1);
       }

     // now build and populate the fonts for the requested font type
     var defaultItem;
     var selectElement = new listElement( fontTypes[i] );
     selectElement.clearList();
     try
       {
         defaultItem = selectElement.appendFontNames( languageList.value, fontTypes[i] );
       }
     catch(e) {
         dump("pref-fonts.js: " + e + "\nFailed to build the font list for " + fontTypes[i] + "\n");
         return;
       }

     // now set the selected font item for the drop down list

     if (!defaultItem)
       return; // nothing to select, so no need to bother

     // the item returned by default is our last resort fall-back
     var selectedItem = defaultItem;
     var dataEls;
     if( languageList.value in languageData )
       {
         // data exists for this language, pre-select items based on this information
         var dataVal = languageData[languageList.value].types[fontTypes[i]];
         if (dataVal.length) // else: special blank means the default
           dataEls = selectElement.listElement.getElementsByAttribute("value", dataVal);
       }
     else
       {
         try
           {
             var fontPrefString = "font.name." + fontTypes[i] + "." + languageList.value;
             var selectVal = parent.hPrefWindow.pref.getComplexValue( fontPrefString, Components.interfaces.nsISupportsString ).data;
             dataEls = selectElement.listElement.getElementsByAttribute("value", selectVal);

             // we need to honor name-list in case name is unavailable 
             if (!dataEls.item(0)) {
                 var fontListPrefString = "font.name-list." + fontTypes[i] + "." + languageList.value;
                 var nameList = parent.hPrefWindow.pref.getComplexValue( fontListPrefString, Components.interfaces.nsISupportsString ).data;
                 var fontNames = nameList.split(",");

                 for (j = 0; j < fontNames.length; j++) {
                   selectVal = fontNames[j].replace(/^\s+|\s+$/, "");
                   dataEls = selectElement.listElement.getElementsByAttribute("value", selectVal);
                   if (dataEls.item(0))  
                     break;  // exit loop if we find one
                 }
             }
           }
         catch(e) {
           }
       }
     if (dataEls && dataEls.item(0))
       selectedItem = dataEls[0];

     selectElement.listElement.selectedItem = selectedItem;
     selectElement.listElement.removeAttribute( "disabled" );
  }

function saveFontPrefs()
  {
    // saving font prefs
    var dataObject = parent.hPrefWindow.wsm.dataManager.pageData["chrome://communicator/content/pref/pref-fonts.xul"];
    var pref = parent.hPrefWindow.pref;
    for( var language in dataObject.languageData )
      {
        for( var type in dataObject.languageData[language].types )
          {
            var fontPrefString = "font.name." + type + "." + language;
            var currValue = "";
            try
              {
                currValue = pref.getComplexValue( fontPrefString, Components.interfaces.nsISupportsString ).data;
              }
            catch(e)
              {
              }

            var dataValue = dataObject.languageData[language].types[type];
            if( currValue != dataValue )
              {
                if (dataValue)
                  {
                    parent.hPrefWindow.setPref( "string", fontPrefString, dataValue );
                  }
                else
                  {
                    // A font name can't be blank. The special blank means the default.
                    // Unset the pref entirely, letting Gfx to decide. GfxXft will use what
                    // Xft says, whereas GfxWin and others will use the built-in settings
                    // that are shipped for font.name and font.name-list.
                    try
                      {
                        // ClearUserPref throws an exception...
                        pref.clearUserPref( fontPrefString );
                      }
                    catch(e)
                      {
                      }
                  }
              }
          }
        var defaultFontPref = "font.default." + language;
        var variableSizePref = "font.size.variable." + language;
        var fixedSizePref = "font.size.fixed." + language;
        var minSizePref = "font.minimum-size." + language;
        var currDefaultFont = "serif", currVariableSize = 12, currFixedSize = 12, minSizeVal = 0;
        try
          {
            currDefaultFont = parent.hPrefWindow.getPref( "string", defaultFontPref );
            currVariableSize = pref.getIntPref( variableSizePref );
            currFixedSize = pref.getIntPref( fixedSizePref );
            minSizeVal = pref.getIntPref( minSizePref );
          }
        catch(e)
          {
          }
        if( currDefaultFont != dataObject.languageData[language].defaultFont )
          parent.hPrefWindow.setPref( "string", defaultFontPref, dataObject.languageData[language].defaultFont );
        if( currVariableSize != dataObject.languageData[language].variableSize )
          pref.setIntPref( variableSizePref, dataObject.languageData[language].variableSize );
        if( currFixedSize != dataObject.languageData[language].fixedSize )
          pref.setIntPref( fixedSizePref, dataObject.languageData[language].fixedSize );
        if( minSizeVal != dataObject.languageData[language].minSize ) {
          pref.setIntPref ( minSizePref, dataObject.languageData[language].minSize );
        }
      }

    // font scaling
    var documentFonts = dataObject.useDocFonts;
    var defaultFont   = dataObject.defaultFont;

    try
      {
        var currFonts = pref.getIntPref( "browser.display.use_document_fonts" );
      }
    catch(e)
      {
      }
    if( currFonts != documentFonts )
      pref.setIntPref( "browser.display.use_document_fonts", documentFonts );
  }

function saveState()
  {
    for( var i = 0; i < fontTypes.length; i++ )
      {
        // preliminary initialisation
        if( currentLanguage && !( currentLanguage in languageData ) )
          languageData[currentLanguage] = [];
        if( currentLanguage && !( "types" in languageData[currentLanguage] ) )
          languageData[currentLanguage].types = [];
        // save data for the previous language
        if( currentLanguage && currentLanguage in languageData &&
            "types" in languageData[currentLanguage] )
          languageData[currentLanguage].types[fontTypes[i]] = document.getElementById( fontTypes[i] ).value;
      }

    if( currentLanguage && currentLanguage in languageData &&
        "types" in languageData[currentLanguage] )
      {
        languageData[currentLanguage].defaultFont = defaultFont.value;
        languageData[currentLanguage].variableSize = parseInt( variableSize.value );
        languageData[currentLanguage].fixedSize = parseInt( fixedSize.value );
        languageData[currentLanguage].minSize = parseInt( minSize.value );
      }
  }

// Selects size (or the nearest entry that exists in the list)
// in the menulist minSize
function minSizeSelect(size)
  {
    var items = minSize.getElementsByAttribute( "value", size );
    if (items.item(0))
      minSize.selectedItem = items[0];
    else if (size < 6)
      minSizeSelect(6);
    else if (size > 24)
      minSizeSelect(24);
    else
      minSizeSelect(size - 1);
  }

function selectLanguage()
  {
    // save current state
    saveState();

    if( !currentLanguage )
      currentLanguage = languageList.value;
    else if( currentLanguage == languageList.value )
      return; // same as before, nothing changed

    // lazily populate the successive font lists at 100ms intervals.
    // (Note: the third parameter to setTimeout() is going to be
    // passed as argument to the callback function.)
    window.setTimeout(lazyAppendFontNames, 100, 0);

    // in the meantime, disable the menu lists
    for( var i = 0; i < fontTypes.length; i++ )
      {
        var listElement = document.getElementById( fontTypes[i] );
        listElement.setAttribute( "value", "" );
        listElement.setAttribute( "label", "" );
        listElement.setAttribute( "disabled", "true" );
      }

    // and set the default font type and the font sizes
    try
      {
        defaultFont.value = parent.hPrefWindow.getPref("string", "font.default." + languageList.value);

        var variableSizePref = "font.size.variable." + languageList.value;
        var sizeVarVal = parent.hPrefWindow.pref.getIntPref( variableSizePref );
        variableSize.selectedItem = variableSize.getElementsByAttribute( "value", sizeVarVal )[0];

        var fixedSizePref = "font.size.fixed." + languageList.value;
        var sizeFixedVal = parent.hPrefWindow.pref.getIntPref( fixedSizePref );
        fixedSize.selectedItem = fixedSize.getElementsByAttribute( "value", sizeFixedVal )[0];
      }
    catch(e) { } // font size lists can simply default to the first entry

    var minSizeVal = 0;
    try 
      {
        var minSizePref = "font.minimum-size." + languageList.value;
        minSizeVal = parent.hPrefWindow.pref.getIntPref( minSizePref );
      }
    catch(e) { }
    minSizeSelect( minSizeVal );

    currentLanguage = languageList.value;
  }

// disable font items, but not the browserUseDocumentFonts checkbox
function disableAllFontElements()
  {
      var doc_ids = [ "selectLangs", "proportionalFont",
                      "sizeVar", "serif", "sans-serif",
                      "cursive", "fantasy", "monospace",
                      "sizeMono", "minSize" ];
      for (i=0; i<doc_ids.length; i++) {
          element = document.getElementById( doc_ids[i] );
          element.disabled = true;
      }
  }

