/***************************************************************************
 *   Copyright (C) 2007 by A.J. Tavakoli                                   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#include <string>
#include <stdexcept>
#include <cstdlib>
#include <cstddef>
#include "Sound.h"


bool Sound::initialized = false;
std::vector<Mix_Chunk *> Sound::sounds;


void Sound::initSound() {
  // initialize SDL's video support
  if ( SDL_InitSubSystem(SDL_INIT_AUDIO) == -1 )
    throw std::runtime_error("Sound::initSound(): unable to initialize SDL audio");

  // initialize SDL_mixer
  if ( Mix_OpenAudio(44100, AUDIO_S16SYS, 2, 4096) != 0 )
    throw std::runtime_error("Sound::initSound(): unable to initialize SDL mixer");

  // mark the sound system as initialized
  initialized = true;
}


void Sound::shutdownSound() {
  // free all sounds
  for ( size_t i=0; i < sounds.size(); i++ )
    if ( sounds[i] != NULL )
      Mix_FreeChunk(sounds[i]);

  sounds.clear();

  // shutdown SDL mixer
  Mix_CloseAudio();

  initialized = false;
}


// loads a sound from disk and returns id of sound.
// throws a runtime exception if sound cannot be loaded.
size_t Sound::loadSound(const char *filename) {
  // make sure sound system is initialized
  if ( isInitialized() == false )
    throw std::runtime_error("Sound::loadSound(): sound system has not been "
                             "initialized.");

  // another sanity check... make sure filename is non-NULL
  if ( NULL == filename )
    throw std::runtime_error("Sound::loadSound(): filename is NULL");

  // attempt to load sound from disk
  Mix_Chunk *sound = Mix_LoadWAV(filename);

  // was sound loaded successfully?
  if ( NULL == sound ) {
    std::string errMsg("Sound::loadSound(): error loading ");
    errMsg += std::string(filename);
    throw std::runtime_error(errMsg);
  }

  // sound was loaded successfully, so add it to sound list
  size_t soundID = sounds.size();
  sounds.push_back(sound);

  // return ID of sound
  return soundID;
}


// plays sound with given sound id on channel (-1 picks first free channel).
//  sound is repeated # of times specified by loops (-1 indicates loop forever)
void Sound::playSound(size_t soundID, int channel, int loops) {
  // sanity checks
  if ( soundID >= sounds.size() || channel < -1 || loops < -1 )
    return;

  Mix_Chunk *sound = sounds[soundID];

  if ( sound != NULL )
    Mix_PlayChannel(channel, sound, loops);
}


// stops given channel (-1 stops all channels)
void Sound::stopChannel(int channel) {
  if ( channel < -1 )
    return;

  Mix_HaltChannel(channel);
}


// returns true if the channel is playing, false otherwise
bool Sound::isChannelPlaying(int channel) {
  if ( !isInitialized() || channel < 0 )
    return false;

  return Mix_Playing(channel) != 0;
}
