package ru.dbotthepony.mc.otm.core.multiblock

import it.unimi.dsi.fastutil.objects.Reference2IntMap
import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.phys.AABB
import ru.dbotthepony.kommons.util.Listenable

interface IMultiblockAccess {
	/**
	 * Whenever this multiblock is valid (all checks passed)
	 */
	val isValid: MultiblockStatus
	val currentDirection: Direction?
	val currentNodes: Map<BlockPos, IMultiblockNode>

	/**
	 * Arbitrary number representing counter which increases when *something* has changed regarding multiblock configuraiton,
	 * probably something not even visible in public interface
	 *
	 * Useful for caching data structures which derive from current state of multiblock
	 */
	val generation: Int

	/**
	 * [listener] will be executed whenever [generation] changes
	 */
	fun onGenerationChanges(listener: Runnable): Listenable.L

	val boundingBox: AABB?

	/**
	 * Returns block counts present on nodes tagged by [tag]
	 */
	fun blocks(tag: Any): Reference2IntMap<Block>

	/**
	 * Returns blockstate counts present on nodes tagged by [tag]
	 */
	fun blockStates(tag: Any): Reference2IntMap<BlockState>

	/**
	 * Returns block counts present on nodes tagged by [GLOBAL_BLOCK_TAG]
	 */
	fun blocks(): Reference2IntMap<Block> {
		return blocks(GLOBAL_BLOCK_TAG)
	}

	/**
	 * Returns blockstate counts present on nodes tagged by [GLOBAL_BLOCK_TAG]
	 */
	fun blockStates(): Reference2IntMap<BlockState> {
		return blockStates(GLOBAL_BLOCK_TAG)
	}

	fun <T : Any> blockEntities(tag: BlockEntityTag<T>): Set<T>

	companion object {
		val GLOBAL_BLOCK_TAG = Any()
	}
}
