package ocelot.desktop.audio

import ocelot.desktop.util.{FileUtils, Logging, Resource}
import org.lwjgl.openal.AL10

class SoundBuffer(val file: String) extends Resource with Logging {
  private var _bufferId: Option[Int] = None

  Audio.synchronized {
    OpenAlException.ignoring {
      if (!Audio.isDisabled) {
        logger.debug(s"Loading sound buffer from '$file'...")
        _bufferId = Some(AL10W.alGenBuffers())

        if (AL10W.alIsExtensionPresent("AL_EXT_vorbis")) {
          initWithExt()
        } else {
          initFallback()
        }
      } else {
        logger.debug(s"Skipping loading sound buffer from '$file' because audio is not available")
      }
    }
  }

  @throws[OpenAlException]
  private def initWithExt(): Unit = {
    val fileBuffer = FileUtils.load(file)
    if (fileBuffer == null) {
      logger.error(s"Could not load '$file'!")
      return
    }

    AL10W.alBufferData(bufferId.get, AL10.AL_FORMAT_VORBIS_EXT, fileBuffer, -1)
  }

  @throws[OpenAlException]
  private def initFallback(): Unit = {
    val ogg = OggDecoder.decode(getClass.getResourceAsStream(file))
    _bufferId = ogg.genBuffer()
  }

  def numSamples: Int = bufferId match {
    case Some(bufferId) =>
      OpenAlException.defaulting(0) {
        val sizeBytes = AL10W.alGetBufferi(bufferId, AL10.AL_SIZE)
        val channels = AL10W.alGetBufferi(bufferId, AL10.AL_CHANNELS)
        val bits = AL10W.alGetBufferi(bufferId, AL10.AL_BITS)

        sizeBytes * 8 / channels / bits
      }

    case None => 0
  }

  val sampleRate: Int = bufferId match {
    case Some(bufferId) =>
      OpenAlException.defaulting(44100) {
        Audio.synchronized {
          AL10W.alGetBufferi(bufferId, AL10.AL_FREQUENCY)
        }
      }

    case None => 44100
  }

  def bufferId: Option[Int] = _bufferId

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

    bufferId.foreach { bufferId =>
      OpenAlException.ignoring {
        AL10W.alDeleteBuffers(bufferId)
      }
    }
  }
}
