package ru.dbotthepony.mc.otm.client.screen.panels.util

import net.minecraft.client.gui.screens.Screen
import ru.dbotthepony.mc.otm.client.render.RenderGravity
import ru.dbotthepony.mc.otm.client.screen.panels.Dock
import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel
import ru.dbotthepony.mc.otm.client.screen.panels.slot.AbstractSlotPanel
import ru.dbotthepony.mc.otm.core.collect.filter
import ru.dbotthepony.mc.otm.core.collect.maybe

open class GridPanel<out S : Screen>(
	screen: S,
	parent: EditablePanel<*>?,
	x: Float = 0f,
	y: Float = 0f,
	width: Float = 0f,
	height: Float = 0f,
	columns: Int,
	rows: Int
) : EditablePanel<S>(screen, parent, x, y, width, height) {
	var columns: Int = columns
		set(value) {
			field = value
			invalidateLayout()
		}

	var rows: Int = rows
		set(value) {
			field = value
			invalidateLayout()
		}

	var gravity: RenderGravity = RenderGravity.CENTER_CENTER
		set(value) {
			field = value
			invalidateLayout()
		}

	override fun performLayout() {
		super.performLayout()
		var children = visibleChildren.iterator().filter { it.dock == Dock.NONE }

		var totalWidth = 0f
		var totalHeight = 0f

		for (row in 0 until rows) {
			var maxHeight = 0f
			var width = 0f

			for (column in 0 until columns) {
				val child = children.maybe() ?: break
				width += child.dockedWidth
				maxHeight = maxHeight.coerceAtLeast(child.dockedHeight)
			}

			totalWidth = totalWidth.coerceAtLeast(width)
			totalHeight += maxHeight
		}

		val alignX = gravity.repositionX(width, totalWidth)
		val alignY = gravity.repositionY(height, totalHeight)
		children = visibleChildren.iterator().filter { it.dock == Dock.NONE }

		totalWidth = 0f
		totalHeight = 0f

		for (row in 0 until rows) {
			var maxHeight = 0f
			var width = 0f

			for (column in 0 until columns) {
				val child = children.maybe() ?: break
				child.x = alignX + width
				child.y = alignY + totalHeight
				width += child.dockedWidth
				maxHeight = maxHeight.coerceAtLeast(child.dockedHeight)
			}

			totalWidth = totalWidth.coerceAtLeast(width)
			totalHeight += maxHeight
		}
	}

	companion object {
		fun <S : Screen> slots(screen: S, parent: EditablePanel<*>?, columns: Int, rows: Int): GridPanel<S> {
			return GridPanel(screen, parent, width = columns * AbstractSlotPanel.SIZE, height = rows * AbstractSlotPanel.SIZE, rows = rows, columns = columns)
		}
	}
}
