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

import net.minecraft.util.Mth
import net.minecraft.util.RandomSource
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.GJRAND64Random
import java.lang.StringBuilder

class GJRAND64RandomSource : GJRAND64Random, IRandomSourceGenerator {
	private val gaussian = MarsagliaPolarGaussian(this)

	constructor() : super(RandomSupport.generateUniqueSeed(), RandomSupport.generateUniqueSeed())
	constructor(seed: Long) : super(seed)
	constructor(seed0: Long, seed1: Long) : super(seed0, seed1)

	override fun nextInt(): Int {
		return nextLong().ushr(32).toInt()
	}

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

	override fun fork(): RandomSource {
		return GJRAND64RandomSource(nextLong(), nextLong())
	}

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

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

	class Positional(private val seed0: Long, private val seed1: Long) : PositionalRandomFactory {
		override fun at(x: Int, y: Int, z: Int): RandomSource {
			val seed = Mth.getSeed(x, y, z)
			return GJRAND64RandomSource(seed0.xor(seed.rotateLeft(32)), seed1.xor(seed))
		}

		override fun fromHashOf(name: String): RandomSource {
			return GJRAND64RandomSource(name.hashCode().toLong().xor(seed0), seed1)
		}

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

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