/* 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/. */

top.MAX_RECIPIENTS = 1;
var inputElementType = "";

var gListCard;
var gEditList;
var oldListName = "";
var gLoadListeners = [];
var gSaveListeners = [];

try
{
  var gDragService = Components.classes["@mozilla.org/widget/dragservice;1"]
                               .getService(Components.interfaces.nsIDragService);
}
catch (e)
{
}

// Returns the load context for the current window
function getLoadContext() {
  return window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
               .getInterface(Components.interfaces.nsIWebNavigation)
               .QueryInterface(Components.interfaces.nsILoadContext);
}

function handleKeyPress(element, event)
{
  // allow dialog to close on enter if focused textbox has no value
  if (element.value != "" && event.keyCode == 13) {
    event.stopPropagation();
    event.preventDefault();
  }
}

function mailingListExists(listname)
{
  if (MailServices.ab.mailListNameExists(listname))
  {
    Services.prompt.alert(window,
      gAddressBookBundle.getString("mailListNameExistsTitle"),
      gAddressBookBundle.getString("mailListNameExistsMessage"));
    return true;
  }
  return false;
}

function GetListValue(mailList, doAdd)
{
  var listname = document.getElementById("ListName").value.trim();

  if (listname.length == 0)
  {
    var alertText = gAddressBookBundle.getString("emptyListName");
    alert(alertText);
    return false;
  }
  else
  {
    var canonicalNewListName = listname.toLowerCase();
    var canonicalOldListName = oldListName.toLowerCase();
    if (doAdd)
    {
      if (mailingListExists(canonicalNewListName))
        return false;
    }
    else if (canonicalOldListName != canonicalNewListName)
    {
      if (mailingListExists(canonicalNewListName))
        return false;
    }
  }

  mailList.isMailList = true;
  mailList.dirName = listname;
  mailList.listNickName = document.getElementById('ListNickName').value;
  mailList.description = document.getElementById('ListDescription').value;

  var oldTotal = mailList.addressLists.length;
  var i = 1;
  var pos = 0;
  var inputField, fieldValue, cardproperty;
  while ((inputField = awGetInputElement(i)))
  {

    fieldValue = inputField.value;

    if (doAdd || (!doAdd && pos >= oldTotal))
      cardproperty = Components.classes["@mozilla.org/addressbook/cardproperty;1"].createInstance();
    else
      cardproperty = mailList.addressLists.queryElementAt(pos, Components.interfaces.nsIAbCard);

    if (fieldValue == "")
    {
      if (!doAdd && cardproperty)
      try
      {
        mailList.addressLists.removeElementAt(pos);
      }
      catch(ex)
      {
        // Ignore attempting to remove an item
        // at a position greater than the number
        // of elements in the addressLists attribute
      }
    }
    else if (cardproperty)
    {
      cardproperty = cardproperty.QueryInterface(Components.interfaces.nsIAbCard);
      if (cardproperty)
      {
        let addrObjects = MailServices.headerParser
                                      .makeFromDisplayAddress(fieldValue, {});
        for (let j = 0; j < addrObjects.length; j++)
        {
          if (j > 0)
          {
            cardproperty = Components.classes["@mozilla.org/addressbook/cardproperty;1"].createInstance();
            cardproperty = cardproperty.QueryInterface(Components.interfaces.nsIAbCard);
          }
          cardproperty.primaryEmail = addrObjects[j].email;
          cardproperty.displayName = addrObjects[j].name || addrObjects[j].email;

          if (doAdd || (doAdd == false && pos >= oldTotal))
            mailList.addressLists.appendElement(cardproperty, false);
        }
        pos++;
      }
    }
    i++;
  }

  --i;

  if (doAdd == false && i < oldTotal)
  {
    for (var j = i; j < oldTotal; j++)
      mailList.addressLists.removeElementAt(j);
  }
  return true;
}

function MailListOKButton()
{
  var popup = document.getElementById('abPopup');
  if (popup)
  {
    var uri = popup.getAttribute('value');

    // FIX ME - hack to avoid crashing if no ab selected because of blank option bug from template
    // should be able to just remove this if we are not seeing blank lines in the ab popup
    if (!uri)
      return false;  // don't close window
    // -----

    //Add mailing list to database
    var mailList = Components.classes["@mozilla.org/addressbook/directoryproperty;1"].createInstance();
    mailList = mailList.QueryInterface(Components.interfaces.nsIAbDirectory);

    if (GetListValue(mailList, true))
    {
      var parentDirectory = GetDirectoryFromURI(uri);
      mailList = parentDirectory.addMailList(mailList);
      NotifySaveListeners(mailList);
    }
    else
      return false;
  }

  return true;  // close the window
}

function OnLoadNewMailList()
{
  var selectedAB = null;

  InitCommonJS();

  if (window.arguments && window.arguments[0])
  {
    var abURI = window.arguments[0].selectedAB;
    if (abURI) {
      var directory = GetDirectoryFromURI(abURI);
      if (directory.isMailList) {
        var parentURI = GetParentDirectoryFromMailingListURI(abURI);
        if (parentURI) {
          selectedAB = parentURI;
        }
      }
      else if (directory.readOnly) {
        selectedAB = kPersonalAddressbookURI;
      }
      else {
        selectedAB = abURI;
      }
    }
  }

  if (!selectedAB)
    selectedAB = kPersonalAddressbookURI;

  // set popup with address book names
  var abPopup = document.getElementById('abPopup');
  abPopup.value = selectedAB;

  AppendNewRowAndSetFocus();
  awFitDummyRows(1);

  document.addEventListener("keypress", awDocumentKeyPress, true);

  // focus on first name
  var listName = document.getElementById('ListName');
  if (listName)
    setTimeout( function(firstTextBox) { firstTextBox.focus(); }, 0, listName );

  NotifyLoadListeners(directory);
}

function EditListOKButton()
{
  //edit mailing list in database
  if (GetListValue(gEditList, false))
  {
    if (gListCard) {
      // modify the list card (for the results pane) from the mailing list 
      gListCard.displayName = gEditList.dirName;
      gListCard.lastName = gEditList.dirName;
      gListCard.setProperty("NickName", gEditList.listNickName);
      gListCard.setProperty("Notes", gEditList.description);
    }

    NotifySaveListeners(gEditList);
    gEditList.editMailListToDatabase(gListCard);

    return true;  // close the window
  }

  return false;
}

function OnLoadEditList()
{
  InitCommonJS();

  gListCard = window.arguments[0].abCard;
  var listUri  = window.arguments[0].listURI;

  gEditList = GetDirectoryFromURI(listUri);

  document.getElementById('ListName').value = gEditList.dirName;
  document.getElementById('ListNickName').value = gEditList.listNickName;
  document.getElementById('ListDescription').value = gEditList.description;
  oldListName = gEditList.dirName;

  if (gEditList.addressLists)
  {
    let total = gEditList.addressLists.length;
    if (total)
    {
      let listbox = document.getElementById('addressingWidget');
      let newListBoxNode = listbox.cloneNode(false);
      let templateNode = listbox.querySelector("listitem");

      top.MAX_RECIPIENTS = 0;
      for (let i = 0; i < total; i++)
      {
        let card = gEditList.addressLists.queryElementAt(i, Components.interfaces.nsIAbCard);
        let address = MailServices.headerParser.makeMailboxObject(
          card.displayName, card.primaryEmail).toString();
        SetInputValue(address, newListBoxNode, templateNode);
      }
      listbox.parentNode.replaceChild(newListBoxNode, listbox);
    }
  }

  // Is this directory read-only? If so, we now need to set all the fields to
  // read-only.
  if (gEditList.readOnly) {
    const kMailListFields = [ 'ListName', 'ListNickName', 'ListDescription' ];

    for (let i = 0; i < kMailListFields.length; ++i)
      document.getElementById(kMailListFields[i]).readOnly = true;

    document.documentElement.buttons = "accept";
    document.documentElement.removeAttribute("ondialogaccept");

    // Getting a sane read-only implementation for the addressing widget would
    // basically need a separate dialog. Given I'm not sure about the future of
    // the mailing list dialog in its current state, let's just disable it
    // completely.
    document.getElementById("addressingWidget").disabled = true;
  }

  document.addEventListener("keypress", awDocumentKeyPress, true);

  // workaround for bug 118337 - for mailing lists that have more rows than fits inside
  // the display, the value of the textbox inside the new row isn't inherited into the input -
  // the first row then appears to be duplicated at the end although it is actually empty.
  // see awAppendNewRow which copies first row and clears it
  setTimeout(AppendLastRow, 0);
  NotifyLoadListeners(gEditList);
}

function AppendLastRow()
{ 
  AppendNewRowAndSetFocus();
  awFitDummyRows(1);

  // focus on first name
  var listName = document.getElementById('ListName');
  if (listName)
    listName.focus();
}

function AppendNewRowAndSetFocus()
{
  var lastInput = awGetInputElement(top.MAX_RECIPIENTS);
  if (lastInput && lastInput.value)
    awAppendNewRow(true);
  else
    awSetFocus(top.MAX_RECIPIENTS, lastInput);
}

function SetInputValue(inputValue, parentNode, templateNode)
{
    top.MAX_RECIPIENTS++;

    var newNode = templateNode.cloneNode(true);
    parentNode.appendChild(newNode); // we need to insert the new node before we set the value of the select element!

    var input = newNode.getElementsByTagName(awInputElementName());
    if (input && input.length == 1)
    {
    //We need to set the value using both setAttribute and .value else we will
    // lose the content when the field is not visible. See bug 37435
      input[0].setAttribute("value", inputValue);
      input[0].value = inputValue;
      input[0].setAttribute("id", "addressCol1#" + top.MAX_RECIPIENTS);
  }
}

function awNotAnEmptyArea(event)
{
  //This is temporary until i figure out how to ensure to always having an empty space after the last row

  var lastInput = awGetInputElement(top.MAX_RECIPIENTS);
  if (lastInput && lastInput.value)
    awAppendNewRow(false);

  event.stopPropagation();
}

function awClickEmptySpace(target, setFocus)
{
  if (target == null ||
      (target.localName != "listboxbody" &&
      target.localName != "listcell" &&
      target.localName != "listitem"))
    return;

  var lastInput = awGetInputElement(top.MAX_RECIPIENTS);

  if (lastInput && lastInput.value)
    awAppendNewRow(setFocus);
  else
    if (setFocus)
      awSetFocus(top.MAX_RECIPIENTS, lastInput);
}

function awReturnHit(inputElement)
{
  var row = awGetRowByInputElement(inputElement);
  if (inputElement.value)
  {
    var nextInput = awGetInputElement(row+1);
    if (!nextInput)
      awAppendNewRow(true);
    else
      awSetFocus(row+1, nextInput);
  }
}

function awDeleteRow(rowToDelete)
{
  /* When we delete a row, we must reset the id of others row in order to not break the sequence */
  var maxRecipients = top.MAX_RECIPIENTS;
  awRemoveRow(rowToDelete);

  var numberOfCols = awGetNumberOfCols();
  for (var row = rowToDelete + 1; row <= maxRecipients; row ++)
    for (var col = 1; col <= numberOfCols; col++)
      awGetElementByCol(row, col).setAttribute("id", "addressCol" + (col) + "#" + (row-1));

  awTestRowSequence();
}

function awInputChanged(inputElement)
{
//  AutoCompleteAddress(inputElement);

  //Do we need to add a new row?
  var lastInput = awGetInputElement(top.MAX_RECIPIENTS);
  if (lastInput && lastInput.value && !top.doNotCreateANewRow)
    awAppendNewRow(false);
  top.doNotCreateANewRow = false;
}

function awInputElementName()
{
    if (inputElementType == "")
        inputElementType = document.getElementById("addressCol1#1").localName;
    return inputElementType;
}

function awAppendNewRow(setFocus)
{
  var body = document.getElementById("addressingWidget");
  var listitem1 = awGetListItem(1);

  if (body && listitem1)
  {
    var nextDummy = awGetNextDummyRow();
    var newNode = listitem1.cloneNode(true);
    if (nextDummy)
      body.replaceChild(newNode, nextDummy);
    else
      body.appendChild(newNode);
    
    top.MAX_RECIPIENTS++;

    var input = newNode.getElementsByTagName(awInputElementName());
    if (input && input.length == 1)
    {
      input[0].setAttribute("value", "");
      input[0].setAttribute("id", "addressCol1#" + top.MAX_RECIPIENTS);

      if (input[0].getAttribute('focused') != '')
        input[0].removeAttribute('focused');
    }
    // focus on new input widget
    if (setFocus && input )
      awSetFocus(top.MAX_RECIPIENTS, input[0]);
  }
}


// functions for accessing the elements in the addressing widget

function awGetInputElement(row)
{
    return document.getElementById("addressCol1#" + row);
}


function _awSetFocus()
{
  var listbox = document.getElementById('addressingWidget');
  try
  {
    var theNewRow = awGetListItem(top.awRow);

    listbox.ensureElementIsVisible(theNewRow);
    top.awInputElement.focus();
  }
  catch(ex)
  {
    top.awFocusRetry ++;
    if (top.awFocusRetry < 8)
    {
      dump("_awSetFocus failed, try it again...\n");
      setTimeout(_awSetFocus, 0);
    }
    else
      dump("_awSetFocus failed, forget about it!\n");
  }
}

function awTabFromRecipient(element, event)
{
  //If we are the last element in the listbox, we don't want to create a new row.
  if (element == awGetInputElement(top.MAX_RECIPIENTS))
    top.doNotCreateANewRow = true;
}

function DragOverAddressListTree(event)
{
  var validFlavor = false;
  var dragSession = gDragService.getCurrentSession();

  // XXX add support for other flavors here
  if (dragSession.isDataFlavorSupported("text/x-moz-address")) {
    dragSession.canDrop = true;
  }
}

function DropOnAddressListTree(event)
{
  let dragSession = gDragService.getCurrentSession();
  let trans;

  try {
   trans = Components.classes["@mozilla.org/widget/transferable;1"].createInstance(Components.interfaces.nsITransferable);
   trans.init(getLoadContext());
   trans.addDataFlavor("text/x-moz-address");
  }
  catch (ex) {
    return;
  }

  for (let i = 0; i < dragSession.numDropItems; ++i)
  {
    dragSession.getData(trans, i);
    let dataObj = new Object();
    let bestFlavor = new Object();
    let len = new Object();
    trans.getAnyTransferData(bestFlavor, dataObj, len);
    if (dataObj)
      dataObj = dataObj.value.QueryInterface(Components.interfaces.nsISupportsString);
    if (!dataObj)
      continue;

    // pull the URL out of the data object
    let address = dataObj.data.substring(0, len.value);
    if (!address)
      continue;

    DropListAddress(event.target, address);
  }
}

function DropListAddress(target, address)
{
  // Set focus on a new available, visible row.
  awClickEmptySpace(target, true);
  if (top.MAX_RECIPIENTS == 0)
    top.MAX_RECIPIENTS = 1;

  // Break apart the MIME-ready header address into individual addressees to
  // add to the dialog.
  let addresses = {}, names = {}, fullNames = {};
  MailServices.headerParser.parseHeadersWithArray(address, addresses, names,
    fullNames);
  for (let full of fullNames.value)
  {
    let lastInput = awGetInputElement(top.MAX_RECIPIENTS);
    lastInput.value = full;
    awAppendNewRow(true);
  }
}

/* Allows extensions to register a listener function for
 * when a mailing list is loaded.  The listener function
 * should take two parameters - the first being the
 * mailing list being loaded, the second one being the
 * current window document.
 */
function RegisterLoadListener(aListener)
{
  gLoadListeners.push(aListener);
}

/* Allows extensions to unload a load listener function.
 */
function UnregisterLoadListener(aListener)
{
  var fIndex = gLoadListeners.indexOf(aListener);
  if (fIndex != -1)
    gLoadListeners.splice(fIndex, 1);
}

/* Allows extensions to register a listener function for
 * when a mailing list is saved.  Like a load listener,
 * the save listener should take two parameters: the first
 * being a copy of the mailing list that is being saved,
 * and the second being the current window document.
 */
function RegisterSaveListener(aListener)
{
  gSaveListeners.push(aListener);
}

/* Allows extensions to unload a save listener function.
 */
function UnregisterSaveListener(aListener)
{
  var fIndex = gSaveListeners.indexOf(aListener);
  if (fIndex != -1)
    gSaveListeners.splice(fIndex, 1);
}

/* Notifies all load listeners.
 */
function NotifyLoadListeners(aMailingList)
{
  for (let i = 0; i < gLoadListeners.length; i++)
    gLoadListeners[i](aMailingList, document);
}

/* Notifies all save listeners.
 */
function NotifySaveListeners(aMailingList)
{
  for (let i = 0; i < gSaveListeners.length; i++)
    gSaveListeners[i](aMailingList, document);
}
