package ru.dbotthepony.mc.otm.capability

import com.google.common.collect.ImmutableList
import net.minecraft.world.item.ItemStack
import net.minecraftforge.items.IItemHandler
import ru.dbotthepony.mc.otm.container.ContainerHandler
import java.util.stream.Stream

class CombinedItemHandler(val handlers: ImmutableList<IItemHandler>) : IItemHandler {
	constructor(handlers: Stream<IItemHandler>) : this(handlers.collect(ImmutableList.toImmutableList()))
	constructor(handlers: Collection<IItemHandler>) : this(ImmutableList.copyOf(handlers))
	constructor(vararg handlers: IItemHandler) : this(ImmutableList.copyOf(handlers))

	private val needsChecking = handlers.any { it !is ContainerHandler }
	private val lastSizes = IntArray(this.handlers.size)
	private var totalSize = 0
	private val mappings = ArrayList<Mapping>()
	private data class Mapping(val handler: IItemHandler, val slot: Int)

	init {
		check(true)
	}

	private fun check(force: Boolean = false) {
		if (!needsChecking && !force)
			return

		for ((i, handler) in handlers.withIndex()) {
			var oldSize = lastSizes[i]

			if (oldSize != handler.slots) {
				totalSize += handler.slots - lastSizes[i]
				var edge = 0

				for (i2 in 0 .. i) {
					edge += lastSizes[i2]
				}

				edge--

				while (oldSize > handler.slots) {
					mappings.removeAt(edge--)
					oldSize--
				}

				while (oldSize < handler.slots) {
					mappings.add(++edge, Mapping(handler, oldSize++))
				}

				lastSizes[i] = handler.slots
			}
		}
	}

	override fun getSlots(): Int {
		check()
		return totalSize
	}

	override fun getStackInSlot(slot: Int): ItemStack {
		check()
		val mapping = mappings.getOrNull(slot) ?: return ItemStack.EMPTY
		return mapping.handler.getStackInSlot(mapping.slot)
	}

	override fun insertItem(slot: Int, stack: ItemStack, simulate: Boolean): ItemStack {
		check()
		val mapping = mappings.getOrNull(slot) ?: return stack
		return mapping.handler.insertItem(mapping.slot, stack, simulate)
	}

	override fun extractItem(slot: Int, amount: Int, simulate: Boolean): ItemStack {
		check()
		val mapping = mappings.getOrNull(slot) ?: return ItemStack.EMPTY
		return mapping.handler.extractItem(mapping.slot, amount, simulate)
	}

	override fun getSlotLimit(slot: Int): Int {
		check()
		val mapping = mappings.getOrNull(slot) ?: return 0
		return mapping.handler.getSlotLimit(mapping.slot)
	}

	override fun isItemValid(slot: Int, stack: ItemStack): Boolean {
		check()
		val mapping = mappings.getOrNull(slot) ?: return false
		return mapping.handler.isItemValid(mapping.slot, stack)
	}
}
