package ocelot.desktop.geometry

import java.nio.ByteBuffer

object Transform2D {
  def identity: Transform2D = Transform2D(
    1, 0, 0,
    0, 1, 0,
  )

  def scale(x: Float, y: Float): Transform2D = Transform2D(
    x, 0, 0,
    0, y, 0,
  )

  def scale(a: Float): Transform2D = Transform2D.scale(a, a)

  def translate(x: Float, y: Float): Transform2D = Transform2D(
    1, 0, x,
    0, 1, y,
  )

  def viewport(width: Float, height: Float): Transform2D =
    Transform2D.translate(-1f, 1f) >> Transform2D.scale(2f / width, -2f / height)

  def rotate(angle: Float): Transform2D = {
    val (s, c) = (math.sin(angle).toFloat, math.cos(angle).toFloat)

    // format: off
    Transform2D(
      c, -s, 0,
      s, c, 0
    )
  }
}

case class Transform2D(m11: Float, m12: Float, m13: Float, m21: Float, m22: Float, m23: Float) {
  def array: Array[Float] = Array(m11, m12, m13, m21, m22, m23)

  // format: off
  def >>(that: Transform2D): Transform2D = Transform2D(
    m11 * that.m11 + m12 * that.m21, m11 * that.m12 + m12 * that.m22, m11 * that.m13 + m12 * that.m23 + m13,
    m21 * that.m11 + m22 * that.m21, m21 * that.m12 + m22 * that.m22, m21 * that.m13 + m22 * that.m23 + m23,
  )

  // format: off
  def <<(that: Transform2D): Transform2D = Transform2D(
    m11 * that.m11 + m21 * that.m12, m12 * that.m11 + m22 * that.m12, m13 * that.m11 + m23 * that.m12 + that.m13,
    m11 * that.m21 + m21 * that.m22, m12 * that.m21 + m22 * that.m22, m13 * that.m21 + m23 * that.m22 + that.m23
  )

  def *(that: Vector2D): Vector2D = Vector2D(
    m11 * that.x + m12 * that.y + m13,
    m21 * that.x + m22 * that.y + m23,
  )

  override def toString: String = {
    f"""Transform2D [$m11%6.3f $m12%6.3f $m13%6.3f]
       |            [$m21%6.3f $m22%6.3f $m23%6.3f]
     """.stripMargin
  }

  // (╯°□°)╯︵ ┻━┻
  def put(buffer: ByteBuffer): Unit = {
    buffer.putFloat(m11)
    buffer.putFloat(m12)
    buffer.putFloat(m13)

    buffer.putFloat(m21)
    buffer.putFloat(m22)
    buffer.putFloat(m23)
  }
}
