'use strict';
module.exports = ContainerNode;

var Node = require('./Node');
var NodeList = require('./NodeList');

// This class defines common functionality for node subtypes that
// can have children

function ContainerNode() {
  Node.call(this);
  this._firstChild = this._childNodes = null;
}

// Primary representation is a circular linked list of siblings
ContainerNode.prototype = Object.create(Node.prototype, {
  hasChildNodes: {
    value: function () {
      if (this._childNodes) {
        return this._childNodes.length > 0;
      }
      return this._firstChild !== null;
    },
  },

  childNodes: {
    get: function () {
      this._ensureChildNodes();
      return this._childNodes;
    },
  },

  firstChild: {
    get: function () {
      if (this._childNodes) {
        return this._childNodes.length === 0 ? null : this._childNodes[0];
      }
      return this._firstChild;
    },
  },

  lastChild: {
    get: function () {
      var kids = this._childNodes,
        first;
      if (kids) {
        return kids.length === 0 ? null : kids[kids.length - 1];
      }
      first = this._firstChild;
      if (first === null) {
        return null;
      }
      return first._previousSibling; // circular linked list
    },
  },

  _ensureChildNodes: {
    value: function () {
      if (this._childNodes) {
        return;
      }
      var first = this._firstChild,
        kid = first,
        childNodes = (this._childNodes = new NodeList());
      if (first)
        do {
          childNodes.push(kid);
          kid = kid._nextSibling;
        } while (kid !== first); // circular linked list
      this._firstChild = null; // free memory
    },
  },

  replaceChildren: {
    value: function replaceChildren() {
      this.removeChildren();
      
      // Should probably implement here the replace logic as well
      // but for now we just need the "children" removal ability
    }
  },  

  // Remove all of this node's children.  This is a minor
  // optimization that only calls modify() once.
  removeChildren: {
    value: function removeChildren() {
      var root = this.rooted ? this.ownerDocument : null,
        next = this.firstChild,
        kid;
      while (next !== null) {
        kid = next;
        next = kid.nextSibling;

        if (root) root.mutateRemove(kid);
        kid.parentNode = null;
      }
      if (this._childNodes) {
        this._childNodes.length = 0;
      } else {
        this._firstChild = null;
      }
      this.modify(); // Update last modified type once only
    },
  },
});
