package ru.dbotthepony.mc.otm.menu.widget

import ru.dbotthepony.mc.otm.capability.AbstractProfiledStorage
import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage
import ru.dbotthepony.mc.otm.capability.matter.IMatterStorage
import ru.dbotthepony.mc.otm.core.collect.SupplierList
import ru.dbotthepony.mc.otm.core.immutableList
import ru.dbotthepony.mc.otm.core.math.Decimal
import ru.dbotthepony.mc.otm.core.util.DecimalValueCodec
import ru.dbotthepony.mc.otm.menu.MatteryMenu
import ru.dbotthepony.mc.otm.menu.MatteryPoweredMenu
import ru.dbotthepony.mc.otm.network.synchronizer.FieldSynchronizer

class ProfiledLevelGaugeWidget<P : AbstractProfiledStorage<*>>(synchronizer: FieldSynchronizer, val gauge: LevelGaugeWidget = LevelGaugeWidget(synchronizer)) {
	var parent: P? = null
		private set

	val historyReceive = immutableList(AbstractProfiledStorage.HISTORY_SIZE) {
		synchronizer.ComputedField({ parent?.historyReceive?.get(it) ?: Decimal.ZERO }, DecimalValueCodec)
	}

	val historyTransfer = immutableList(AbstractProfiledStorage.HISTORY_SIZE) {
		synchronizer.ComputedField({ parent?.historyTransfer?.get(it) ?: Decimal.ZERO }, DecimalValueCodec)
	}

	val directHistoryReceive = SupplierList(historyReceive)
	val directHistoryTransfer = SupplierList(historyTransfer)

	val tick by synchronizer.ComputedIntField({ parent?.tick ?: 0 }).property
	val lastTickReceive by synchronizer.ComputedField({ parent?.lastTickReceive ?: Decimal.ZERO }, DecimalValueCodec)
	val lastTickTransfer by synchronizer.ComputedField({ parent?.lastTickTransfer ?: Decimal.ZERO }, DecimalValueCodec)

	constructor(synchronizer: FieldSynchronizer, storage: P?, gauge: LevelGaugeWidget = LevelGaugeWidget(synchronizer)) : this(synchronizer, gauge = gauge) {
		if (storage != null) {
			with(storage)
		}
	}

	constructor(menu: MatteryMenu, storage: P?, gauge: LevelGaugeWidget = LevelGaugeWidget(menu)) : this(menu.mSynchronizer, storage, gauge = gauge)
	constructor(menu: MatteryMenu, gauge: LevelGaugeWidget = LevelGaugeWidget(menu)) : this(menu.mSynchronizer, gauge = gauge)

	constructor(menu: MatteryPoweredMenu, storage: P?) : this(menu.mSynchronizer, storage, menu.energyWidget)
	constructor(menu: MatteryPoweredMenu) : this(menu.mSynchronizer, menu.energyWidget)

	fun with(storage: P): ProfiledLevelGaugeWidget<P> {
		if (storage is IMatterStorage)
			gauge.with(storage)
		else if (storage is IMatteryEnergyStorage)
			gauge.with(storage)

		parent = storage
		return this
	}

	val weightedTransfer: Decimal get() {
		return AbstractProfiledStorage.calcWeightedAverage(directHistoryTransfer, tick)
	}

	val weightedReceive: Decimal get() {
		return AbstractProfiledStorage.calcWeightedAverage(directHistoryReceive, tick)
	}
}
