package ch.dissem.yaep.domain

@Suppress("UNCHECKED_CAST", "JavaDefaultMethodsNotOverriddenByDelegation")
class Grid(
    val rows: List<GameRow<*>>
) : List<GameRow<ItemClass<*>>> by rows as List<GameRow<ItemClass<*>>> {

    val cells: List<GameCell<*>>
        get() = rows.flatten()

    fun <C : ItemClass<C>> indexOf(element: C): Int {
        return this[element.companion]
            .indexOfFirst { it.selection?.itemType == element }
    }

    operator fun <C : ItemClass<C>> get(itemType: ItemClassCompanion<C>): GameRow<C> {
        @Suppress("UNCHECKED_CAST")
        return rows.first { it.category == itemType } as GameRow<C>
    }

    operator fun <C : ItemClass<C>> get(item: Item<C>): GameCell<C> {
        return this[item.itemType.companion].first { it.selection == item }
    }

    override fun toString(): String {
        return joinToString("\n") { row ->
            row.joinToString("") { it.selection?.symbol ?: "⬛" }
        }
    }

    fun cleanupOptions() {
        forEach { row -> row.cleanupOptions() }
    }

    fun snapshot() {
        forEach { row -> row.snapshot() }
    }

    fun undo(): Boolean {
        return map { row -> row.undo() }.reduce { a, b -> a || b }
    }
}

fun List<List<Item<ItemClass<*>>>>.toGrid(): Grid = Grid(
    map { row ->
        GameRow(
            category = row.first().itemType.companion,
            options = row.sorted(),
            cells = row.map {
                GameCell(
                    selection = null,
                    solution = it,
                    options = row.toMutableList()
                )
            }
        )
    }
)
