package ru.dbotthepony.kstarbound.defs

import com.google.gson.Gson
import com.google.gson.JsonSyntaxException
import com.google.gson.TypeAdapter
import com.google.gson.annotations.JsonAdapter
import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonToken
import com.google.gson.stream.JsonWriter
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap
import ru.dbotthepony.kommons.gson.consumeNull
import ru.dbotthepony.kommons.math.RGBAColor

@JsonAdapter(ColorReplacements.Adapter::class)
class ColorReplacements private constructor(private val mapping: Int2IntOpenHashMap) {
	constructor(mapping: Map<Int, Int>) : this(Int2IntOpenHashMap(mapping))

	fun replace(color: Int): Int {
		return mapping.getOrDefault(color, color)
	}

	fun toImageOperator(): String {
		return "replace;${mapping.int2IntEntrySet().joinToString { "${RGBAColor.rgb(it.intKey).toHexStringRGB()}=${RGBAColor.rgb(it.intValue).toHexStringRGB()}" }}"
	}

	class Adapter(gson: Gson) : TypeAdapter<ColorReplacements>() {
		override fun write(out: JsonWriter, value: ColorReplacements?) {
			if (value == null)
				out.nullValue()
			else {
				out.beginObject()

				for ((k, v) in value.mapping) {
					out.name(RGBAColor.rgb(k).toHexStringRGB())
					out.value(RGBAColor.rgb(v).toHexStringRGB())
				}

				out.endObject()
			}
		}

		override fun read(`in`: JsonReader): ColorReplacements? {
			if (`in`.consumeNull())
				return null
			else if (`in`.peek() == JsonToken.STRING) {
				if (`in`.nextString() != "")
					throw JsonSyntaxException("Invalid color replacement definition near ${`in`.path}")

				return EMPTY
			}

			val mapping = Int2IntOpenHashMap()

			`in`.beginObject()

			while (`in`.peek() != JsonToken.END_OBJECT) {
				val kGet = `in`.nextName()
				val vGet = `in`.nextString()
				val k = RGBAColor.fromHexStringRGB(kGet)
				val v = RGBAColor.fromHexStringRGB(vGet)

				if (k == null) {
					throw JsonSyntaxException("Not a valid Hex color: $kGet")
				}

				if (v == null) {
					throw JsonSyntaxException("Not a valid Hex color: $vGet")
				}

				mapping[k.toRGBA()] = v.toRGBA()
			}

			`in`.endObject()

			return ColorReplacements(mapping)
		}
	}

	companion object {
		val EMPTY = ColorReplacements(Int2IntOpenHashMap())
	}
}
