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

#include "SoundManager.h"
#include "Sound.h"

SoundManager SoundManager::instance_;

SoundManager::SoundManager() : device_(NULL), context_(NULL), defaultDevice_(0) {
}

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

bool SoundManager::Create() {
  // check the manager is not created
  assert(!IsManagerCreated());

  // open the default device and check it was successfully opened
  ALCdevice* const device = alcOpenDevice(NULL);
  if (device == NULL) return false;

  // create a new context for the device without any special attribute, and
  // then check if it was created successfully
  ALCcontext* const context = alcCreateContext(device, NULL);
  if (context == NULL) return false;

  // select the current context and check for any error
  alcMakeContextCurrent(context);
  if (alGetError() != AL_NO_ERROR) return false;

  // the sound manager was created without errors
  device_ = device;
  context_ = context;
  return true;
}

void SoundManager::Destroy() {
  if (IsManagerCreated()) {
    // this is another way to get the desired data
    // ALCcontext* const context = alcGetCurrentContext();
    // ALCdevice* const device = alcGetContextsDevice(context);

    // clear all the sounds from the manager
    UnloadAllSounds();

    // reset the current context and then destroy it
    alcMakeContextCurrent(NULL);
    alcDestroyContext(context_);
    context_ = NULL;

    // close the device and destroy and reset the pointers
    alcCloseDevice(device_);
    device_ = NULL;
  }
}

void SoundManager::UnloadAllSounds() {
  // delete all sounds from the map
  for (std::map<std::string, Sound*>::iterator next = sounds_.begin(),
                                               end = sounds_.end();
                                               next != end; ++next)
    delete next->second;
  sounds_.clear();
}

bool SoundManager::IsManagerCreated() const {
  return device_ != NULL && context_ != NULL;
}

void SoundManager::SetListenerPosition(float posX, float posY, float posZ,
                                       float lookX, float lookY, float lookZ,
                                       float upX, float upY, float upZ) {
  // set the position and the orientation
  const float orientation[6] = {lookX, lookY, lookZ, upX, upY, upZ};
  alListener3f(AL_POSITION, posX, posY, posZ);
  alListenerfv(AL_ORIENTATION, orientation);
}

Sound* SoundManager::GetSound(const char* filename) {
  // check if the sound is already loaded
  std::map<std::string, Sound*>::iterator find = sounds_.find(filename);
  if (find != sounds_.end()) return find->second;

  // create and load a new sound from the file
  std::auto_ptr<Sound> sound(new Sound);
  
  if (!sound->Create(filename)) return NULL;

  // insert the sound in the map and return
  Sound* const newSound = sound.release();
  sounds_.insert(std::pair<std::string, Sound*>(filename, newSound));
  return newSound;
}
