package ru.dbotthepony.mc.otm.menu.input

import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
import ru.dbotthepony.mc.otm.capability.FlowDirection
import ru.dbotthepony.mc.otm.core.immutableMap
import ru.dbotthepony.mc.otm.core.math.RelativeSide
import ru.dbotthepony.mc.otm.menu.MatteryMenu

/**
 * [allowPull] and [allowPush] controls whenever player is allowed to change these options
 */
class FluidConfigPlayerInput(val menu: MatteryMenu, config: MatteryDeviceBlockEntity.ConfigurableFluidHandler<*>? = null, val allowPull: Boolean = false, val allowPush: Boolean = false) {
	var possibleModes by menu.mSynchronizer.enum(FlowDirection::class.java)
		private set

	inner class Piece(val side: RelativeSide) {
		val pull = BooleanInputWithFeedback(menu)
		val push = BooleanInputWithFeedback(menu)
		val input = EnumInputWithFeedback<FlowDirection>(menu)

		var default by menu.mSynchronizer.enum(FlowDirection.NONE)

		init {
			pull.filter { allowPull && possibleModes.isSupertype(FlowDirection.INPUT) }
			push.filter { allowPush && possibleModes.isSupertype(FlowDirection.OUTPUT) }
		}

		fun with(config: MatteryDeviceBlockEntity.ConfigurableFluidHandler<*>.Piece, parent: MatteryDeviceBlockEntity.ConfigurableFluidHandler<*>) {
			pull.with(config::automatePull)
			push.with(config::automatePush)
			input.withSupplier { config.flow }.withConsumer { if (parent.possibleModes.isSupertype(it)) config.flow = it }
		}
	}

	val pieces = immutableMap { for (side in RelativeSide.values()) put(side, Piece(side)) }

	fun with(config: MatteryDeviceBlockEntity.ConfigurableFluidHandler<*>) {
		possibleModes = config.possibleModes

		for ((side, v) in config.pieces) {
			pieces[side]!!.with(v, config)
			pieces[side]!!.default = config.defaults[side]!!
		}
	}

	init {
		if (config != null) {
			with(config)
		}
	}
}
