package ocelot.desktop.audio

import ocelot.desktop.Settings
import ocelot.desktop.util.Logging
import org.lwjgl.openal.AL10

import java.nio.{ByteBuffer, IntBuffer}

object AL10W extends Logging {
  private def run[T](func: String)(f: => T): T = {
    val res = f
    val err = AL10.alGetError()
    if (err != AL10.AL_NO_ERROR) {
      val errName = classOf[AL10].getDeclaredFields.find(field => {
        try {
          field.getInt() == err
        } catch {
          case _: Exception => false
        }
      }).map(_.getName).getOrElse(err.toHexString)
      val exc = OpenAlException(func, errName, err)

      if (Settings.get.logAudioErrorStacktrace) {
        logger.error(exc.getMessage, exc)
      } else {
        logger.error(exc.getMessage)
      }

      throw exc
    }

    res
  }

  def alIsExtensionPresent(name: String): Boolean = OpenAlException.defaulting(false) {
    run("alIsExtensionPresent") {
      AL10.alIsExtensionPresent(name)
    }
  }

  @throws[OpenAlException]
  def alGenBuffers(): Int = run("alGenBuffers") {
    AL10.alGenBuffers()
  }

  @throws[OpenAlException]
  def alBufferData(buffer: Int, format: Int, data: ByteBuffer, freq: Int): Unit = run("alBufferData") {
    AL10.alBufferData(buffer, format, data, freq)
  }

  @throws[OpenAlException]
  def alGetBufferi(buffer: Int, pname: Int): Int = run("alGetBufferi") {
    AL10.alGetBufferi(buffer, pname)
  }

  @throws[OpenAlException]
  def alDeleteBuffers(buffer: Int): Unit = run("alDeleteBuffers") {
    AL10.alDeleteBuffers(buffer)
  }

  @throws[OpenAlException]
  def alGenSources(): Int = run("alGenSources") {
    AL10.alGenSources()
  }

  @throws[OpenAlException]
  def alSourceQueueBuffers(source: Int, buffer: Int): Unit = run("alSourceQueueBuffers") {
    AL10.alSourceQueueBuffers(source, buffer)
  }

  @throws[OpenAlException]
  def alSourceUnqueueBuffers(source: Int, buffers: IntBuffer): Unit = run("alSourceUnqueueBuffers") {
    AL10.alSourceUnqueueBuffers(source, buffers)
  }

  @throws[OpenAlException]
  def alGetSourcei(source: Int, pname: Int): Int = run("alGetSourcei") {
    AL10.alGetSourcei(source, pname)
  }

  @throws[OpenAlException]
  def alSourcei(source: Int, pname: Int, value: Int): Unit = run("alSourcei") {
    AL10.alSourcei(source, pname, value)
  }

  @throws[OpenAlException]
  def alSourcef(source: Int, pname: Int, value: Float): Unit = run("alSourcef") {
    AL10.alSourcef(source, pname, value)
  }

  @throws[OpenAlException]
  def alSource3f(source: Int, pname: Int, v1: Float, v2: Float, v3: Float): Unit = run("alSource3f") {
    AL10.alSource3f(source, pname, v1, v2, v3)
  }

  @throws[OpenAlException]
  def alSourcePlay(source: Int): Unit = run("alSourcePlay") {
    AL10.alSourcePlay(source)
  }

  @throws[OpenAlException]
  def alSourcePause(source: Int): Unit = run("alSourcePause") {
    AL10.alSourcePause(source)
  }

  @throws[OpenAlException]
  def alSourceStop(source: Int): Unit = run("alSourceStop") {
    AL10.alSourceStop(source)
  }

  @throws[OpenAlException]
  def alDeleteSources(source: Int): Unit = run("alDeleteSources") {
    AL10.alDeleteSources(source)
  }
}
