package ru.dbotthepony.kstarbound.collect

class RandomSubList<E>(private val elements: MutableList<E>, private val fromIndex: Int, private var toIndex: Int) : MutableList<E> {
	override val size: Int
		get() = toIndex - fromIndex

	init {
		check(size >= 0) { "Invalid sublist range: $fromIndex .. $toIndex" }
	}

	override fun contains(element: E): Boolean {
		for (i in fromIndex until toIndex) {
			if (elements[i] == element) {
				return true
			}
		}

		return false
	}

	override fun containsAll(elements: Collection<E>): Boolean {
		return elements.all { contains(it) }
	}

	override fun get(index: Int): E {
		if (index !in 0 until size)
			throw IndexOutOfBoundsException(index.toString())

		return elements[index + fromIndex]
	}

	override fun indexOf(element: E): Int {
		for (i in fromIndex until toIndex) {
			if (elements[i] == element) {
				return i - fromIndex
			}
		}

		return -1
	}

	override fun isEmpty(): Boolean {
		return size == 0
	}

	override fun iterator(): MutableIterator<E> {
		return listIterator()
	}

	override fun lastIndexOf(element: E): Int {
		for (i in toIndex - 1 downTo fromIndex) {
			if (elements[i] == element) {
				return i - fromIndex
			}
		}

		return -1
	}

	override fun add(element: E): Boolean {
		elements.add(toIndex++, element)
		return true
	}

	override fun add(index: Int, element: E) {
		if (index !in 0 .. size)
			throw IndexOutOfBoundsException(index.toString())

		elements.add(index + fromIndex, element)
		toIndex++
	}

	override fun addAll(index: Int, elements: Collection<E>): Boolean {
		if (index !in 0 .. size)
			throw IndexOutOfBoundsException(index.toString())

		this.elements.addAll(index + fromIndex, elements)
		toIndex += elements.size
		return true
	}

	override fun addAll(elements: Collection<E>): Boolean {
		return addAll(toIndex, elements)
	}

	override fun clear() {
		for (i in fromIndex until toIndex) {
			elements.removeAt(fromIndex)
		}

		toIndex = fromIndex
	}

	override fun listIterator(): MutableListIterator<E> {
		return RandomListIterator(this)
	}

	override fun listIterator(index: Int): MutableListIterator<E> {
		return RandomListIterator(this, index)
	}

	override fun remove(element: E): Boolean {
		val indexOf = indexOf(element)

		if (indexOf == -1)
			return false

		removeAt(indexOf)
		return true
	}

	override fun removeAll(elements: Collection<E>): Boolean {
		var any = false
		elements.forEach { any = remove(it) || any }
		return any
	}

	override fun removeAt(index: Int): E {
		if (index !in 0 until size)
			throw IndexOutOfBoundsException(index.toString())

		val result = elements.removeAt(index + fromIndex)
		toIndex--
		return result
	}

	override fun retainAll(elements: Collection<E>): Boolean {
		val itr = iterator()
		var modified = false

		for (v in itr) {
			if (v !in elements) {
				itr.remove()
				modified = true
			}
		}

		return modified
	}

	override fun set(index: Int, element: E): E {
		if (index !in 0 until size)
			throw IndexOutOfBoundsException(index.toString())

		return elements.set(index + fromIndex, element)
	}

	override fun subList(fromIndex: Int, toIndex: Int): MutableList<E> {
		return RandomSubList(this, fromIndex, toIndex)
	}

	override fun equals(other: Any?): Boolean {
		if (other === this) return true
		if (other !is List<*>) return false

		val e1: ListIterator<E> = listIterator()
		val e2 = other.listIterator()

		while (e1.hasNext() && e2.hasNext()) {
			val o1 = e1.next()
			val o2 = e2.next()
			if (!(if (o1 == null) o2 == null else o1 == o2)) return false
		}

		return !(e1.hasNext() || e2.hasNext())
	}

	override fun hashCode(): Int {
		var hashCode = 1
		for (e in this) hashCode = 31 * hashCode + e.hashCode()
		return hashCode
	}

	override fun toString(): String {
		return "[${joinToString()}]"
	}
}
