/* jshint bitwise: false */
'use strict';
module.exports = CharacterData;

var Leaf = require('./Leaf');
var utils = require('./utils');
var ChildNode = require('./ChildNode');
var NonDocumentTypeChildNode = require('./NonDocumentTypeChildNode');

function CharacterData() {
  Leaf.call(this);
}

CharacterData.prototype = Object.create(Leaf.prototype, {
  // DOMString substringData(unsigned long offset,
  //               unsigned long count);
  // The substringData(offset, count) method must run these steps:
  //
  //     If offset is greater than the context object's
  //     length, throw an INDEX_SIZE_ERR exception and
  //     terminate these steps.
  //
  //     If offset+count is greater than the context
  //     object's length, return a DOMString whose value is
  //     the UTF-16 code units from the offsetth UTF-16 code
  //     unit to the end of data.
  //
  //     Return a DOMString whose value is the UTF-16 code
  //     units from the offsetth UTF-16 code unit to the
  //     offset+countth UTF-16 code unit in data.
  substringData: {
    value: function substringData(offset, count) {
      if (arguments.length < 2) {
        throw new TypeError('Not enough arguments');
      }
      // Convert arguments to WebIDL "unsigned long"
      offset = offset >>> 0;
      count = count >>> 0;
      if (offset > this.data.length || offset < 0 || count < 0) {
        utils.IndexSizeError();
      }
      return this.data.substring(offset, offset + count);
    },
  },

  // void appendData(DOMString data);
  // The appendData(data) method must append data to the context
  // object's data.
  appendData: {
    value: function appendData(data) {
      if (arguments.length < 1) {
        throw new TypeError('Not enough arguments');
      }
      this.data += String(data);
    },
  },

  // void insertData(unsigned long offset, DOMString data);
  // The insertData(offset, data) method must run these steps:
  //
  //     If offset is greater than the context object's
  //     length, throw an INDEX_SIZE_ERR exception and
  //     terminate these steps.
  //
  //     Insert data into the context object's data after
  //     offset UTF-16 code units.
  //
  insertData: {
    value: function insertData(offset, data) {
      return this.replaceData(offset, 0, data);
    },
  },

  // void deleteData(unsigned long offset, unsigned long count);
  // The deleteData(offset, count) method must run these steps:
  //
  //     If offset is greater than the context object's
  //     length, throw an INDEX_SIZE_ERR exception and
  //     terminate these steps.
  //
  //     If offset+count is greater than the context
  //     object's length var count be length-offset.
  //
  //     Starting from offset UTF-16 code units remove count
  //     UTF-16 code units from the context object's data.
  deleteData: {
    value: function deleteData(offset, count) {
      return this.replaceData(offset, count, '');
    },
  },

  // void replaceData(unsigned long offset, unsigned long count,
  //          DOMString data);
  //
  // The replaceData(offset, count, data) method must act as
  // if the deleteData() method is invoked with offset and
  // count as arguments followed by the insertData() method
  // with offset and data as arguments and re-throw any
  // exceptions these methods might have thrown.
  replaceData: {
    value: function replaceData(offset, count, data) {
      var curtext = this.data,
        len = curtext.length;
      // Convert arguments to correct WebIDL type
      offset = offset >>> 0;
      count = count >>> 0;
      data = String(data);

      if (offset > len || offset < 0) utils.IndexSizeError();

      if (offset + count > len) count = len - offset;

      var prefix = curtext.substring(0, offset),
        suffix = curtext.substring(offset + count);

      this.data = prefix + data + suffix;
    },
  },

  // Utility method that Node.isEqualNode() calls to test Text and
  // Comment nodes for equality.  It is okay to put it here, since
  // Node will have already verified that nodeType is equal
  isEqual: {
    value: function isEqual(n) {
      return this._data === n._data;
    },
  },

  length: {
    get: function () {
      return this.data.length;
    },
  },
});

Object.defineProperties(CharacterData.prototype, ChildNode);
Object.defineProperties(CharacterData.prototype, NonDocumentTypeChildNode);
