/* 
 * The contents of this file are subject to the Netscape 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/NPL/
 *  
 * 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 Session Roaming code.
 * 
 * The Initial Developer of the Original Code is
 * Ben Bucksch <http://www.bucksch.org> of
 * Beonex <http://www.beonex.com>
 * Portions created by Ben Bucksch are Copyright (C) 2002 Ben Bucksch.
 * All Rights Reserved.
 * 
 * Contributor(s): 
 */

var gData;
var gPrefService = Components.classes["@mozilla.org/preferences-service;1"]
                        .getService(Components.interfaces.nsIPrefService);

// for pane switches
function Unload()
{
  UIToData();
  //parent.roaming.verifyData();
  var pref = gPrefService.getBranch(null);
  pref.removeObserver("roaming.", parent.roaming);
}

/* *sigh*!!! when the user clicks OK in another pane,
   all the other functions and even the consts are gone, 
   so creating an object. */

function RoamingPrefs()
{
  // init
  this.loaded = false; // already read from registry
  this.changed = false; // any of the values changed, so save all
  // user data
  this.Enabled = false;
  this.Method = 0; // int, reall enum: 0=stream, 1=copy
  this.Files = new Array(); // of strings, will get another default below
  this.Stream = new Object();
  this.Stream.BaseURL = "";
  this.Stream.Username = "";
  this.Stream.SavePW = false;
  this.Stream.Password = "";
  this.Copy = new Object();
  this.Copy.RemoteDir = "";

  this.pref = gPrefService.getBranch(null);
  
  var prefBranchInternal = this.pref.QueryInterface(Components.interfaces.nsIPrefBranchInternal);
  this.pref.addObserver("roaming.", this, false);

  this.prefsToData();

  var me = this;
  parent.hPrefWindow.registerOKCallbackFunc(function() { me.okClicked(); });
}

RoamingPrefs.prototype =
{
  kPrefEnabled :           "roaming.enabled",
  kPrefMethod :            "roaming.method",
  kPrefFiles :             "roaming.files",
  kPrefLocalFile :         "roaming.localFile",
  kPrefStreamURL :         "roaming.stream.baseURL",
  kPrefStreamUsername :    "roaming.stream.username",
  kPrefStreamPassword :    "roaming.stream.password",
  kPrefStreamSavePW :      "roaming.stream.savePassword",
  kPrefCopyDir :           "roaming.copy.remoteDir",
  kPrefSavePreference :    "roaming.savePreference",

  kMethodStream :          "stream",
  kMethodCopy :            "copy",
  
  pref : null,

  okClicked : function()
  {
    if ("UIToData" in window) // unless a different pane is selected
    {
      UIToData();
    }
    if (this.verifyData())
      this.dataToPrefs();
  },
  
  observe : function(subject, topic, data)
  {
    if (data.indexOf("roaming.") >= 0 &&
        topic == "nsPref:changed")
    {
      var savePreference = subject.getBoolPref(this.kPrefSavePreference);
      var method = subject.getCharPref(this.kPrefMethod);
      if (method == this.kMethodCopy && !savePreference) {
        this.showMessage("RoamingPrefChanged", null);
        // Set this value so that we don't upload files to server when shutdown Mozilla this time.
        subject.setBoolPref(this.kPrefSavePreference, true);
      } else if (method != this.kMethodCopy)
        subject.setBoolPref(this.kPrefSavePreference, false);
    }
  },

  prefsToData : function()
  {
    if (this.loaded == true)
      // prevent overwriting of user changes after pane switch back/forth
      return;

    // set default values, matching the hardcoded ones, in case we fail below
    // internal logic

    try
    {
      // enabled
      try {
        this.Enabled = this.pref.getBoolPref(this.kPrefEnabled);

        // method (in the sense of the roaming implementation) selection
        value = this.pref.getCharPref(this.kPrefMethod);
        if (value == this.kMethodStream)
          this.Method = 0;
        else if (value == this.kMethodCopy)
          this.Method = 1;
      } catch (e) {
        dump(e + "\n");
      }
      // files
      this.Files = getFileList();

      // stream
      this.Stream.BaseURL = this.pref.getCharPref(this.kPrefStreamURL);
      this.Stream.Username = this.pref.getCharPref(this.kPrefStreamUsername);

      this.Stream.Password = this.pref.getCharPref(this.kPrefStreamPassword);

      this.Stream.SavePW = this.pref.getBoolPref(this.kPrefStreamSavePW);

      // copy
      this.Copy.RemoteDir = this.pref.getCharPref(this.kPrefCopyDir);

      // Note that read and write all values. We want to remember them,
      // even if not used at the moment.
    }
    catch (e)
    {
      dump("Error reading preference:\n" + e + "\n");
    }
    this.loaded = true;
        /* we might have failed above, but in this case, there is probably no
           sense trying it again, so treat that the same as loaded.
           This is important for the first setup - the first read will fail. */
  },
  
  // Saves from the internal data structure into the Mozilla preference
  dataToPrefs : function()
  {
    if (!this.changed)
      return;

    try {
      var pref = Components.classes["@mozilla.org/preferences-service;1"]
                   .getService(Components.interfaces.nsIPrefService)
                   .getBranch(null);

      // enabled
      this.pref.setBoolPref(this.kPrefEnabled, this.Enabled);

      // method (in the sense of the roaming implementation) selection
      var value;
      if (this.Method == 0)
        value = this.kMethodStream;
      else if (this.Method == 1)
        value = this.kMethodCopy;
      else // huh??
        value = this.kMethodStream;
      this.pref.setCharPref(this.kPrefMethod, value);

      // files
      for (var i = 0, l = this.Files.length; i < l; i++)
      {
        var file = this.Files[i];
        if (file.filename && file.filename != "") {
          var prefFilename = this.kPrefFiles + "." + file.filename;
          if (!this.pref.prefIsLocked(prefFilename))
            this.pref.setBoolPref(prefFilename, file.enabled);
          if (file.localFilename && file.localFilename != "")
            this.pref.setCharPref(this.kPrefLocalFile + "." + file.filename, file.localFilename);
        }
      }

      // stream
      this.pref.setCharPref(this.kPrefStreamURL, this.Stream.BaseURL);
      this.pref.setCharPref(this.kPrefStreamUsername, this.Stream.Username);
      this.pref.setCharPref(this.kPrefStreamPassword,
                            this.Stream.SavePW == true ? this.Stream.Password : "");
      this.pref.setBoolPref(this.kPrefStreamSavePW, this.Stream.SavePW);

      // copy
      this.pref.setCharPref(this.kPrefCopyDir, this.Copy.RemoteDir);

      this.changed = false;
    } catch (e) {
      this.showError("ErrorRegWrite", undefined, e.message);
      return;
    }
  },

  // if some (user-entered) value is bad, shows error dialog and returns false
  verifyData : function()
  {
    if (!this.Enabled)
      return true;

    var errorProp; // see showError();
    var errorVal;  // dito
    var errorException;
    if (this.Files.length <= 0)
    {
      errorProp = "NoFilesSelected";
    }
    if (this.Method == 0) // stream
    {
      // username
      if (!this.Stream.Username || this.Stream.Username == "")
      {
        errorProp = "NoUsername";
      }

      // password
      /* password may be empty despite savepw, we'll then ask for the password
         during the next transfer and store it (by default) then. */

      // base url
      try
      {
        var ioserv = Components.classes["@mozilla.org/network/io-service;1"]
                     .getService(Components.interfaces.nsIIOService);
        var baseURL = ioserv.newURI(this.Stream.BaseURL, null, null);
      }
      catch(e)
      {
        errorProp = "BaseURLMalformed";
        errorVal = this.Stream.BaseURL;
        //errorException = e;
      }
    }
    else if (this.Method == 1) // copy
    {
      // remote dir
      if (this.Copy.RemoteDir == "")
      {
        errorProp = "RemoteDirNonExistant";
        errorVal = " ";
      }
      else
      {
        try
        {
          var lf = Components.classes["@mozilla.org/file/local;1"]
                           .createInstance(Components.interfaces.nsILocalFile);
          lf.initWithPath(this.Copy.RemoteDir);
          if (!lf.exists())
          {
            throw "";
          }
        }
        catch(e)
        {
          errorProp = "RemoteDirNonExistant";
          errorVal = this.Copy.RemoteDir;
          errorException = e.message; // will be undefined, if !lf.exist()
        }
      }
    }

    if (errorProp)
      this.showError(errorProp, errorVal, errorException);

    return errorProp == undefined ? true : false;
    // XXX We should prevent closure and force the user to enter valid data,
    // but I don't know how to do it.
  },

  /**
   * Warning: Don't try to show this after pref window disappeared, because
   * we then can't display decendant windows (this error dialog) anymore.
   *
   * @param prop  string  stringbungle string name
   * @param val   string  text to be replaced in string
   * @param tech  string  internal error message (exception etc.). In English.
   */
  showError : function(prop, val, tech)
  {
    try
    {
      var promptService = Components
                          .classes["@mozilla.org/embedcomp/prompt-service;1"]
                          .getService(Components.interfaces.nsIPromptService);
      var bundle = Components.classes["@mozilla.org/intl/stringbundle;1"]
                  .getService()
                  .QueryInterface(Components.interfaces.nsIStringBundleService)
                  .createBundle("chrome://sroaming/locale/prefs.properties");
      var dialogTitle = bundle.GetStringFromName("RoamingErrorTitle");
      var text = dialogTitle + "\n";

      if (val != undefined) {
        text += bundle.formatStringFromName(prop, [val], 1);
      }
      else
        text += bundle.GetStringFromName(prop);
      if (tech) // should we show exceptions to user?
        text += "\n" + tech;
      promptService.alert(window, dialogTitle, text);
    } catch(e) {
      dump("Error while trying to display an error: " + e
           + " (original error: " + prop + " " + tech + ")\n");
    }
  },
  
  showMessage : function(prop, val)
  {
    try
    {
      var promptService = Components
                          .classes["@mozilla.org/embedcomp/prompt-service;1"]
                          .getService(Components.interfaces.nsIPromptService);
      var bundle = Components.classes["@mozilla.org/intl/stringbundle;1"]
                  .getService()
                  .QueryInterface(Components.interfaces.nsIStringBundleService)
                  .createBundle("chrome://sroaming/locale/prefs.properties");
      var dialogTitle = bundle.GetStringFromName("RoamingMessageTitle");
      var text = "";

      if (val != undefined) {
        text += bundle.formatStringFromName(prop, [val], 1);
      }
      else
        text += bundle.GetStringFromName(prop);
      promptService.alert(window, dialogTitle, text);
    } catch(e) {
      dump("Error while trying to display an error: " + e
           + " (original error: " + prop + " " + tech + ")\n");
    }
  }
}

// UI

function SwitchDeck(page, deckElement)
{
  deckElement.setAttribute("selectedIndex", page);
}

function EnableElement(enabled, triggerElement, elementID)
{
  var element = document.getElementById(elementID);
  if(!enabled)
    element.setAttribute("disabled", "true");
  else
    element.removeAttribute("disabled");
}

function EnableTree(enabled, element)
{
  if (!element || !element.setAttribute)
    return;

  if(!enabled)
    element.setAttribute("disabled", "true");
  else
    element.removeAttribute("disabled");

  // EnableTree direct children (recursive)
  var children = element.childNodes;
  for (var i = 0; i < children.length; i++)
    EnableTree(enabled, children.item(i));
}

function InitElement(elementID)
{
  var e = document.getElementById(elementID);
  eval(e.getAttribute("oncommand").replace(/this/g, "e")); //hackish, but WFM
}

function E(elementID)
{
  return document.getElementById(elementID);
}
