// BEGIN FLOCK GPL
//
// Copyright Flock Inc. 2005-2009
// http://flock.com
//
// This file may be used under the terms of the
// GNU General Public License Version 2 or later (the "GPL"),
// http://www.gnu.org/licenses/gpl.html
//
// 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.
//
// END FLOCK GPL

/**
 * notificationOverlay - Object that handles the alert notifications for flock services.
 */

const FLOCK_PARTNER_EDITION_PREF = "general.useragent.edition";

Components.utils.import("resource:///modules/FlockPrefsUtils.jsm");

var notificationOverlay = {
  DEBUG : false,    // Change to true to enable dumps

  observerService : null,
  prefService: null,
  wsMgr : null,
  mBranch: null,
  mSrv: null,
  _flashTimer: null,
  debug: function (aMessage) {
    if (this.DEBUG) { dump("notificationOverlay.js: " + aMessage + "\n"); }
  },

  // "Constant" for the stringbundle used most in this file.
  SB: "common/notificationOverlay",

  init: function() {
    this.debug("init()");
    this.observerService = Components.classes["@mozilla.org/observer-service;1"]
                                     .getService(Components.interfaces.nsIObserverService);
    this.observerService.addObserver(this, 'notificationCountChanged', false);
    this.observerService.addObserver(this, 'new-stuff-notification', false);
    this.observerService.addObserver(this, "new-people-notification", false);
    this.observerService.addObserver(this, "new-webmail-notification", false);
    this.observerService.addObserver(this, 'test-notification', false);

    this.coop = Components.classes["@flock.com/singleton;1"]
                          .getService(Components.interfaces.flockISingleton)
                          .getSingleton("chrome://flock/content/common/load-faves-coop.js")
                          .wrappedJSObject;

    this.observe(null, "notificationCountChanged", this.coop.accounts_root.id());
    this.observe(null, "notificationCountChanged", this.coop.my_flock.id());
    // Register to receive notifications of preference changes
    this.prefService = Components.classes["@mozilla.org/preferences-service;1"]
                       .getService(Components.interfaces.nsIPrefService);
    //adding observer on pref branch flock.notification.show.accounts
    this.mBranch = this.prefService.getBranch("flock.notification.show.accounts");
    this.mBranch.QueryInterface(Components.interfaces.nsIPrefBranch2);
    this.mBranch.addObserver("", this, false);
    this.wsMgr = Components.classes["@flock.com/webservice-manager;1"]
                           .getService(Components.interfaces.flockIWebServiceManager);
    this._isFirstAuthForService = false;
    this.wsMgr.addListener(this);
    this.setPeopleIconState();
  },

  uninit: function() {
    this.debug("uninit()");
    if (this.observerService != null) {
      this.observerService.removeObserver(this, 'notificationCountChanged');
      this.observerService.removeObserver(this, 'new-stuff-notification');
      this.observerService.removeObserver(this, "new-people-notification");
      this.observerService.removeObserver(this, "new-webmail-notification");
      this.observerService.removeObserver(this, 'test-notification');
    }
    if (this.mBranch) {
      this.mBranch.removeObserver("", this, false);
    }
    if (this.wsMgr != null) {
      this.wsMgr.removeListener(this);
    }
  },

  observe: function (aSubject, aTopic, aData) {
    this.debug("observe - " + aTopic);
    switch (aTopic) {
      case 'notificationCountChanged':
        switch (aData) {
          case this.coop.my_flock.id():
            document.getElementById('flock_PeopleNotificationBroadcaster').setAttribute('totalcount',  '(' + this.coop.my_flock.count + ')');
            document.getElementById('flock_PeopleNotificationBroadcaster').setAttribute('label', '(' + this.coop.my_flock.unseenItems + ')');
            break;
          case this.coop.accounts_root.id():
            document.getElementById('flock_MeNotificationBroadcaster').setAttribute('totalcount',  '(' + this.coop.accounts_root.count + ')');
            document.getElementById('flock_MeNotificationBroadcaster').setAttribute('label', '(' + this.coop.accounts_root.unseenItems + ')');
            break;
        }
        break;
        case 'nsPref:changed':
          if(this.mSrv)
          {
            var prefName = "flock.notification.show.accounts.account-setup-info-" + this.mSrv.shortName;
            if (this.prefService.getPrefType(prefName) && !this.prefService.getBoolPref(prefName) && this.mSrv.shortName != null)
              { 
                      // Pop the message bar
                      var notificationBox = gBrowser.getNotificationBox();
                      var links = [{
                         label: flockGetString(this.SB,"account.openSidebar"),
                         callback: function() { toggleSidebarWithMetric("flock_AccountsSidebarBroadcaster",
                                                                        "AccountSidebar-Open",
                                                                        null,
                                                                        "NewServiceAddDontShowDiscovery",
                                                                        true); }
                       }];
                      
                      var appName = brandGetString("brand", "brandShortName");
                      var message = flockGetString(this.SB,
                                                   "accounts.checkBoxClicked.label",
                                                   [appName,
                                                   this.mSrv.title]);
                      notificationBox.appendUniqueNotification(message, "account-remove-success-" + this.mSrv.shortName, 
                                                        (document.getElementById("page-proxy-favicon"))?document.getElementById("page-proxy-favicon").src:null,
                                                        notificationBox.FLOCK_PRIORITY_MEDIUM, null, links, null, true);
                }else if(this.prefService.getPrefType(prefName) && this.prefService.getBoolPref(prefName) && this.mSrv.shortName != null)
                {
                  var notificationBox = gBrowser.getNotificationBox();
                  notificationBox.removeCurrentNotification( "account-remove-success-" + this.mSrv.shortName);
                }
              }
          break;
      case 'new-stuff-notification':
        var service;
        var alertMessage;
        var alertTitle;
        var alertURL;
        var alertIcon;
        var notificationType;
        var notificationObj = this.coop.get(aData);
        var clickListener = {
          observe: function(subject, topic, data) {
            switch (topic) {  
              case "alertclickcallback":
              openUILinkIn(data, 'tab');
              break;
            }
          }
        }
        if (notificationObj) {
            notificationType = notificationObj.name;
            alertTitle = notificationObj.title;
            alertMessage =  notificationObj.description;
            alertIcon = notificationObj.favicon;
            alertURL = notificationObj.URL;
            this.showNotification(alertIcon, alertTitle, alertMessage, alertURL, clickListener);
        }
        break;
      case 'new-people-notification':
        var peopleButton = document.getElementById("people-button");
        // Is the people button on the chrome?
        if (!peopleButton) {
          return;
        }
        if (aData == "true") {
          peopleButton.setAttribute("hasNew", "true");
        } else {
          peopleButton.removeAttribute("hasNew");
        }
        break;
      case "new-webmail-notification":
        var webmailButton = document.getElementById("webmail-button");
        if (webmailButton) {
          if (aData == "true") {
            webmailButton.setAttribute("hasNew", "true");
          } else {
            webmailButton.removeAttribute("hasNew");
          }
        }
        break;
      case 'test-notification':
        var clickListener = {
          observe: function(subject, topic, data) {
            switch (topic) {
              case "alertclickcallback":
              openUILinkIn(data, 'tab');
              break;
            }
          }
        }
        var alertTitle = "Test Message";
        var alertMessage =  "This is a test notification, click to goto http://www.flock.com";
        var alertIcon = "http://x.myspace.com/images/icon_envelope.gif";
        var alertURL = "http://www.flock.com";
        this.showNotification(alertIcon, alertTitle, alertMessage, alertURL, clickListener);
        break;

      }
    },

    QueryInterface : function (aIID) {
      if ( !aIID.equals(Components.interfaces.nsISupports) &&
           !aIID.equals(Components.interfaces.nsIObserver) &&
           !aIID.equals(Components.interfaces.flockIWebServiceAccountListener) )
      {
        throw Components.results.NS_ERROR_NO_INTERFACE;
      }
      return this;
    },

    // BEGIN flockIWebServiceAccountListener
    onAccountCreated : function (aAccount, aDocument) {
      // First check whether this account is transient (ie., whether is has
      // already been "Remembered").  Below, we will suppress the first message
      // bar unless this account is transient.
      var accountIsTransient = aAccount.getParam("isTransient");

      this._isFirstAuthForService = true;

      // Find the tab that contains aDocument
      var tabbrowser = getBrowser();
      var browsers = tabbrowser.mPanelContainer.childNodes;
      var window = aDocument.defaultView;
      while (window.parent != window) { window = window.parent; }
      var svc = aAccount.getService();
      for (var i = 0; i < browsers.length; i++) {
        var browser = tabbrowser.getBrowserAtIndex(i);
        if (browser.contentWindow == window) {
          // Pop the message bar
          var nBox = gBrowser.getNotificationBox(browser);
          this.mSrv = svc; 
          var bar1Label;
          var bar1Button1;
          var bar1Links;
          var appName = brandGetString("brand", "brandShortName");
          var bar1Button1Accesskey;
          var serviceName = svc.title;

          if (svc instanceof Components.interfaces.flockIBookmarkWebService) {
            bar1Label = flockGetString(this.SB,
                                       "favs.bar1.label",
                                       [serviceName, appName]);
            bar1Button1 = flockGetString(this.SB, "favs.bar1.button1");
            bar1Button1Accesskey = flockGetString(this.SB,
                                                  "favs.bar1.button1.accesskey");
          } else if (svc instanceof Components.interfaces.flockIBlogWebService) {
            bar1Label = flockGetString(this.SB,
                                       "blog.bar1.label",
                                       [appName, serviceName, appName]);
            bar1Button1 = flockGetString(this.SB, "blog.bar1.button1");
            bar1Button1Accesskey = flockGetString(this.SB,
                                                  "blog.bar1.button1.accesskey");
          } else if (svc instanceof Components.interfaces.flockISocialWebService) {
            bar1Label = flockGetString(this.SB,
                                       "social.bar1.label",
                                       [appName,
                                        serviceName,
                                        serviceName,
                                        appName,
                                        serviceName]);
            bar1Button1 = flockGetString(this.SB, "social.bar1.button1");
            bar1Button1Accesskey = flockGetString(this.SB,
                                                  "social.bar1.button1.accesskey");
          } else if (svc instanceof Components.interfaces.flockIMediaWebService) {
            bar1Label = flockGetString(this.SB,
                                       "media.bar1.label",
                                       [appName, serviceName, appName]);
            bar1Button1 = flockGetString(this.SB, "media.bar1.button1");
            bar1Button1Accesskey = flockGetString(this.SB,
                                                  "media.bar1.button1.accesskey");
          } else if (svc instanceof Components.interfaces.flockIMailWebService) {
            bar1Label = flockGetString(this.SB, "mail.bar1.label", [appName, serviceName]);
            bar1Button1 = flockGetString(this.SB, "mail.bar1.button1");
            bar1Button1Accesskey = flockGetString(this.SB,
                                                  "mail.bar1.button1.accesskey");
          } else {
            bar1Label = "We need to add a message for your " + serviceName +
                        " account here. Please tell the developers.";
            bar1Button1 = "Remember this account";
            bar1Button1Accesskey = "R";
          }

          // Try to get favicon from auth code.
          var favicon = null;
          try {
            favicon = document.getElementById("page-proxy-favicon").src;
          } catch (ex) {
          }

          // IF auth code isn't giving us a favicon
          // THEN get it from the service.
          if (!favicon && svc.icon) {
            favicon = svc.icon;
          }

          // IF the service has autoKeepAccounts set
          // THEN automatically keep the account
          var autoKeepAccountPref =
            "flock.service." + svc.shortName + ".autoKeepAccounts";
          if (FlockPrefsUtils.getBoolPref(autoKeepAccountPref)) {
            aAccount.keep();
          } else if (accountIsTransient) {
            // First we want to show a message bar giving the user a chance to
            // remember the account.
            var bar1Buttons = [{
              label: bar1Button1,
              accessKey: bar1Button1Accesskey,
              popup: null,
              callback: function () {
                aAccount.keep();
              }
            }];

            var inst = this;

            // Listener for the case where the user clicks the close button on
            // a "Remember Account" notie. In this case we will stop bugging the
            // user with the "Remember Account" notie for the duration of the
            // session.
            function rememberAccountNotieResponseHandler(aEvt) {
              var notie = aEvt.target;
              if (notie.mUserResponse == notie.USER_RESPONSE_CLOSE_CLICKED) {
                inst.wsMgr.suppressNotiesForAccount(aAccount.urn);
              }
            }

            function rememberAccountNotie() {
              var lm = Cc["@mozilla.org/login-manager;1"]
                       .getService(Ci.nsILoginManager);
              // First see if the user has remembered the password
              var accountId =  aAccount.getParam("accountId");
              var acUtils = Cc["@flock.com/account-utils;1"]
                           .getService(Ci.flockIAccountUtils);
              var pw = acUtils.getTempPassword(svc.urn + ":" + accountId);
              if (!aAccount.getParam("isTransient")) {
                // The user has already clicked on Remember me in the A&S
                return;
              }
              for each (var login in lm.getAllLogins({})) {
                if (!pw || login.password != pw.password) {
                  continue;
                }
                for each (var domain in svc.domains.split(",")) {
                  var lengthDiff = login.hostname.length - domain.length;
                  var index = login.hostname.indexOf(domain, lengthDiff);
                  var previous = (index != -1) ? login.hostname[index - 1] : "";
                  if (previous == "/" || previous == ".") {
                    aAccount.keep();
                    return;
                  }
                }
              }

              if (inst.wsMgr.isShowingNotiesForAccount(aAccount.urn)) {
                // Remove the existing notie if there is one.
                var oldNotie = nBox.getNotificationWithValue("accounts.account-setup-info-" 
                                                               + svc.shortName);
                if (oldNotie) {
                  nBox.removeNotification(oldNotie);
                }

                var notie = nBox.appendUniqueNotification(bar1Label,
                                                          "accounts.account-setup-info-"
                                                            + svc.shortName,
                                                          favicon,
                                                          nBox.FLOCK_PRIORITY_MEDIUM,
                                                          bar1Buttons,
                                                          bar1Links,
                                                          aDocument.documentURI,
                                                          true);
                notie.addEventListener("NotificationResponseReceived",
                                       rememberAccountNotieResponseHandler,
                                       false);
              }
            }

            // To avoid bombarding the user with noties we only show the
            // "Remember Account" notie once the user has responded to 
            // the "Remember Password" notie.
            var passwordNotie = nBox.getNotificationWithValue("password-save");
            if (passwordNotie) {
              passwordNotie.addEventListener("NotificationResponseReceived",
                                             rememberAccountNotie,
                                             false);
            } else {
              rememberAccountNotie();
            }

          }
          break;
        }
      }

    },

    onAccountPasswordMissing : function (aService, aDocument) {
      // Find the tab that contains aDocument
      var tabbrowser = getBrowser();
      var browsers = tabbrowser.mPanelContainer.childNodes;
      var window = aDocument.defaultView;
      while (window.parent != window) { window = window.parent; }
      var i = 0;
      for (; i < browsers.length; i++) {
        if (tabbrowser.getBrowserAtIndex(i).contentWindow == window) {
          // Pop the message bar
          var browser = tabbrowser.getBrowserAtIndex(i);
          var notificationBox = gBrowser.getNotificationBox(browser);
          var appName = brandGetString("brand", "brandShortName");
          var message = null;
          var svcBundle = aService.getStringBundle();
          if (svcBundle) {
            try {
              // The service may have overridden the "account.logout" message.
              message =  getStringFromBundle(svcBundle,
                                             "account.logout",
                                             [aService.title,
                                             appName,
                                             aService.title,
                                             appName]);
            } catch (ex) {
              // The service did not override the message.
            }
          }
          if (!message) {
            // Get the default "account.logout" message.
            message = flockGetString(this.SB,
                                     "account.logout",
                                     [aService.title,
                                     appName,
                                     aService.title,
                                     appName]);
          }

          var buttons = [{
            label: flockGetString(this.SB, "account.logout.button"),
            accessKey: flockGetString(this.SB,
                                      "account.logout.button.accesskey"),
            popup: null,
            callback: function () {
              aService.logout();
              browser.reload();
            }
          }];
          var notieIcon = (document.getElementById("page-proxy-favicon"))
                        ? document.getElementById("page-proxy-favicon").src 
                        : null;
          notificationBox.appendUniqueNotification(message,
                                                   "account-setup-info",
                                                   notieIcon,
                                                   notificationBox.PRIORITY_INFO_MEDIUM,
                                                   buttons,
                                                   null,
                                                   aDocument.documentURI);
          break;
        }
      }
    },

    onAccountRemoved : function (aAccount) {
    },

    onAccountAuthChange : function (aAccount) {
      if (!this._isFirstAuthForService) {
        // Don't do anything if it's not the first auth
        return;
      }

      var wm = Cc["@mozilla.org/appshell/window-mediator;1"]
               .getService(Ci.nsIWindowMediator);
      var win = wm.getMostRecentWindow("navigator:browser");

      // Since accounts may implement more than one interface,
      // the order of the if/else if matters:
      // it shows the priority of various types;
      // Social > Media > the rest
      if (aAccount instanceof Ci.flockISocialAccount) {
        var psbBroadcaster = win.document
                                .getElementById("flockPeopleSidebarBroadcaster");
        // Open the people bar
        if (win) {
          // this will select the newly added tab in the people sidebar if the
          // people sidebar is not already open
          if (!psbBroadcaster.hasAttribute("checked")) {
            psbBroadcaster.setAttribute("newAccountId",
                                        aAccount.getParam("accountId"));
          }

          win.toggleSidebarWithMetric("flockPeopleSidebarBroadcaster",
                                      "PeopleSidebar-Open",
                                      null,
                                      "NewSocialWebServiceDiscovery",
                                      true);
        }
      } else if (aAccount instanceof Ci.flockIMediaAccount) {
        // Show the user's photos in the mediabar
        if (win) {
          win.mediabar.load(aAccount);
        }
      }

      this._isFirstAuthForService = false;
    },
    // END flockIWebServiceAccountListener


    /**
     * showNotification - Actually displays the alertWindow with the nsIAlertsService
     *
     * @param aIconUrl URL to the icon we are going to display on the left
     * @param aAlertTitle Title of the alert
     * @param aAlertText Message to display (possibly clickable)
     * @param gotoUrl URL to load when aAlertText is clicked
     * @param aListener Listener object to callback to.
     */
    showNotification : function (aIconUrl, aAlertTitle, aAlertText, gotoUrl, aListener) {
      if (Components.classes["@mozilla.org/alerts-service;1"]) {
        // Only works for GTK and Window Toolkits?
        var alertsService = Components.classes["@mozilla.org/alerts-service;1"]
                                    .getService(Components.interfaces.nsIAlertsService);
        alertsService.showAlertNotification(aIconUrl,
                                          aAlertTitle,
                                          aAlertText,
                                          true,
                                          gotoUrl,
                                          aListener);
      } else {
        // STEVO: Hack to display alerts on OS X, nsIAlertsService is not compiled on OSX?
        //        We have to find a way to get nsIAlertsService to compile on OSX (it has something to do with the toolkit)
        window.openDialog("chrome://global/content/alerts/alert.xul", "_blank", "chrome,dialog=yes,titlebar=no,popup=yes",
                        aIconUrl,
                        aAlertTitle,
                        aAlertText,
                        true,
                        gotoUrl,
                        aListener);
      }
    },

    /**
     * handleEvent - Handles events attached to this object only onload/onunload are currently handled.
     *
     * @param aEvent Event object (.type holds the event that was triggered)
     */
    handleEvent: function(aEvent) {
      this.debug("handleEvent - " + aEvent.type);
      switch (aEvent.type) {
        case 'load':
          this.init();
          break;
        case 'unload':
          this.uninit();
          break;
        default:
          this.debug("unhandled event - " + aEvent.type);
          break;
      }
    },

  getNotificationBox: function no_getNotificationBox() {
    var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
                       .getService(Components.interfaces.nsIWindowMediator);
    var win = wm.getMostRecentWindow("navigator:browser");
    if (win) {
      return gBrowser.getNotificationBox();
    }
    return null;
  },

  flash: function notification_flash(aCount, aElement) {
    var children = aElement.getElementsByTagName("menuitem");
    if (aCount == 0) {
      aElement.setAttribute("flashing", "true");
    } else {
      var lastActiveIndex = (aCount - 1) % children.length;
      children[lastActiveIndex].removeAttribute("active");
    }
    if (aCount >= 10) {
      aElement.removeAttribute("flashing");
      this._flashTimer = null;
      return;
    }

    var activeIndex = aCount % children.length;
    children[activeIndex].setAttribute("active", "true");
    var count = aCount + 1;
    var callback = {
      notify: function flash_timeoutcallback() {
        notificationOverlay.flash(count, aElement);
      }
    }
    this._flashTimer = Cc["@mozilla.org/timer;1"]
                       .createInstance(Ci.nsITimer);
    this._flashTimer.initWithCallback(callback,
                                      500,
                                      Ci.nsITimer.TYPE_ONE_SHOT);
  },

  stopFlash: function notification_stopFlash() {
    if (this._flashTimer) {
      this._flashTimer.cancel();
    }
  },

  // Set the initial state of the people icon.
  setPeopleIconState: function no_setPeopleIconState() {
    var ppSvc = Components.classes["@flock.com/people-service;1"]
                .getService(Components.interfaces.flockIPeopleService);

    if (ppSvc.peopleIconLit) {
      ppSvc.togglePeopleIcon(true);
    }
  }
};

window.addEventListener("load", notificationOverlay, false);
window.addEventListener("unload", notificationOverlay, false);
