package ru.dbotthepony.mc.otm.container

import it.unimi.dsi.fastutil.objects.ObjectSpliterator
import it.unimi.dsi.fastutil.objects.ObjectSpliterators
import net.minecraft.world.item.ItemStack
import net.minecraftforge.items.IItemHandler
import ru.dbotthepony.mc.otm.core.collect.AwareItemStack
import ru.dbotthepony.mc.otm.core.collect.ItemHandlerItemStackEntry
import java.util.*
import java.util.stream.Stream
import java.util.stream.StreamSupport

class ItemHandlerSpliterator(private val handler: IItemHandler, offset: Int = 0, private val maxPos: Int = handler.slots) : ObjectSpliterators.AbstractIndexBasedSpliterator<ItemStack>(offset) {
	init {
		require(offset >= 0) { "Invalid offset $offset" }
		require(offset + maxPos <= handler.slots) { "$offset -> $maxPos while having only size of ${handler.slots}!" }
	}

	override fun get(location: Int): ItemStack {
		return handler.getStackInSlot(location)
	}

	override fun getMaxPos(): Int {
		return maxPos
	}

	override fun makeForSplit(pos: Int, maxPos: Int): ObjectSpliterator<ItemStack> {
		return ItemHandlerSpliterator(handler, pos, maxPos)
	}
}

class ItemHandlerAwareSpliterator(private val handler: IItemHandler, offset: Int = 0, private val maxPos: Int = handler.slots) : ObjectSpliterators.AbstractIndexBasedSpliterator<AwareItemStack>(offset) {
	init {
		require(offset >= 0) { "Invalid offset $offset" }
		require(offset + maxPos <= handler.slots) { "$offset -> $maxPos while having only size of ${handler.slots}!" }
	}

	override fun get(location: Int): AwareItemStack {
		return ItemHandlerItemStackEntry(location, handler)
	}

	override fun getMaxPos(): Int {
		return maxPos
	}

	override fun makeForSplit(pos: Int, maxPos: Int): ObjectSpliterator<AwareItemStack> {
		return ItemHandlerAwareSpliterator(handler, pos, maxPos)
	}
}

fun IItemHandler.iterator(): Iterator<ItemStack> = Spliterators.iterator(spliterator())
fun IItemHandler.spliterator(): Spliterator<out ItemStack> = ItemHandlerSpliterator(this)
fun IItemHandler.awareSpliterator(): Spliterator<out AwareItemStack> = ItemHandlerAwareSpliterator(this)
fun IItemHandler.stream(): Stream<out ItemStack> = StreamSupport.stream(spliterator(), false)
fun IItemHandler.awareStream(): Stream<out AwareItemStack> = StreamSupport.stream(awareSpliterator(), false)
