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

/* import-globals-from ../../composer/content/editorUtilities.js */
/* import-globals-from EdAdvancedEdit.js */
/* import-globals-from EdDialogCommon.js */

function BuildHTMLAttributeNameList() {
  gDialog.AddHTMLAttributeNameInput.removeAllItems();

  var elementName = gElement.localName;
  var attNames = gHTMLAttr[elementName];

  if (attNames && attNames.length) {
    var menuitem;

    for (var i = 0; i < attNames.length; i++) {
      var name = attNames[i];

      if (name == "_core") {
        // Signal to append the common 'core' attributes.
        for (var j = 0; j < gCoreHTMLAttr.length; j++) {
          name = gCoreHTMLAttr[j];

          // only filtering rule used for core attributes as of 8-20-01
          // Add more rules if necessary.
          if (name.includes("^")) {
            name = name.replace(/\^/g, "");
            menuitem = gDialog.AddHTMLAttributeNameInput.appendItem(name, name);
            menuitem.setAttribute("limitFirstChar", "true");
          } else {
            gDialog.AddHTMLAttributeNameInput.appendItem(name, name);
          }
        }
      } else if (name == "-") {
        // Signal for separator
        var popup = gDialog.AddHTMLAttributeNameInput.menupopup;
        if (popup) {
          var sep = document.createXULElement("menuseparator");
          if (sep) {
            popup.appendChild(sep);
          }
        }
      } else {
        // Get information about value filtering
        let forceOneChar = name.includes("!");
        let forceInteger = name.includes("#");
        let forceSignedInteger = name.includes("+");
        let forceIntOrPercent = name.includes("%");
        let limitFirstChar = name.includes("^");
        // let required = name.includes("$");

        // Strip flag characters
        name = name.replace(/[!^#%$+]/g, "");

        menuitem = gDialog.AddHTMLAttributeNameInput.appendItem(name, name);
        if (menuitem) {
          // Signify "required" attributes by special style
          // TODO: Don't do this until next version, when we add
          //      explanatory text and an 'Autofill Required Attributes' button
          // if (required)
          //  menuitem.setAttribute("class", "menuitem-highlight-1");

          // Set flags to filter value input
          if (forceOneChar) {
            menuitem.setAttribute("forceOneChar", "true");
          }
          if (limitFirstChar) {
            menuitem.setAttribute("limitFirstChar", "true");
          }
          if (forceInteger) {
            menuitem.setAttribute("forceInteger", "true");
          }
          if (forceSignedInteger) {
            menuitem.setAttribute("forceSignedInteger", "true");
          }
          if (forceIntOrPercent) {
            menuitem.setAttribute("forceIntOrPercent", "true");
          }
        }
      }
    }
  }
}

// build attribute list in tree form from element attributes
function BuildHTMLAttributeTable() {
  var nodeMap = gElement.attributes;
  var i;
  if (nodeMap.length > 0) {
    var added = false;
    for (i = 0; i < nodeMap.length; i++) {
      let name = nodeMap[i].name.trim().toLowerCase();
      if (
        CheckAttributeNameSimilarity(nodeMap[i].nodeName, HTMLAttrs) ||
        name.startsWith("on") ||
        name == "style"
      ) {
        continue; // repeated or non-HTML attribute, ignore this one and go to next
      }
      if (
        !name.startsWith("_moz") &&
        AddTreeItem(name, nodeMap[i].value, "HTMLAList", HTMLAttrs)
      ) {
        added = true;
      }
    }

    if (added) {
      SelectHTMLTree(0);
    }
  }
}

function ClearHTMLInputWidgets() {
  gDialog.AddHTMLAttributeTree.view.selection.clearSelection();
  gDialog.AddHTMLAttributeNameInput.value = "";
  gDialog.AddHTMLAttributeValueInput.value = "";
  SetTextboxFocus(gDialog.AddHTMLAttributeNameInput);
}

function onSelectHTMLTreeItem() {
  if (!gDoOnSelectTree) {
    return;
  }

  var tree = gDialog.AddHTMLAttributeTree;
  if (tree && tree.view.selection.count) {
    var inputName = TrimString(
      gDialog.AddHTMLAttributeNameInput.value
    ).toLowerCase();
    var selectedItem = getSelectedItem(tree);
    var selectedName = selectedItem.firstChild.firstChild.getAttribute("label");

    if (inputName == selectedName) {
      // Already editing selected name - just update the value input
      gDialog.AddHTMLAttributeValueInput.value = GetTreeItemValueStr(
        selectedItem
      );
    } else {
      gDialog.AddHTMLAttributeNameInput.value = selectedName;

      // Change value input based on new selected name
      onInputHTMLAttributeName();
    }
  }
}

function onInputHTMLAttributeName() {
  let attName = gDialog.AddHTMLAttributeNameInput.value.toLowerCase().trim();

  // Clear value widget, but prevent triggering update in tree
  gUpdateTreeValue = false;
  gDialog.AddHTMLAttributeValueInput.value = "";
  gUpdateTreeValue = true;

  if (attName) {
    // Get value list for current attribute name
    var valueListName;

    // Most elements have the "dir" attribute,
    //   so we have just one array for the allowed values instead
    //   requiring duplicate entries for each element in EdAEAttributes.js
    if (attName == "dir") {
      valueListName = "all_dir";
    } else {
      valueListName = gElement.localName + "_" + attName;
    }

    // Strip off leading "_" we sometimes use (when element name is reserved word)
    if (valueListName.startsWith("_")) {
      valueListName = valueListName.slice(1);
    }

    var newValue = "";
    var listLen = 0;

    // Index to which widget we were using to edit the value
    var deckIndex = gDialog.AddHTMLAttributeValueDeck.getAttribute(
      "selectedIndex"
    );

    if (valueListName in gHTMLAttr) {
      var valueList = gHTMLAttr[valueListName];

      listLen = valueList.length;
      if (listLen == 1) {
        newValue = valueList[0];
      }

      // Note: For case where "value list" is actually just
      // one (default) item, don't use menulist for that
      if (listLen > 1) {
        gDialog.AddHTMLAttributeValueMenulist.removeAllItems();

        if (deckIndex != "1") {
          // Switch to using editable menulist
          gDialog.AddHTMLAttributeValueInput =
            gDialog.AddHTMLAttributeValueMenulist;
          gDialog.AddHTMLAttributeValueDeck.setAttribute("selectedIndex", "1");
        }
        // Rebuild the list
        for (var i = 0; i < listLen; i++) {
          if (valueList[i] == "-") {
            // Signal for separator
            var popup = gDialog.AddHTMLAttributeValueInput.menupopup;
            if (popup) {
              var sep = document.createXULElement("menuseparator");
              if (sep) {
                popup.appendChild(sep);
              }
            }
          } else {
            gDialog.AddHTMLAttributeValueMenulist.appendItem(
              valueList[i],
              valueList[i]
            );
          }
        }
      }
    }

    if (listLen <= 1 && deckIndex != "0") {
      // No list: Use textbox for input instead
      gDialog.AddHTMLAttributeValueInput = gDialog.AddHTMLAttributeValueTextbox;
      gDialog.AddHTMLAttributeValueDeck.setAttribute("selectedIndex", "0");
    }

    // If attribute already exists in tree, use associated value,
    //  else use default found above
    var existingValue = GetAndSelectExistingAttributeValue(
      attName,
      "HTMLAList"
    );
    if (existingValue) {
      newValue = existingValue;
    }

    gDialog.AddHTMLAttributeValueInput.value = newValue;

    if (!existingValue) {
      onInputHTMLAttributeValue();
    }
  }
}

function onInputHTMLAttributeValue() {
  if (!gUpdateTreeValue) {
    return;
  }

  var name = TrimString(gDialog.AddHTMLAttributeNameInput.value);
  if (!name) {
    return;
  }

  // Trim spaces only from left since we must allow spaces within the string
  //  (we always reset the input field's value below)
  var value = TrimStringLeft(gDialog.AddHTMLAttributeValueInput.value);
  if (value) {
    // Do value filtering based on type of attribute
    // (Do not use "forceInteger()" to avoid multiple
    //  resetting of input's value and flickering)
    var selectedItem = gDialog.AddHTMLAttributeNameInput.selectedItem;

    if (selectedItem) {
      if (
        selectedItem.getAttribute("forceOneChar") == "true" &&
        value.length > 1
      ) {
        value = value.slice(0, 1);
      }

      if (selectedItem.getAttribute("forceIntOrPercent") == "true") {
        // Allow integer with optional "%" as last character
        var percent = TrimStringRight(value).slice(-1);
        value = value.replace(/\D+/g, "");
        if (percent == "%") {
          value += percent;
        }
      } else if (selectedItem.getAttribute("forceInteger") == "true") {
        value = value.replace(/\D+/g, "");
      } else if (selectedItem.getAttribute("forceSignedInteger") == "true") {
        // Allow integer with optional "+" or "-" as first character
        var sign = value[0];
        value = value.replace(/\D+/g, "");
        if (sign == "+" || sign == "-") {
          value = sign + value;
        }
      }

      // Special case attributes
      if (selectedItem.getAttribute("limitFirstChar") == "true") {
        // Limit first character to letter, and all others to
        //  letters, numbers, and a few others
        value = value
          .replace(/^[^a-zA-Z\u0080-\uFFFF]/, "")
          .replace(/[^a-zA-Z0-9_\.\-\:\u0080-\uFFFF]+/g, "");
      }

      // Update once only if it changed
      if (value != gDialog.AddHTMLAttributeValueInput.value) {
        gDialog.AddHTMLAttributeValueInput.value = value;
      }
    }
  }

  // Update value in the tree list
  // If not found, add new attribute
  if (!UpdateExistingAttribute(name, value, "HTMLAList") && value) {
    AddTreeItem(name, value, "HTMLAList", HTMLAttrs);
  }
}

function editHTMLAttributeValue(targetCell) {
  if (IsNotTreeHeader(targetCell)) {
    gDialog.AddHTMLAttributeValueInput.select();
  }
}

// update the object with added and removed attributes
function UpdateHTMLAttributes() {
  var HTMLAList = document.getElementById("HTMLAList");
  var i;

  // remove removed attributes
  for (i = 0; i < HTMLRAttrs.length; i++) {
    var name = HTMLRAttrs[i];

    if (gElement.hasAttribute(name)) {
      doRemoveAttribute(name);
    }
  }

  // Set added or changed attributes
  for (i = 0; i < HTMLAList.childNodes.length; i++) {
    var item = HTMLAList.childNodes[i];
    doSetAttribute(GetTreeItemAttributeStr(item), GetTreeItemValueStr(item));
  }
}

function RemoveHTMLAttribute() {
  // We only allow 1 selected item
  if (gDialog.AddHTMLAttributeTree.view.selection.count) {
    var item = getSelectedItem(gDialog.AddHTMLAttributeTree);
    var attr = GetTreeItemAttributeStr(item);

    // remove the item from the attribute array
    HTMLRAttrs[HTMLRAttrs.length] = attr;
    RemoveNameFromAttArray(attr, HTMLAttrs);

    // Remove the item from the tree
    item.remove();

    // Clear inputs and selected item in tree
    ClearHTMLInputWidgets();
  }
}

function SelectHTMLTree(index) {
  gDoOnSelectTree = false;
  try {
    gDialog.AddHTMLAttributeTree.selectedIndex = index;
  } catch (e) {}
  gDoOnSelectTree = true;
}
