package ru.dbotthepony.kstarbound.world.api

import com.github.benmanes.caffeine.cache.Interner
import ru.dbotthepony.kstarbound.Registry
import ru.dbotthepony.kstarbound.Starbound
import ru.dbotthepony.kstarbound.defs.tile.BuiltinMetaMaterials
import ru.dbotthepony.kstarbound.defs.tile.TileModifierDefinition
import ru.dbotthepony.kstarbound.defs.tile.TileDefinition
import ru.dbotthepony.kstarbound.network.LegacyNetworkTileState
import java.io.DataInputStream
import java.io.DataOutputStream

sealed class AbstractTileState {
	abstract val material: Registry.Entry<TileDefinition>
	abstract val modifier: Registry.Entry<TileModifierDefinition>
	abstract val color: TileColor
	abstract val hueShift: Float
	abstract val modifierHueShift: Float

	abstract fun immutable(): ImmutableTileState
	abstract fun mutable(): MutableTileState

	fun byteHueShift(): Int {
		return (hueShift / 360f * 255).toInt()
	}

	fun byteModifierHueShift(): Int {
		return (modifierHueShift / 360f * 255).toInt()
	}

	open fun toLegacyNet(): LegacyNetworkTileState {
		if (material.id != null && material.id in 0 .. 65535) {
			val validMod = modifier.id != null && modifier.id!! in 0 .. 65535
			return LegacyNetworkTileState(material.id!!, byteHueShift(), color.ordinal, if (validMod) modifier.id!! else 0, if (validMod) byteModifierHueShift() else 0)
		} else {
			return LegacyNetworkTileState.EMPTY
		}
	}

	fun write(stream: DataOutputStream) {
		stream.writeShort(material.id ?: 0)
		stream.writeByte(byteHueShift())
		stream.writeByte(color.ordinal)

		stream.writeShort(modifier.id ?: 0)
		stream.write(byteModifierHueShift())
	}

	companion object {
		fun skip(stream: DataInputStream) {
			stream.skipNBytes(2 + 1 + 1 + 2 + 1)
		}

		@JvmStatic
		protected val POOL: Interner<ImmutableTileState> = if (Starbound.DEDUP_CELL_STATES) Starbound.interner() else Interner { it }

		val EMPTY: ImmutableTileState = POOL.intern(ImmutableTileState(BuiltinMetaMaterials.EMPTY))
		val NULL: ImmutableTileState = POOL.intern(ImmutableTileState(BuiltinMetaMaterials.NULL))
	}
}
