package ocelot.desktop.util.animation

import ocelot.desktop.ui.UiHandler
import ocelot.desktop.util.animation.easing.{Easing, EasingFunction}
import totoro.ocelot.brain.nbt.NBTTagCompound

class ValueAnimation(init: Float = 0f, var speed: Float = 10f) {
  private var _value = init
  private var start = init
  private var end = init
  private var time = 0f
  private var reached = true
  private var _easing: EasingFunction = Easing.easeInOutQuad
  private var nextEasing = _easing

  def save(nbt: NBTTagCompound, name: String): Unit = {
    val animationNbt = new NBTTagCompound
    animationNbt.setFloat("t", time)
    animationNbt.setFloat("start", start)
    animationNbt.setFloat("end", end)
    animationNbt.setBoolean("reached", reached)
    animationNbt.setFloat("value", _value)
    nbt.setTag(name, animationNbt)
  }

  def load(nbt: NBTTagCompound, name: String): Unit = {
    if (nbt.hasKey(name)) {
      val animationNbt = nbt.getCompoundTag(name)
      time = animationNbt.getFloat("t")
      start = animationNbt.getFloat("start")
      end = animationNbt.getFloat("end")
      reached = animationNbt.getBoolean("reached")
      _value = animationNbt.getFloat("value")
    }
  }

  def easing: EasingFunction = _easing

  def easing_=(value: EasingFunction): Unit = {
    nextEasing = value
    updateEasing()
  }

  def value: Float = _value

  def jump(to: Float): Unit = {
    _value = to
    start = to
    end = to
    updateReached()
  }

  def goto(to: Float): Unit = {
    start = _value
    end = to
    time = 0
    updateReached()
  }

  def isAt(value: Float): Boolean = {
    (_value - value).abs < 0.001
  }

  def update(): Unit = {
    if (reached) return

    val dist = (end - start).abs
    val dt = (UiHandler.dt * speed) / dist
    time = (time + dt).min(1).max(0)

    _value = if (start > end)
      start - time * dist
    else
      start + time * dist

    updateReached()
    if (reached) _easing = nextEasing
  }

  private def updateReached(): Unit = {
    reached = (_value - end).abs < 0.001
  }

  private def updateEasing(): Unit = {
    updateReached()
    if (reached) _easing = nextEasing
  }
}
