“use strict”;

const HTMLElementImpl = require(“./HTMLElement-impl”).implementation;

const DOMException = require(“../../web-idl/DOMException”); const closest = require(“../helpers/traversal”).closest; const normalizeToCRLF = require(“../helpers/form-controls”).normalizeToCRLF;

class HTMLTextAreaElement extends HTMLElementImpl {

constructor(args, privateData) {
  super(args, privateData);

  this._rawValue = "";
  this._dirtyValue = false;
}

_formReset() {
  this._rawValue = this.textContent;
  this._dirtyValue = false;
}

_getAPIValue() {
  return this._rawValue.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
}

_getValue() {
  // Hard-wrapping omitted, for now.
  return normalizeToCRLF(this._rawValue);
}

_modified() {
  super._modified();

  if (this._dirtyValue === false) {
    this._rawValue = this.textContent;
  }
}

get form() {
  return closest(this, "form");
}

get defaultValue() {
  return this.textContent;
}

set defaultValue(val) {
  this.textContent = val;
}

get value() {
  return this._getAPIValue();
}

set value(val) {
  this._rawValue = val;
  this._dirtyValue = true;

  this._selectionStart = 0;
  this._selectionEnd = 0;
  this._selectionDirection = "none";
}

get textLength() {
  return this.value.length; // code unit length (16 bit)
}
get type() {
  return "textarea";
}

_dispatchSelectEvent() {
  const event = this._ownerDocument.createEvent("HTMLEvents");
  event.initEvent("select", true, true);
  this.dispatchEvent(event);
}
_getValueLength() {
  return typeof this.value === "string" ? this.value.length : 0;
}
select() {
  this._selectionStart = 0;
  this._selectionEnd = this._getValueLength();
  this._selectionDirection = "none";
  this._dispatchSelectEvent();
}
get selectionStart() {
  return this._selectionStart;
}
set selectionStart(start) {
  this.setSelectionRange(start, Math.max(start, this._selectionEnd), this._selectionDirection);
}
get selectionEnd() {
  return this._selectionEnd;
}
set selectionEnd(end) {
  this.setSelectionRange(this._selectionStart, end, this._selectionDirection);
}
get selectionDirection() {
  return this._selectionDirection;
}
set selectionDirection(dir) {
  this.setSelectionRange(this._selectionStart, this._selectionEnd, dir);
}
setSelectionRange(start, end, dir) {
  this._selectionEnd = Math.min(end, this._getValueLength());
  this._selectionStart = Math.min(start, this._selectionEnd);
  this._selectionDirection = dir === "forward" || dir === "backward" ? dir : "none";
  this._dispatchSelectEvent();
}
setRangeText(repl, start, end, selectionMode) {
  if (arguments.length < 2) {
    start = this._selectionStart;
    end = this._selectionEnd;
  } else if (start > end) {
    throw new DOMException(DOMException.INDEX_SIZE_ERR);
  }

  start = Math.min(start, this._getValueLength());
  end = Math.min(end, this._getValueLength());

  const val = this.value;
  let selStart = this._selectionStart;
  let selEnd = this._selectionEnd;

  this.value = val.slice(0, start) + repl + val.slice(end);

  const newEnd = start + this.value.length;

  if (selectionMode === "select") {
    this.setSelectionRange(start, newEnd);
  } else if (selectionMode === "start") {
    this.setSelectionRange(start, start);
  } else if (selectionMode === "end") {
    this.setSelectionRange(newEnd, newEnd);
  } else { // preserve
    const delta = repl.length - (end - start);

    if (selStart > end) {
      selStart += delta;
    } else if (selStart > start) {
      selStart = start;
    }

    if (selEnd > end) {
      selEnd += delta;
    } else if (selEnd > start) {
      selEnd = newEnd;
    }

    this.setSelectionRange(selStart, selEnd);
  }
}

get cols() {
  if (!this.hasAttribute("cols")) {
    return 20;
  }
  return parseInt(this.getAttribute("cols"));
}

set cols(value) {
  if (value <= 0) {
    throw new DOMException(DOMException.INDEX_SIZE_ERR);
  }
  this.setAttribute("cols", String(value));
}

get rows() {
  if (!this.hasAttribute("rows")) {
    return 2;
  }
  return parseInt(this.getAttribute("rows"));
}

set rows(value) {
  if (value <= 0) {
    throw new DOMException(DOMException.INDEX_SIZE_ERR);
  }
  this.setAttribute("rows", String(value));
}

}

module.exports = {

implementation: HTMLTextAreaElement

};