Source: java/util/ArrayList.js

import Collection from './Collection'
import IndexOutOfBoundsException from '../lang/IndexOutOfBoundsException'
import List from './List'
import NoSuchElementException from './NoSuchElementException'

/**
 * @see http://download.oracle.com/javase/6/docs/api/java/util/ArrayList.html
 *
 * @extends List
 * @private
 */
export default function ArrayList () {
  /**
   * @type {Array}
   * @private
  */
  this.array_ = []

  if (arguments[0] instanceof Collection) {
    this.addAll(arguments[0])
  }
};
ArrayList.prototype = Object.create(List.prototype)
ArrayList.prototype.constructor = ArrayList

ArrayList.prototype.ensureCapacity = function () {}
ArrayList.prototype.interfaces_ = [List, Collection]

/**
 * @override
 */
ArrayList.prototype.add = function (e) {
  if (arguments.length === 1) {
    this.array_.push(e)
  } else {
    this.array_.splice(arguments[0], 0, arguments[1])
  }
  return true
}

ArrayList.prototype.clear = function () {
  this.array_ = []
}

/**
 * @override
 */
ArrayList.prototype.addAll = function (c) {
  for (let i = c.iterator(); i.hasNext();) {
    this.add(i.next())
  }
  return true
}

/**
 * @override
 */
ArrayList.prototype.set = function (index, element) {
  const oldElement = this.array_[index]
  this.array_[index] = element
  return oldElement
}

/**
 * @override
 */
ArrayList.prototype.iterator = function () {
  return new Iterator_(this)
}

/**
 * @override
 */
ArrayList.prototype.get = function (index) {
  if (index < 0 || index >= this.size()) {
    throw new IndexOutOfBoundsException()
  }

  return this.array_[index]
}

/**
 * @override
 */
ArrayList.prototype.isEmpty = function () {
  return this.array_.length === 0
}

/**
 * @override
 */
ArrayList.prototype.size = function () {
  return this.array_.length
}

/**
 * @override
 */
ArrayList.prototype.toArray = function () {
  const array = []

  for (let i = 0, len = this.array_.length; i < len; i++) {
    array.push(this.array_[i])
  }

  return array
}

/**
 * @override
 */
ArrayList.prototype.remove = function (o) {
  let found = false

  for (let i = 0, len = this.array_.length; i < len; i++) {
    if (this.array_[i] === o) {
      this.array_.splice(i, 1)
      found = true
      break
    }
  }

  return found
}

ArrayList.prototype.removeAll = function (c) {
  for (let i = c.iterator(); i.hasNext();) {
    this.remove(i.next())
  }
  return true
}

/**
 * @extends {Iterator}
 * @param {ArrayList} arrayList
 * @constructor
 * @private
 */
const Iterator_ = function (arrayList) {
  /**
   * @type {ArrayList}
   * @private
  */
  this.arrayList_ = arrayList
  /**
   * @type {number}
   * @private
  */
  this.position_ = 0
}

/**
 * @override
 */
Iterator_.prototype.next = function () {
  if (this.position_ === this.arrayList_.size()) {
    throw new NoSuchElementException()
  }
  return this.arrayList_.get(this.position_++)
}

/**
 * @override
 */
Iterator_.prototype.hasNext = function () {
  if (this.position_ < this.arrayList_.size()) {
    return true
  } else {
    return false
  }
}

/**
 * TODO: should be in ListIterator
 * @override
 */
Iterator_.prototype.set = function (element) {
  return this.arrayList_.set(this.position_ - 1, element)
}

/**
 * @override
 */
Iterator_.prototype.remove = function () {
  this.arrayList_.remove(this.arrayList_.get(this.position_))
}