package ru.dbotthepony.kstarbound.defs.dungeon

import com.google.gson.JsonObject
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
import ru.dbotthepony.kstarbound.json.builder.JsonFactory
import ru.dbotthepony.kstarbound.util.AssetPathStack

class TiledTileSets(entries: List<Entry>) {
	@JsonFactory
	data class Entry(
		val firstgid: Int,
		// not asset path because of funky names which can't be properly
		// untangled by AssetPath's adapter code
		val source: String,
	)

	private var front: Int2ObjectOpenHashMap<Pair<DungeonTile, JsonObject>>
	private var back: Int2ObjectOpenHashMap<Pair<DungeonTile, JsonObject>>

	init {
		val mapped = entries.map { (firstgid, source) ->
			// Tiled stores tileset paths relative to the map file, which can go below
			// the assets root if it's referencing a tileset in another asset package.
			// The solution chosen here is to ignore everything in the path up until a
			// known path segment, e.g.:
			//  "source" : "..\/..\/..\/..\/packed\/tilesets\/packed\/materials.json"
			// We ignore everything up until the 'tilesets' path segment, and the asset
			// we actually load is located at:
			//  /tilesets/packed/materials.json
			val actualSource: String
			val split = source.lowercase().lastIndexOf("/tilesets/")

			if (split != -1) {
				actualSource = source.substring(split)
			} else {
				actualSource = AssetPathStack.remap(source)
			}

			firstgid to TiledTileSet.load(actualSource)
		}

		front = Int2ObjectOpenHashMap<Pair<DungeonTile, JsonObject>>(mapped.sumOf { it.second.size })
		back = Int2ObjectOpenHashMap<Pair<DungeonTile, JsonObject>>(mapped.sumOf { it.second.size })

		for ((firstgid, set) in mapped) {
			for (i in 0 until set.size) {
				front.put(firstgid + i, set.front[i] ?: throw NullPointerException("aeiou"))
				back.put(firstgid + i, set.back[i] ?: throw NullPointerException("aeiou"))
			}
		}
	}

	fun getFront(gid: Int): DungeonTile {
		return front[gid]?.first ?: DungeonTile.EMPTY
	}

	fun getBack(gid: Int): DungeonTile {
		return back[gid]?.first ?: DungeonTile.CLEAR
	}

	fun getFrontData(gid: Int): JsonObject {
		return front[gid]?.second ?: JsonObject()
	}

	fun getBackData(gid: Int): JsonObject {
		return back[gid]?.second ?: JsonObject()
	}

	fun free() {
		front = Int2ObjectOpenHashMap()
		back = Int2ObjectOpenHashMap()
	}
}
