package ru.dbotthepony.mc.otm.core.collect

import com.google.common.collect.ImmutableMap
import com.google.common.collect.ImmutableSet
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap
import ru.dbotthepony.mc.otm.core.stream
import java.util.function.Supplier
import java.util.stream.Stream

class SupplierMap<K, T>(values: Stream<Pair<K, Supplier<T>>>) : Map<K, T> {
	private val backing = Object2ObjectOpenHashMap<K, Supplier<T>>()
	override val entries: Set<Map.Entry<K, T>>
	override val keys: Set<K>
		get() = backing.keys
	override val size: Int
		get() = entries.size
	override val values: Collection<T>

	init {
		values.forEach {
			backing[it.first] = it.second
		}

		entries = ImmutableSet.copyOf(backing.entries.map { Entry(it.key, it.value) })
		this.values = SupplierList(backing.values)
	}

	override fun containsKey(key: K): Boolean {
		return key in keys
	}

	override fun containsValue(value: T): Boolean {
		return value in values
	}

	override fun get(key: K): T? {
		return backing[key]?.get()
	}

	override fun isEmpty(): Boolean {
		return entries.isEmpty()
	}

	constructor(vararg mValues: Pair<K, Supplier<T>>) : this((mValues as Array<Pair<K, Supplier<T>>>).stream())
	constructor(mValues: Collection<Pair<K, Supplier<T>>>) : this(mValues.stream())
	constructor(mValues: Map<K, Supplier<T>>) : this(mValues.entries.stream().map { it.key to it.value })

	private inner class Entry(
		override val key: K,
		val getter: Supplier<T>
	) : Map.Entry<K, T> {
		override val value: T
			get() = getter.get()
	}
}
