/* -*- Mode: Java; tab-width: 4; c-basic-offset: 4; -*-
 * 
 * The contents of this file are subject to the Netscape Public License
 * Version 1.0 (the "NPL"); you may not use this file except in
 * compliance with the NPL.  You may obtain a copy of the NPL at
 * http://www.mozilla.org/NPL/
 *
 * Software distributed under the NPL is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
 * for the specific language governing rights and limitations under the
 * NPL.
 *
 * The Initial Developer of this code under the NPL is Netscape
 * Communications Corporation.  Portions created by Netscape are
 * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
 * Reserved.
 *
 * Contributor(s):
 *   Ben "Count XULula" Goodger <rgoodger@ihug.co.nz>
 *   Syd Logan <syd@netscape.com>
 */

window.doneLoading = false; 
 
/** class PrefWindow ( string frame_id );
 *  - purpose: object representing the state of the prefs window
 *  - in:      string representing the panel content frame
 *  - out:     nothing;
 **/
function PrefWindow( frame_id )
{
  if ( !frame_id )
    throw "Error: frame_id not supplied!";

  // data members
  this.contentFrame   = frame_id
  // chrome folder structure
  this.folder         = new ChromeFolder( "chrome://pref/" );
  // instantiate the WidgetStateManager
  this.wsm            = new WidgetStateManager( frame_id, this.folder.content, ".xul" );
  this.pref           = null;
    
  // member functions
  this.onload         = PREF_onload;
  this.onok = PREF_onok;
  this.AddOnOK = PREF_AddOnOK;
  this.AddOnCancel = PREF_AddOnCancel;
  this.onokUser           = new Array;
  this.okCount = 0;
  this.oncancel = PREF_oncancel;
  this.oncancelUser       = new Array;
  this.cancelCount = 0;
  this.SwitchPage     = PREF_SwitchPage;
  this.onpageload     = PREF_onpageload;
  this.DoSavePrefs    = PREF_DoSavePrefs;
  this.ParsePref      = PREF_ParsePref;
  
  // set up window
  this.onload();
}

/** void onload();
 *  - purpose: startup routine for prefs dialog.
 *  - in:      nothing;
 *  - out:     nothing;
 **/
function PREF_onload()
{
  // set ok/cancel handlers
  doSetOKCancel( this.onok, null );
  // create pref object
  try {
    this.pref = Components.classes["component://netscape/preferences"].getService();
    if(this.pref)
      this.pref = this.pref.QueryInterface( Components.interfaces.nsIPref );
  }
  catch(e) {
    dump("*** Failed to create prefs object\n");
    return;
  }
  // this.wsm.PageData.splice(0);    // brutally empty the PageData Array
  if( window.queuedTag )
    this.onpageload( window.queuedTag );
  
}

function PREF_onok()
{
	for ( var i = 0; i < window.handle.okCount; i++ )
		window.handle.onokUser[i]();
	PREF_onokprivate();
}

function PREF_oncancel()
{
	for ( var i = 0; i < window.handle.cancelCount; i++ )
		window.handle.oncancelUser[i]();
	PREF_oncancelprivate();
}

/** void onok();
 *  - purpose: save all pref panel data and quit pref dialog
 *  - in:      nothing;
 *  - out:     nothing;
 **/
function PREF_onokprivate()
{
  var url = document.getElementById( window.handle.contentFrame ).getAttribute("src");
  var tag = window.handle.wsm.GetTagFromURL( url, window.handle.folder.content, ".xul" );
  var extras  = ["pref", "preftype", "prefstring", "prefindex"];
  window.handle.wsm.SavePageData( tag, extras, false, false );      // save data from the current page. 
  window.handle.DoSavePrefs();
  window.opener.prefWindow = 0;
  window.close();
}

function PREF_oncancelprivate()
{
  window.opener.prefWindow = 0;
  window.close();
}

function PREF_AddOnOK( func )
{
  this.onokUser[this.okCount] = func;
  this.okCount += 1;
}

function PREF_AddOnCancel( func )
{
  this.oncancelUser[this.cancelCount] = func;
  this.cancelCount += 1;
}

function PREF_DoSavePrefs()
{
  for( var i in window.handle.wsm.PageData ) {
    for ( var k in window.handle.wsm.PageData[i] ) {
      window.handle.ParsePref( k, window.handle.wsm.PageData[i][k] );
    }
  }
  // actually save the prefs file. 
  this.pref.SavePrefFile();
}

function PREF_ParsePref( elementID, elementObject )
{
  var whp = window.handle.pref; // shortcut
  
  // since we no longer use the convoluted id strings, we now use the id passed
  // in as an argument to this function to grab the appropriate element in the
  if( elementObject.pref ) {
    switch( elementObject.preftype ) 
    {
      case "bool":
        if( elementObject.prefindex === "true" || elementObject.prefindex === "false" ) {
          // bool prefs with a prefindex, e.g. boolean radios. the value we set
          // is actually the prefindex, not the checked value. 
          if( elementObject.value == true ) {
            if( typeof( elementObject.prefindex ) == "string" ) {
              if( elementObject.prefindex == "true" ) 
                elementObject.prefindex = true;
              else
                elementObject.prefindex = false;
            }
            // only set a pref if it is different to the current value. 
            try { 
              var oldPref = whp.GetBoolPref( elementObject.prefstring )
            } 
            catch(e) {
              var oldPref = false;
            }
            if( oldPref != elementObject.prefindex );
              whp.SetBoolPref( elementObject.prefstring, elementObject.prefindex );  // bool pref
            break;
          }
        }
        try { 
          var oldPref = whp.GetBoolPref( elementObject.prefstring )
        } 
        catch(e) {
          var oldPref = false;
        }
        if( oldPref != elementObject.prefindex );
          whp.SetBoolPref( elementObject.prefstring, elementObject.value );  // bool pref
        break;

      case "int":
        dump("*** elementObject.elType = " + elementObject.elType + "\n");
        if( elementObject.elType.toLowerCase() == "radio" && !elementObject.value )
          return false; // ignore, go to next
        if( !elementObject.prefindex ) {
          // element object does not have a prefindex (e.g. select widgets)
          var prefvalue = elementObject.value;
        }
        else {
          // element object has prefindex attribute (e.g. radio buttons)
          var prefvalue = elementObject.prefindex;
        }
        try {
          var oldPref = whp.GetIntPref( elementObject.prefstring );
        }
        catch(e) {
          var oldPref = 0;  // no default pref found, default int prefs to zero
        }
        dump("*** going to set int pref: " + elementObject.prefstring + " = " + prefvalue + "\n");
        if( oldPref != prefvalue ) 
          whp.SetIntPref( elementObject.prefstring, prefvalue );  // integer pref
        break;

      case "string":
      case "color":
        try {
          var charPref = whp.CopyCharPref( elementObject.prefstring );
        }
        catch(e) {
          var charPref = "";
        }
        // we cannot set a color pref to "" or else all hell will break loose.
        // we must REFUSE to set this pref if there is an empty string.
        if( elementObject.preftype == "color" && charPref == "" ) {
          dump("*** empty string color pref was going to be set, but we're avoiding this just in the nick of time...\n");
          break;
        }
        if( charPref != elementObject.value )   // do we care about whitespace? 
          whp.SetCharPref( elementObject.prefstring, elementObject.value );  // string pref
        break;
      default:
        // TODO: insert implementation for other pref types;
        break;
    }
  }
}

/** void SwitchPage ( DOMElement node );
 *  - purpose: switches the page in the content frame to that specified in the
 *  -          tag attribute of the selected treecell
 *  - in:      DOMElement representing the clicked node in the panel tree
 *  - out:     nothing;
 **/
function PREF_SwitchPage( node )
{
  // XXX 12/04/99
  if( node.nodeName == "treecell" && node.getAttribute("url") != "__header" ) {
    var url = document.getElementById( this.contentFrame ).getAttribute("src");
    var oldTag = this.wsm.GetTagFromURL( url, "/", ".xul", false );
    // extra attributes to be saved
    var extras  = ["pref", "preftype", "prefstring", "prefindex"];
    dump("*** going to save page data for tag: " + oldTag + "\n");
    this.wsm.SavePageData( oldTag, extras, false, false );      // save data from the current page. 

    var newURL = node.getAttribute("url");
    dump("*** newURL: " + newURL + "\n");
    var newTag = this.wsm.GetTagFromURL( newURL, "/", ".xul", false );
    // if the page clicked is the same one, don't bother reloading it.
    if( newTag != oldTag )
      document.getElementById( this.contentFrame ).setAttribute( "src", newURL );
    else 
      return;
  }
}

/** void onpageload ( string tag );
 *  - purpose: sets page data on the page which has just loaded
 *  - in:      string tag representing filename minus extension
 *  - out:     nothing;
 **/
function PREF_onpageload( tag )
{
  dump("*** PREF_onpageload('" + tag + "');\n");

  // remove wallet functions (unless overruled by the "wallet.enabled" pref)
  try {
    if (!this.pref.GetBoolPref("wallet.enabled")) {
      var element;
      if (tag == "pref-wallet") {
        element = window.frames[this.contentFrame].document.getElementById("walletArea");
        element.setAttribute("style","display: none;" );
      }
    }
  } catch(e) {
    dump("wallet.enabled pref is missing from all.js");
  }

  if( !this.wsm.PageData[tag] ) {
    // there is no entry in the data hash for this page, so we need to initialise
    // the form values from existing prefs. The best way to do this is to pack
    // the PageData table for this element with values from prefs, rather than
    // setting attributes here because we can then leverage the setting ability
    // of wsm.SetPageData
    
    // step one: get all the elements with pref ids. (this may change to get
    // elements with some other pref attributes - likely)
    // yes I know this is an evil function to use, sue me. 
    prefElements = window.frames[this.contentFrame].document.getElementsByAttribute( "pref", "true" );

    this.wsm.PageData[tag] = [];   
    for( var i = 0; i < prefElements.length; i++ )
    {
      var prefstring  = prefElements[i].getAttribute("prefstring");
      var prefid      = prefElements[i].getAttribute("id");
      var preftype    = prefElements[i].getAttribute("preftype");
      var prefdefval  = prefElements[i].getAttribute("prefdefval");
      switch( preftype ) {
        case "bool":
          try {
            var prefvalue = this.pref.GetBoolPref( prefstring );
            dump("*** user prefs\n");
          }
          catch(e) {
            // radio elements need to have at least one element be set.
            dump("*** failed in default prefs\n")
            if( prefElements[i].nodeName.toLowerCase() == "radio" )
              dump("*** NO DEFAULT PREF for " + prefstring + ", and one IS needed for radio items.\n");
            continue;
          }
          break;
        case "int":
          try {
            var prefvalue = this.pref.GetIntPref( prefstring );
          }
          catch(e) {
            // radio elements need at least one value to be set.
            if( prefElements[i].nodeName.toLowerCase() == "radio" )
              dump("*** NO DEFAULT PREF for " + prefstring + ", and one IS needed for radio items.\n");
            continue;
          }
          break;
        case "string":
        case "color":
          try {
            var prefvalue = this.pref.CopyCharPref( prefstring );
          } 
          catch(e) {
            continue;
          }
          break;
        default:
          // TODO: define cases for other pref types if required
          break;
      }
      this.wsm.PageData[tag][prefid]  = [];   
      var root                        = this.wsm.PageData[tag][prefid];
      root["id"]                      = prefid;
      if( prefElements[i].type.toLowerCase() == "radio") {
        // radio elements are a special case - we have a value in the prefs for
        // only one of however many there are, and in thsi case "value" represents
        // the index of the one that we want to check, not an actual settable value.
        // here is where the "prefindex" attribute on such elements comes into
        // play. We compare this with the value read from nsIPref, and if it matches,
        // that is the radioelement that needs to be checked.
        var prefindex = prefElements[i].getAttribute("prefindex");
        if( prefElements[i].getAttribute("preftype").toLowerCase() == "bool" )
          prefvalue = prefvalue.toString(); // need to explicitly type convert on bool prefs.
        
        dump("*** prefindex = " + prefindex + "; prefvalue = " + prefvalue + "\n");
        if( prefindex == prefvalue ) 
          prefvalue = true;     // match! this element is checked!
        else 
          prefvalue = false;    // no match. This element.checked = false;
        dump("*** prefvalue = " + prefvalue + "\n");
      }
      root["value"]     = prefvalue;
    }
  } 
  this.wsm.SetPageData( tag, false );  // do not set extra elements, accept hard coded defaults

  // run startup function on panel if one is available.
  if( window.frames[ this.contentFrame ].Startup )
    window.frames[ this.contentFrame ].Startup();
}

/** class ChromeFolder ( string root );
 *  - purpose: a general object to provide easy access to chrome folders 
 *  - in:      string representing root, e.g. "chrome://bookmarks/"
 *  - out:     nothing;
 **/
function ChromeFolder( root )
{
  if( root.charAt(root.length-1) != "/" )
    root += "/";
  this.content  = root + "content/";
  this.skin     = root + "skin/";
  this.locale   = root + "locale/";
}
