/* -*- java -*- */

with ({
  LOG: function LOG(message) {
    dump("toolbar.js: " + message + "\n");
    Components
      .classes['@mozilla.org/consoleservice;1']
      .getService(Components.interfaces.nsIConsoleService)
      .logStringMessage("toolbar.js: " + message);
  }
}) {

  try {
    LOG("start.");

    var mutualHeader = {}, mutualAuth = {};

    with ({
      load: function load(filename, scope) {
        Components
          .classes["@mozilla.org/moz/jssubscript-loader;1"]
          .getService(Components.interfaces.mozIJSSubScriptLoader)
          .loadSubScript("chrome://mutualauthext/content/" + filename, scope);
      }
    }) {
      load("header.js", mutualHeader);
      load("auth.js", mutualAuth);
    }

    LOG("mutualAuth.authScheme = " + mutualAuth.authScheme);

    var __mutual_updateUI = function __mutual_updateUI() {

      LOG("__mutual_updateUI: start");
      var bundle = srGetStrBundle("chrome://mutualauthext/locale/toolbar.properties");

      var browser = gBrowser.selectedBrowser;
      var box = document.getElementById("mutual-border-box");
      if (!box) {
          LOG("__mutual_updateUI: no box. return...");
          return;
      }

      var button = document.getElementById("mutual-submit-button");
      if (button.hasAttribute("working")) {
        button.removeAttribute("working");
      }
      button.checked = false;

      LOG("__mutual_updateUI: here1");
      if(browser.__mutual_needAuth){
        LOG("__mutual_updateUI: here2");
        if (browser.__mutual_login_redirect) {
          LOG("__mutual_updateUI: here3");
          browser.contentWindow.location.replace(browser.__mutual_login_redirect);

        } else {
          LOG("__mutual_updateUI: here4");
          if ("__mutual_inputUsername" in browser) {
            __mutual_username_textbox.getElement().value = browser.__mutual_inputUsername;
          } else {
            __mutual_username_textbox.getElement().value = "";
          }
          __mutual_password_textbox.getElement().value = "";
          __mutual_username_textbox.onBlur();
          __mutual_password_textbox.onBlur();
          LOG("__mutual_updateUI: here5");

          box.setAttribute("status", "prompt");
          button.setAttribute("tooltiptext",
                              bundle.GetStringFromName("mutual.tooltip.login"));
        }

        LOG("__mutual_updateUI: needAuth finish");
        return;
      }

      LOG("__mutual_updateUI: here6");
      if ("__mutual_authStatus" in browser == false) {
        LOG("__mutual_updateUI: no __mutual_authStatus.  return");
        return;
      }
      var authStatus = browser.__mutual_authStatus;

      LOG("__mutual_updateUI: authStatus = " + authStatus);

      LOG("__mutual_updateUI: here7");
      if (authStatus.isTopLevelAuthSucceed) {
        var label = document.getElementById("mutual-username-label");
        label.setAttribute("value", authStatus.topLevelUsername);
        label.setAttribute("tooltiptext", authStatus.topLevelUsername);
        box.setAttribute("status", "loggedin-safe");
        button.checked = true;
        button.setAttribute("tooltiptext",
                            bundle.GetStringFromName("mutual.tooltip.logout"));

        if (label.hasAttribute("style")) {
          label.removeAttribute("style");
        }
        if (label.boxObject.width > 100) {
          label.setAttribute("style", "width: 100px;");
        }
        LOG("__mutual_updateUI: isTopLevelAuthSucceed finished.");
        return;
      }

      LOG("__mutual_updateUI: here8");
      box.setAttribute("status", "normal");

      LOG("__mutual_updateUI: finish");
      return;
    };


    var mutualProgressListener = function mutualProgressListener (browser) {
      this.browser = browser;
      browser.addProgressListener(this);
      browser.__mutual_listener = this;
    };

    mutualProgressListener.prototype = {

      QueryInterface: function QueryInterface(iid)
      {
        if(iid.equals(Components.interfaces.nsISupports) ||
           iid.equals(Components.interfaces.nsISupportsWeakReference) ||
           iid.equals(Components.interfaces.nsIWebProgressListener)){
          return this;
        }

        throw Components.results.NS_ERROR_NO_INTERFACE;
      },

      onLocationChange: function onLocationChange(webProgress, request, location)
      {
        LOG("onLocationChange: start.");

        // return when event is not toplevel.
        try {
          var win = webProgress.DOMWindow;
          if (win.parent != win) return;
        } catch(ex) {
          return;
        }

        delete this.browser.__mutual_needAuth;
        delete this.browser.__mutual_inputUsername;
        delete this.browser.__mutual_authUri;
        delete this.browser.__mutual_authChallenge;

        delete this.browser.__mutual_authStatus;
        delete this.browser.__mutual_login_redirect;
        delete this.browser.__mutual_logout_location;

        LOG("onLocationChange(" + request.name + "): " + location.spec);

        this.browser.__mutual_authStatus = {
          topLevelUsername: undefined,
          topLevelAuthRealm: undefined,
          isTopLevelAuthSucceed: false,
        };

        LOG("onLocationChange: here1");
        LOG("onLocationChange request.status = " + (request && request.status));
        LOG("onLocationChange Components.results.NS_OK = " + (Components.results.NS_OK));

        if(request && request.status == Components.results.NS_OK){
          LOG("onLocationChange: here2");
          try{
            var http = request.QueryInterface(Components.interfaces.nsIHttpChannel);
            var bag2 = http.QueryInterface(Components.interfaces.nsIPropertyBag2);

            LOG("onLocationChange: here3");
            var status = bag2.getPropertyAsACString("__mutual_auth_status");
            LOG("onLocationChange: here4");

            LOG("onLocationChange: status = " + status);

            if (status == "AUTH SUCCEED") {
              var username = bag2.getPropertyAsACString("__mutual_username");
              var algorithm = bag2.getPropertyAsACString("__mutual_authRealm_algorithm");
              var authDomain = bag2.getPropertyAsACString("__mutual_authRealm_authDomain");
              var realm = bag2.getPropertyAsACString("__mutual_authRealm_realm");

              LOG("onLocationChange: username = " + username);
              LOG("onLocationChange: algorithm = " + algorithm);
              LOG("onLocationChange: authDomain = " + authDomain);
              LOG("onLocationChange: realm = " + realm);

              var authStatus = this.browser.__mutual_authStatus;
              authStatus.isTopLevelAuthSucceed = true;
              authStatus.topLevelUri = location;
              authStatus.topLevelUsername = username;
              authStatus.topLevelAuthRealm = {
                algorithm: algorithm,
                authDomain: authDomain,
                realm: realm
              };

              if (bag2.hasKey("__mutual_logout_location")) {
                var ll = this.browser.__mutual_logout_location = bag2.getPropertyAsACString("__mutual_logout_location");
                LOG("onLocationChange: logout_location = " + ll);
              }
            }

            if (status == "AUTH REQUESTED" && bag2.hasKey("__mutual_auth_challenge")) {

              var wwwAuthenticateString = bag2.getPropertyAsACString("__mutual_auth_challenge");

              LOG("wwwAuthenticateString = " + wwwAuthenticateString);

              this.browser.__mutual_needAuth = true;
              this.browser.__mutual_authUri = location;
              this.browser.__mutual_authChallenge = wwwAuthenticateString;

              if (bag2.hasKey("__mutual_input_username")) {
                var username = bag2.getPropertyAsACString("__mutual_input_username");
                this.browser.__mutual_inputUsername = username;
              }
              LOG("Activate!");
            }
          } catch(ex) {
            LOG("exception ignored intentionally: " + ex);
          }
        }

        __mutual_updateUI();

        LOG("onLocationChange: finish.");
      },

      onProgressChange: function onProgressChange(webProgress,
                                                  request,
                                                  curSelfProgress,
                                                  maxSelfProgress,
                                                  curTotalProgress,
                                                  maxTotalProgress)
      {
      },

      onSecurityChange: function onSecurityChange(webProgress, request, state)
      {
      },

      onStateChange: function onStateChange(webProgress, request, stateFlags, status)
      {
        var wpl = Components.interfaces.nsIWebProgressListener;
        if (stateFlags == (wpl.STATE_IS_WINDOW | wpl.STATE_IS_NETWORK | wpl.STATE_STOP)) {
          LOG("update from onStateChange");
          __mutual_updateUI();
        }
      },

      onStatusChange: function onStatusChange(webProgress, request, status, message)
      {
      }
    };


    var __mutual_window_loadListener = {
      handleEvent: function handleEvent(e)
      {
        LOG("load: handleEvent");

        var tabOpened = function tabOpened (event) {
          var browser = event.target.linkedBrowser;
          LOG("tabOpened: " + browser);
          new mutualProgressListener(browser);
        };

        var tabSelected = function tabSelected (event) {
          LOG("tabSelected");
          var browser = gBrowser.selectedTab.linkedBrowser;
          __mutual_updateUI();
        };

        var container = gBrowser.tabContainer;
        container.addEventListener("TabSelect", tabSelected, false);
        container.addEventListener("TabOpen",   tabOpened,   false);

        for(var i = 0 ; i < gBrowser.browsers.length; i++){
          var browser = gBrowser.getBrowserAtIndex(i);
          new mutualProgressListener(browser);
        }

        var originalToolboxCustomizeDone = BrowserToolboxCustomizeDone;
        BrowserToolboxCustomizeDone = function proxyBrowserToolboxCustomizeDone(aToolboxChanged) {
          __mutual_updateUI();
          originalToolboxCustomizeDone(aToolboxChanged);
          }
      }
    };
    window.addEventListener("load", __mutual_window_loadListener, false);


    var __mutual_window_unloadListener = {
      handleEvent: function handleEvent(e)
      {
        LOG("unload: handleEvent");
      }
    };
    window.addEventListener("unload", __mutual_window_unloadListener, false);


    /************************************************************
      UI functions
     ************************************************************/

    var __mutual_start_auth = function __mutual_start_auth() {
      var button = document.getElementById("mutual-submit-button");
      button.focus();

      var browser = gBrowser.selectedBrowser;

      var mutualBox = document.getElementById("mutual-border-box");
      if (mutualBox.getAttribute("status") == "loggedin-safe")
      {
        LOG("__mutual_start_auth: logging out");
        var authManager = Components.classes["@mozilla.org/network/http-auth-manager;1"]
                                    .getService(Components.interfaces.nsIHttpAuthManager);
        var authStatus = browser.__mutual_authStatus;
        var uri = authStatus.topLevelUri;

        authManager.clearAuthIdentity(
          uri.scheme,
          uri.asciiHost,
          mutualAuth.getPortFromUri(uri),
          mutualAuth.authScheme,
          authStatus.topLevelAuthRealm.realm
          );
        if (browser.__mutual_logout_location) {
          LOG("__mutual_start_auth: logout location = " + browser.__mutual_logout_location);
          browser.contentWindow.location.assign(browser.__mutual_logout_location);
        } else {
          browser.reload();
        }
        return;
      }

      var username, password;
      {
        var inputError = false;

        if (!__mutual_username_textbox.isEmpty()) {
          username = __mutual_username_textbox.getText();
        } else {
          __mutual_username_textbox.setError();
          LOG("*** ERROR ***: Empty username.");
          inputError = true;
        }

        if (!__mutual_password_textbox.isEmpty()) {
          password = __mutual_password_textbox.getText();
        } else {
          __mutual_password_textbox.setError();
          LOG("*** ERROR ***: Empty password.");
          inputError = true;
        }

        if(inputError){
          return;
        }
      }

      var uri = browser.__mutual_authUri;
      var challengeStr = browser.__mutual_authChallenge;

      var b = document.getElementById("mutual-submit-button");
      b.setAttribute("working", "working");
      try{
        mutualAuth.doAuth(uri, challengeStr, username, password);
      }catch(ex){
        b.removeAttribute("working");
      }
    };

    var __mutual_textbox = function __mutual_textbox (name, isPassword) {
      this.name = name;
      if (isPassword) this.isPassword = true;

      var self = this;
      var loadListener  = function loadListener  () {
        window.removeEventListener("load", loadListener, false);
        var e = self.getElement();
        e.addEventListener("focus", function onFocusProxy() { self.onFocus(); }, false);
        e.addEventListener("blur", function onBlurProxy() { self.onBlur(); }, false);
      }

      window.addEventListener("load", loadListener, false);
    };

    __mutual_textbox.prototype = {
      getElement: function getElement()
      {
        return document.getElementById(this.name);
      },

      setError: function setError()
      {
        var e = this.getElement();
        e.setAttribute("error", "error");
      },

      clearError: function clearError()
      {
        var e = this.getElement();
        e.removeAttribute("error");
      },

      onFocus: function onFocus()
      {
        var e = this.getElement();
        if (this.isPassword) {
          e.setAttribute("type", "password");
        }
        this.clearError();
      },

      onBlur: function onBlur()
      {
        var e = this.getElement();
        if (this.isPassword && this.isEmpty()) {
          e.removeAttribute("type");
        }
        this.clearError();
      },

      isEmpty: function isEmpty()
      {
        var e = this.getElement();
        return e.hasAttribute("isempty") && e.getAttribute("isempty") == "true";
      },

      getText: function getText()
      {
        if (this.isEmpty()) return "";

        var e = this.getElement();
        return e.value;
      }
    };

    var __mutual_username_textbox = new __mutual_textbox("mutual-username-textbox");
    var __mutual_password_textbox = new __mutual_textbox("mutual-password-textbox",
                                                         true);

  } catch(ex) {
    LOG(ex);
  }
}
