// Filename: audio/SoundManager.h
// Author: Jorge Bernadas (JB)
// Date of Creation: 12/07/2006
// Version: 1.0
#include "assert.h"
#include "stdlib.h"

#include "Sound.h"

Sound::Sound() : buffer_(0), source_(0) {
}

Sound::~Sound() {
  Destroy();
}

bool Sound::LoadWaveFile(const char* filename, ALuint buffer) {
  // validate input parameters
  assert(filename != NULL);
  assert(buffer != 0);

  // data used to load a WAV file from ALUT
  ALsizei size, freq;
  ALenum format;
  ALvoid* data;
  ALboolean loop;

  // load the WAV file using ALUT and check for any error
  alutLoadWAVFile(filename, &format, &data, &size, &freq, &loop);
  if (alGetError() != AL_NO_ERROR)
    return false;

  // copy the data in the buffer using the data from ALUT, unload it and return
  alBufferData(buffer, format, data, size, freq);
  alutUnloadWAV(format, data, size, freq);
  return true;
}

bool Sound::Create(const char* filename) {
  assert(!IsSoundLoaded());

  // generate the buffer, load the file and check for any error
  ALuint buffer = 0;
  alGenBuffers(1, &buffer);
  if (!LoadWaveFile(filename, buffer))
    return false;

  // generate the source and attach the loaded buffer
  ALuint source = 0;
  alGenSources(1, &source);
  alSourcei(source, AL_BUFFER, buffer);

  // check if there was an error during the previous operations
  if (alGetError() != AL_NO_ERROR)
    return false;

  // copy the sound values and return success
  buffer_ = buffer;
  source_ = source;
  return true;
}

void Sound::Destroy() {
  if (IsSoundLoaded()) {
    // stop the sound is still playing
    ALint state = 0;
    const ALuint source = source_;
    alGetSourcei(source, AL_SOURCE_STATE, &state);
    if (state == AL_PLAYING)
      alSourceStop(source);

    // delete the source and the buffer
    alDeleteSources(1, &source);
    alDeleteBuffers(1, &buffer_);
    source_ = 0;
    buffer_ = 0;
  }
}

bool Sound::IsSoundLoaded() const {
  return source_ != 0 && buffer_ != 0;
}

void Sound::SetPosition(float x, float y, float z) {
	alSource3f(source_, AL_POSITION, x, y, z);
}

void Sound::Play(bool rewindIfPlaying, bool loop) {
  assert(IsSoundLoaded());

  // set the source's repeating attibute
  const ALuint source = source_;
  alSourcei(source, AL_LOOPING, loop);

  // check if the sound must be played only if it is stopped
  if (rewindIfPlaying) {
    alSourcePlay(source);
  } else {
    // reproduce the sound only if it is not playing
    ALint state = 0;
    alGetSourcei(source, AL_SOURCE_STATE, &state);
    if (state == AL_INITIAL || state == AL_STOPPED)
      alSourcePlay(source);
  }
}
