package ru.dbotthepony.kstarbound.defs.util

import com.github.benmanes.caffeine.cache.Interner
import com.google.gson.JsonArray
import com.google.gson.JsonElement
import com.google.gson.JsonNull
import com.google.gson.JsonObject
import com.google.gson.JsonPrimitive
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap

private fun flattenJsonPrimitive(input: JsonPrimitive, interner: Interner<String> = Interner { it }): Any {
	if (input.isNumber) {
		return input.asNumber
	} else if (input.isString) {
		return interner.intern(input.asString)
	} else {
		return input.asBoolean
	}
}

private fun flattenJsonArray(input: JsonArray, interner: Interner<String> = Interner { it }): ArrayList<Any> {
	val flattened = ArrayList<Any>(input.size())

	for (v in input) {
		when (v) {
			is JsonObject -> flattened.add(flattenJsonObject(v, interner))
			is JsonArray -> flattened.add(flattenJsonArray(v, interner))
			is JsonPrimitive -> flattened.add(flattenJsonPrimitive(v, interner))
			// is JsonNull -> baked.add(null)
		}
	}

	return flattened
}

private fun flattenJsonObject(input: JsonObject, interner: Interner<String> = Interner { it }): MutableMap<String, Any> {
	val flattened = HashMap<String, Any>()

	for ((k, v) in input.entrySet()) {
		when (v) {
			is JsonObject -> flattened[k] = flattenJsonObject(v, interner)
			is JsonArray -> flattened[k] = flattenJsonArray(v, interner)
			is JsonPrimitive -> flattened[k] = flattenJsonPrimitive(v, interner)
		}
	}

	return flattened
}

fun flattenJsonElement(input: JsonElement, interner: Interner<String> = Interner { it }): Any? {
	return when (input) {
		is JsonObject -> flattenJsonObject(input, interner)
		is JsonArray -> flattenJsonArray(input, interner)
		is JsonPrimitive -> flattenJsonPrimitive(input, interner)
		is JsonNull -> null
		else -> throw IllegalArgumentException("Unknown argument $input")
	}
}

fun flattenJsonElement(input: JsonObject, interner: Interner<String> = Interner { it }) = flattenJsonObject(input, interner)
fun flattenJsonElement(input: JsonArray, interner: Interner<String> = Interner { it }) = flattenJsonArray(input, interner)
fun flattenJsonElement(input: JsonPrimitive, interner: Interner<String> = Interner { it }) = flattenJsonPrimitive(input, interner)
