package ocelot.desktop.entity

import ocelot.desktop.util.WebcamCapture
import totoro.ocelot.brain.Constants
import totoro.ocelot.brain.entity.machine.{Arguments, Context}
import totoro.ocelot.brain.entity.traits.DeviceInfo.{DeviceAttribute, DeviceClass}
import totoro.ocelot.brain.entity.traits.{DeviceInfo, Entity, GenericCamera}
import totoro.ocelot.brain.nbt.NBTTagCompound
import totoro.ocelot.brain.util.ResultWrapper.result
import totoro.ocelot.brain.workspace.Workspace

class Camera extends Entity with GenericCamera with DeviceInfo {
  var webcamCapture: Option[WebcamCapture] = WebcamCapture.getDefault
  var flipHorizontally: Boolean = false
  var flipVertically: Boolean = false
  var directCalls: Boolean = false

  override protected def distanceImpl(context: Context, args: Arguments): Array[AnyRef] = {
    if (!directCalls)
      context.consumeCallBudget(1.0 / Camera.DistanceCallCost)

    result(webcamCapture match {
      case Some(webcamCapture) =>
        var x: Float = 0f
        var y: Float = 0f

        if (args.count() == 2) {
          // [-1; 1] => [0; 1]
          x = (args.checkDouble(0).toFloat + 1f) / 2f
          y = (args.checkDouble(1).toFloat + 1f) / 2f
        }

        if (!flipHorizontally) x = 1f - x
        if (!flipVertically) y = 1f - y

        webcamCapture.ray(x, y)

      case None => 0f
    })
  }

  override def getDeviceInfo: Map[String, String] = Map(
    DeviceAttribute.Class -> DeviceClass.Multimedia,
    DeviceAttribute.Description -> "Dungeon Scanner 2.5D",
    DeviceAttribute.Vendor -> Constants.DeviceInfo.DefaultVendor,
    DeviceAttribute.Product -> webcamCapture.map(_.name).getOrElse("Blind Pirate"),
  )

  override def load(nbt: NBTTagCompound, workspace: Workspace): Unit = {
    super.load(nbt, workspace)

    if (nbt.hasKey("device"))
      webcamCapture = WebcamCapture.getInstance(nbt.getString("device")).orElse(WebcamCapture.getDefault)

    if (nbt.hasKey("flipHorizontally"))
      flipHorizontally = nbt.getBoolean("flipHorizontally")

    if (nbt.hasKey("flipVertically"))
      flipVertically = nbt.getBoolean("flipVertically")

    if (nbt.hasKey("directCalls"))
      directCalls = nbt.getBoolean("directCalls")
  }

  override def save(nbt: NBTTagCompound): Unit = {
    super.save(nbt)

    webcamCapture.foreach(capture => nbt.setString("device", capture.name))
    nbt.setBoolean("flipHorizontally", flipHorizontally)
    nbt.setBoolean("flipVertically", flipVertically)
    nbt.setBoolean("directCalls", directCalls)
  }
}

object Camera {
  private val DistanceCallCost = 20
}
