package ocelot.desktop.ui.widget.tooltip

import ocelot.desktop.geometry.{Size2D, Vector2D}
import ocelot.desktop.graphics.Graphics
import ocelot.desktop.ui.UiHandler
import ocelot.desktop.ui.layout.Layout
import ocelot.desktop.ui.widget.Widget
import ocelot.desktop.util.animation.easing.Easing

import scala.collection.mutable.ListBuffer

class TooltipPool extends Widget {
  private val Offset = 10
  private val ScreenPadding = 10

  private def offset(tooltip: Tooltip): Vector2D = {
    val mouse = UiHandler.mousePosition
    val x = if (mouse.x > width - tooltip.width - Offset - ScreenPadding) -Offset - tooltip.width else Offset
    val y = if (mouse.y > height - tooltip.height - Offset - ScreenPadding) -Offset - tooltip.height else Offset
    Vector2D(x, y)
  }

  override protected val layout: Layout = new Layout(this) {
    override def relayout(): Unit = {
      for (tooltip <- tooltips) {
        tooltip.tooltip match {
          case t: Tooltip =>
            if (!(t.isClosing && tooltip.delay == 0))
              t.rawSetPosition(UiHandler.mousePosition + offset(t))
          case _ =>
        }
      }
      super.relayout()
    }
  }

  private val tooltips: ListBuffer[DelayedTooltip] = ListBuffer()

  def addTooltip(tooltip: Tooltip, delayTime: Float): Unit = {
    tooltips += DelayedTooltip(delayTime, tooltip)
    children :+= tooltip
    tooltip.close(true)
  }

  def addTooltip(tooltip: Tooltip): Unit = {
    addTooltip(tooltip, tooltip.DelayTime)
  }

  def closeTooltip(tooltip: Tooltip): Unit = {
    tooltips.find(_.tooltip == tooltip).foreach(tooltip => {
      tooltip.delay = 0
      tooltip.tooltip.close()
    })
  }

  def removeTooltip(tooltip: Tooltip): Unit = {
    tooltips.filterInPlace(_.tooltip != tooltip)
    children = children.filter(_ != tooltip)
  }

  def removeTooltips(tooltipsToRemove: Iterable[Tooltip]): Unit = {
    tooltips.filterInPlace(dt => !tooltipsToRemove.exists(_ == dt.tooltip))
    children = children.filter(t => !tooltipsToRemove.exists(_ == t))
  }

  private def removeDelayedTooltips(tooltipsToRemove: Iterable[DelayedTooltip]): Unit = {
    tooltips.filterInPlace(dt => !tooltipsToRemove.exists(_ == dt))
    children = children.filter(t => !tooltipsToRemove.exists(_.tooltip == t))
  }

  override def minimumSize: Size2D = Size2D.Zero
  override def maximumSize: Size2D = Size2D.Inf

  override def receiveMouseEvents: Boolean = false
  override def receiveScrollEvents: Boolean = false

  override def update(): Unit = {
    super.update()

    var dueToClean = false
    tooltips.foreach(tooltip => {
      if (tooltip.delay > 0) {
        tooltip.delay = Math.max(0, tooltip.delay - UiHandler.dt)
        if (tooltip.delay <= 0)
          tooltip.tooltip.open()
      }
      if (tooltip.delay <= 0) {
        if (tooltip.tooltip.isClosed)
          dueToClean = true
      }
      tooltip.tooltip.position = tooltip.tooltip.position +
        (UiHandler.mousePosition + offset(tooltip.tooltip) - tooltip.tooltip.position) *
        (if (tooltip.tooltip.isClosing) math.pow(Easing.easeInQuad(tooltip.tooltip.getAlpha), 6).toFloat else 1f)
    })

    if (dueToClean) {
      val toRemove = tooltips.filter(tooltip => tooltip.delay <= 0 && tooltip.tooltip.isClosed)
      if (toRemove.nonEmpty) removeDelayedTooltips(toRemove)
    }
  }

  override def draw(g: Graphics): Unit = {
    drawChildren(g)
  }

  private case class DelayedTooltip(var delay: Float, tooltip: Tooltip)
}
