package ru.dbotthepony.kstarbound.math

import ru.dbotthepony.kommons.math.linearInterpolation
import java.util.random.RandomGenerator

data class PeriodicFunction(
	val period: Double = 1.0,
	val min: Double = 0.0,
	val max: Double = 1.0,
	val periodVariance: Double = 0.0,
	val magnitudeVariance: Double = 0.0
) {
	private var timer = 0.0
	private var timerMax = 1.0

	private var base = 0.0
	private var target = 0.0
	private var isDescending = false

	private val halfPeriod = period * 0.5
	private val halfVariance = periodVariance * 0.5

	fun update(delta: Double, random: RandomGenerator) {
		timer -= delta

		// original code here explicitly ignore deltas bigger than max period time
		// we, however, do not, if period time is big enough
		while (timer <= 0.0) {
			base = target
			target = (if (isDescending) min else max) + if (magnitudeVariance == 0.0) 0.0 else random.nextDouble(-magnitudeVariance, magnitudeVariance)
			isDescending = !isDescending
			timerMax = (halfPeriod + if (halfVariance == 0.0) 0.0 else random.nextDouble(-halfVariance, halfVariance)).coerceAtLeast(0.01)
			timer += timerMax

			if (timerMax <= 0.05 && timer <= 0.0) {
				timer = 0.0
				break
			}
		}
	}

	fun value(interpolator: Interpolator): Double {
		return interpolator.interpolate(1.0 - timer / timerMax, base, target)
	}

	fun value(): Double {
		return value(::linearInterpolation)
	}

	fun sinValue(): Double {
		return value(Interpolator.Sin)
	}
}
