'use strict';

Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });

const constants = require('./constants.cjs');
const EventTarget = require('./EventTarget.cjs');
const shared = require('./shared.cjs');

class Node extends EventTarget.EventTarget {
  nodeType = (() => constants.NodeType.NODE)();
  [constants.NAME] = '';
  [constants.PARENT] = null;
  [constants.CHILD] = null;
  [constants.PREV] = null;
  [constants.NEXT] = null;
  [constants.IS_CONNECTED] = false;
  get [constants.HOOKS]() {
    return this[constants.OWNER_DOCUMENT].defaultView[constants.HOOKS];
  }
  get localName() {
    return this[constants.NAME];
  }
  get nodeName() {
    return this[constants.NAME].toUpperCase();
  }
  get ownerDocument() {
    return this[constants.OWNER_DOCUMENT];
  }
  get isConnected() {
    return this[constants.IS_CONNECTED];
  }
  isDefaultNamespace(namespace) {
    return namespace === constants.NamespaceURI.XHTML;
  }
  get parentNode() {
    return this[constants.PARENT];
  }
  set parentNode(_readonly) {}
  get parentElement() {
    const parent = this[constants.PARENT];
    if (!parent || parent.nodeType !== 1) return null;
    return parent;
  }
  set parentElement(_readonly) {}
  get previousSibling() {
    return this[constants.PREV];
  }
  set previousSibling(_readonly) {}
  get nextSibling() {
    return this[constants.NEXT];
  }
  set nextSibling(_readonly) {}
  get previousElementSibling() {
    let sib = this[constants.PREV];
    while (sib && sib.nodeType !== 1) sib = sib[constants.PREV];
    return sib;
  }
  set previousElementSibling(_readonly) {}
  get nextElementSibling() {
    let sib = this[constants.NEXT];
    while (sib && sib.nodeType !== 1) sib = sib[constants.NEXT];
    return sib;
  }
  set nextElementSibling(_readonly) {}
  get firstChild() {
    return this[constants.CHILD];
  }
  set firstChild(_readonly) {}
  get lastChild() {
    let child = this[constants.CHILD];
    while (child) {
      const next = child[constants.NEXT];
      if (next == null) break;
      child = next;
    }
    return child;
  }
  set lastChild(_readonly) {}
  get nodeValue() {
    if (shared.isCharacterData(this)) return this.data;
    return null;
  }
  set nodeValue(data) {
    if (shared.isCharacterData(this)) this.data = data;
  }
  get textContent() {
    if (shared.isCharacterData(this)) return this.data;
    let text = '';
    for (const node of shared.descendants(this)) {
      if (shared.isTextNode(node)) {
        text += node.data;
      }
    }
    return text;
  }
  set textContent(data) {
    if (shared.isCharacterData(this)) {
      this.data = data;
    } else if (shared.isParentNode(this)) {
      let child;
      while (child = this[constants.CHILD]) {
        this.removeChild(child);
      }
      this.append(data);
    }
  }
  cloneNode(deep) {
    return shared.cloneNode(this, deep);
  }
  contains(node) {
    let currentNode = node;
    while (true) {
      if (currentNode == null) return false;
      if (currentNode === this) return true;
      currentNode = node.parentNode;
    }
  }
}

exports.Node = Node;
