if (typeof XML_NS == "undefined") {
  window.XML_NS = "http://www.w3.org/XML/1998/namespace";
}

if (typeof XHTML_NS == "undefined") {
  window.XHTML_NS = "http://www.w3.org/1999/xhtml";
}

function isXMLDocument(aDocument) {
  if ((aDocument instanceof XMLDocument)||(aDocument instanceof XULDocument)) {
    return true;
  }
  if ((aDocument instanceof HTMLDocument)&&(aDocument.contentType != "text/html")) {
    return true;
  }
  return false;
}

const hasLangAttrFilter = {
  acceptNode: function(aNode) {
    if ((this.isXML)&&(aNode.hasAttributeNS(XML_NS, "lang"))) {
      return NodeFilter.FILTER_ACCEPT;
    }
    if ((this.isHTML)&&(aNode.hasAttribute("lang"))) {
      return NodeFilter.FILTER_ACCEPT;
    }
    return NodeFilter.FILTER_SKIP;
  },

  isXML: false,
  isHTML: false
};

function getLanguage(aElement) {
  var rv = "";
  var aNode = aElement;
  var aDoc = aElement.ownerDocument;
  var walker = aDoc.createTreeWalker(aDoc.documentElement, NodeFilter.SHOW_ELEMENT, hasLangAttrFilter, true);
  var metaList;
  var metaNode;
  var i;
  walker.currentNode = aNode;
  hasLangAttrFilter.isXML = isXMLDocument(aDoc);
  hasLangAttrFilter.isHTML = (aDoc instanceof HTMLDocument);
  do {
    if (hasLangAttrFilter.isXML) {
      rv = aNode.getAttributeNS(XML_NS, "lang");
    }
    if (!rv && hasLangAttrFilter.isHTML) {
      if (!hasLangAttrFilter.isXML || (aNode.namespaceURI == XHTML_NS)) {
        // we check aNode.namespaceURI in case we have <foo:bar lang="baz"/>
        rv = aNode.getAttribute("lang");
      }
    }
    if (!rv) {
      aNode = walker.parentNode();
    }
  } while (!rv && aNode);

  if (!rv && hasLangAttrFilter.isHTML) {
    // okay, check the meta nodes
    if (hasLangAttrFilter.isXML) {
      metaList = document.getElementsByTagNameNS(XHTML_NS, "meta");
    } else {
      metaList = document.getElementsByTagName("meta");
    }
    for (i = 0; i < metaList.length; i++) {
      metaNode = metaList[i];
      if (metaNode.httpEquiv == "Content-Language") {
        rv = metaNode.content;
      }
    }
  }
  return rv;
}
