/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.import("resource:///modules/iteratorUtils.jsm");

// Copied from nsILookAndFeel.h, see comments on eMetric_AlertNotificationOrigin
var NS_ALERT_HORIZONTAL = 1;
var NS_ALERT_LEFT = 2;
var NS_ALERT_TOP = 4;

var gNumNewMsgsToShowInAlert = 4; // the more messages we show in the alert, the larger it will be
var gOpenTime = 4000; // total time the alert should stay up once we are done animating.

var gAlertListener = null;
var gPendingPreviewFetchRequests = 0;
var gUserInitiated = false;
var gOrigin = 0; // Default value: alert from bottom right.

function prefillAlertInfo()
{
  const Ci = Components.interfaces;
  // unwrap all the args....
  // arguments[0] --> nsIArray of folders with new mail
  // arguments[1] --> the observer to call back with notifications about the alert
  // arguments[2] --> user initiated boolean. true if the user initiated opening the alert
  //                 (which means skip the fade effect and don't auto close the alert)
  // arguments[3] --> the alert origin returned by the look and feel
  var foldersWithNewMail = window.arguments[0];
  gAlertListener = window.arguments[1];
  gUserInitiated = window.arguments[2];
  gOrigin = window.arguments[3];

  // For now just grab the first folder which should be a root folder
  // for the account that has new mail. If we can't find a folder, just
  // return to avoid the exception and empty dialog in upper left-hand corner.
  if (!foldersWithNewMail || foldersWithNewMail.length < 1)
    return;
  let rootFolder = foldersWithNewMail.queryElementAt(0, Ci.nsIWeakReference)
                                     .QueryReferent(Ci.nsIMsgFolder);

  // Generate an account label string based on the root folder.
  var label = document.getElementById('alertTitle');
  var totalNumNewMessages = rootFolder.getNumNewMessages(true);
  var message = totalNumNewMessages == 1 ? "newMailNotification_message"
                                         : "newMailNotification_messages";
  label.value = document.getElementById('bundle_messenger')
                        .getFormattedString(message,
                                            [rootFolder.prettiestName,
                                             totalNumNewMessages]);

  // This is really the root folder and we have to walk through the list to
  // find the real folder that has new mail in it...:(
  let allFolders = rootFolder.descendants;
  var folderSummaryInfoEl = document.getElementById('folderSummaryInfo');
  folderSummaryInfoEl.mMaxMsgHdrsInPopup = gNumNewMsgsToShowInAlert;
  for (let folder in fixIterator(allFolders, Components.interfaces.nsIMsgFolder))
  {
    if (folder.hasNewMessages) {
      let notify =
        // Any folder which is an inbox or ...
        folder.getFlag(Ci.nsMsgFolderFlags.Inbox) ||
        // any non-special or non-virtual folder. In other words, we don't
        // notify for Drafts|Trash|SentMail|Templates|Junk|Archive|Queue or virtual.
        !(folder.flags & (Ci.nsMsgFolderFlags.SpecialUse | Ci.nsMsgFolderFlags.Virtual));

      if (notify) {
        var asyncFetch = {};
        folderSummaryInfoEl.parseFolder(folder, new urlListener(folder), asyncFetch);
        if (asyncFetch.value)
          gPendingPreviewFetchRequests++;
      }
    }
  }
}

function urlListener(aFolder)
{
  this.mFolder = aFolder;
}

urlListener.prototype =
{
  OnStartRunningUrl: function(aUrl)
  {
  },

  OnStopRunningUrl: function(aUrl, aExitCode)
  {
    var folderSummaryInfoEl = document.getElementById('folderSummaryInfo');
    folderSummaryInfoEl.parseFolder(this.mFolder, null, {});
    gPendingPreviewFetchRequests--;

    // when we are done running all of our urls for fetching the preview text,
    // start the alert.
    if (!gPendingPreviewFetchRequests)
      showAlert();
  }
}

function onAlertLoad()
{
  prefillAlertInfo();
  // read out our initial settings from prefs.
  try
  {
    gOpenTime = Services.prefs.getIntPref("alerts.totalOpenTime");
  } catch (ex) {}

  // bogus call to make sure the window is moved offscreen until we are ready for it.
  resizeAlert(true);

  // if we aren't waiting to fetch preview text, then go ahead and
  // start showing the alert.
  if (!gPendingPreviewFetchRequests)
    setTimeout(showAlert, 0); // let the JS thread unwind, to give layout
                              // a chance to recompute the styles and widths for our alert text.
}

// If the user initiated the alert, show it right away, otherwise start opening the alert with
// the fade effect.
function showAlert()
{
  if (!document.getElementById("folderSummaryInfo").hasMessages) {
    closeAlert(); // no mail, so don't bother showing the alert...
    return;
  }

  // resize the alert based on our current content
  resizeAlert(false);

  var alertContainer = document.getElementById("alertContainer");
  // Don't fade in if the user opened the alert or the pref is true.
  if (gUserInitiated ||
      Services.prefs.getBoolPref("alerts.disableSlidingEffect")) {
    alertContainer.setAttribute("noanimation", true);
    setTimeout(closeAlert, gOpenTime);
    return;
  }

  alertContainer.addEventListener("animationend", function hideAlert(event) {
    if (event.animationName == "fade-in") {
      alertContainer.removeEventListener("animationend", hideAlert, false);
      let remaining = Math.max(Math.round(gOpenTime - event.elapsedTime * 1000), 0);
      setTimeout(fadeOutAlert, remaining);
    }
  }, false);
  alertContainer.setAttribute("fade-in", true);
}

function resizeAlert(aMoveOffScreen)
{
  var alertTextBox = document.getElementById("alertTextBox");
  var alertImageBox = document.getElementById("alertImageBox");
  alertImageBox.style.minHeight = alertTextBox.scrollHeight + "px";

  sizeToContent();

  // leftover hack to get the window properly hidden when we first open it
  if (aMoveOffScreen)
    window.outerHeight = 1;

  // Determine position
  var x = gOrigin & NS_ALERT_LEFT ? screen.availLeft :
          screen.availLeft + screen.availWidth - window.outerWidth;
  var y = gOrigin & NS_ALERT_TOP ? screen.availTop :
          screen.availTop + screen.availHeight - window.outerHeight;

  // Offset the alert by 10 pixels from the edge of the screen
  y += gOrigin & NS_ALERT_TOP ? 10 : -10;
  x += gOrigin & NS_ALERT_LEFT ? 10 : -10;

  window.moveTo(x, y);
}

function fadeOutAlert()
{
  var alertContainer = document.getElementById("alertContainer");
  alertContainer.addEventListener("animationend", function fadeOut(event) {
    if (event.animationName == "fade-out") {
      alertContainer.removeEventListener("animationend", fadeOut, false);
      closeAlert();
    }
  }, false);
  alertContainer.setAttribute("fade-out", true);
}

function closeAlert()
{
  if (gAlertListener)
    gAlertListener.observe(null, "alertfinished", "");
  window.close();
}
