“use strict”; const hasOwnProp = Object.prototype.hasOwnProperty; const namedPropertiesTracker = require(“../named-properties-tracker”); const NODE_TYPE = require(“./node-type”); const createHTMLCollection = require(“./html-collection”).create; const treeOrderSorter = require(“../utils”).treeOrderSorter; const idlUtils = require(“./generated/utils”);

function isNamedPropertyElement(element) {

// (for the name attribute)

// use hasOwnProperty to make sure contentWindow comes from the prototype,
// and is not set directly on the node by a script.
if ("contentWindow" in element && !hasOwnProp.call(element, "contentWindow")) {
  return true;
}

switch (element.nodeName) {
  case "A":
  case "APPLET":
  case "AREA":
  case "EMBED":
  case "FORM":
  case "FRAMESET":
  case "IMG":
  case "OBJECT":
    return true;
  default:
    return false;
}

}

function namedPropertyResolver(HTMLCollection, window, name, values) {

function getResult() {
  const results = [];

  for (const node of values().keys()) {
    if (node.nodeType !== NODE_TYPE.ELEMENT_NODE) {
      continue;
    }

    if (node.getAttribute("id") === name) {
      results.push(node);
    } else if (node.getAttribute("name") === name && isNamedPropertyElement(node)) {
      results.push(node);
    }
  }

  results.sort(treeOrderSorter);

  return results;
}

const document = window._document;
const objects = createHTMLCollection(idlUtils.implForWrapper(document.documentElement), getResult);

const length = objects.length;
for (let i = 0; i < length; ++i) {
  const node = objects[i];

  if ("contentWindow" in node && !hasOwnProp.call(node, "contentWindow") &&
     node.getAttribute("name") === name) {
    return node.contentWindow;
  }
}

if (length === 0) {
  return undefined;
}

if (length === 1) {
  return objects[0];
}

return objects;

}

exports.initializeWindow = function (window, HTMLCollection) {

namedPropertiesTracker.create(window, namedPropertyResolver.bind(null, HTMLCollection));

};

exports.elementAttributeModified = function (element, name, value, oldValue) {

if (!element._attached) {
  return;
}

const useName = isNamedPropertyElement(element);

if (name === "id" || (name === "name" && useName)) {
  const tracker = namedPropertiesTracker.get(element._ownerDocument._global);

  // (tracker will be null if the document has no Window)
  if (tracker) {
    if (name === "id" && (!useName || element.getAttribute("name") !== oldValue)) {
      tracker.untrack(oldValue, element);
    }

    if (name === "name" && element.getAttribute("id") !== oldValue) {
      tracker.untrack(oldValue, element);
    }

    tracker.track(value, element);
  }
}

};

exports.nodeAttachedToDocument = function (node) {

if (node.nodeType !== NODE_TYPE.ELEMENT_NODE) {
  return;
}

const tracker = namedPropertiesTracker.get(node._ownerDocument._global);
if (!tracker) {
  return;
}

tracker.track(node.getAttribute("id"), node);

if (isNamedPropertyElement(node)) {
  tracker.track(node.getAttribute("name"), node);
}

};

exports.nodeDetachedFromDocument = function (node) {

if (node.nodeType !== NODE_TYPE.ELEMENT_NODE) {
  return;
}

const tracker = namedPropertiesTracker.get(node._ownerDocument._global);
if (!tracker) {
  return;
}

tracker.untrack(node.getAttribute("id"), node);

if (isNamedPropertyElement(node)) {
  tracker.untrack(node.getAttribute("name"), node);
}

};