package ru.dbotthepony.mc.otm.core.util

import net.minecraft.util.Mth
import net.minecraft.util.RandomSource
import net.minecraft.world.level.levelgen.LegacyRandomSource
import net.minecraft.world.level.levelgen.MarsagliaPolarGaussian
import net.minecraft.world.level.levelgen.PositionalRandomFactory
import net.minecraft.world.level.levelgen.RandomSupport
import ru.dbotthepony.kommons.random.LCG64Random
import java.lang.StringBuilder

/**
 * Simple and insanely fast random number generator, which can be used for seeding (initializing internal state) of other number generators.
 *
 * While can be used on its own, it probably shouldn't.
 *
 * Differs from [LegacyRandomSource] (also LCG, created by [RandomSource.create]) Minecraft uses in:
 * * Different constants (with supposedly/expected better statistical properties)
 * * Always use upper 32 bits instead of implementing BitRandomSource and sampling some upper bits
 * * Uses all bits from provided seed
 */
class LCG64RandomSource(seed: Long = RandomSupport.generateUniqueSeed()) : LCG64Random(seed), IRandomSourceGenerator {
	private val gaussian = MarsagliaPolarGaussian(this)

	override fun setSeed(seed: Long) {
		this.seed = seed
		gaussian.reset()
	}

	override fun nextGaussian(): Double {
		return gaussian.nextGaussian()
	}

	override fun fork(): RandomSource {
		return LCG64RandomSource(nextLong())
	}

	override fun forkPositional(): PositionalRandomFactory {
		return Positional(nextLong())
	}

	class Positional(private val seed: Long) : PositionalRandomFactory {
		override fun at(x: Int, y: Int, z: Int): RandomSource {
			return LCG64RandomSource(Mth.getSeed(x, y, z).xor(seed))
		}

		override fun fromHashOf(name: String): RandomSource {
			return LCG64RandomSource(name.hashCode().toLong().xor(seed))
		}

		override fun fromSeed(seed: Long): RandomSource {
			return LCG64RandomSource(seed)
		}

		override fun parityConfigString(builder: StringBuilder) {
			throw UnsupportedOperationException()
		}
	}
}
