#include "Audio.h"
#include <FK/Error.h>
#include <FK/Model.h>

#include <iostream>
#include <vector>

#ifdef __BIG_ENDIAN__
const int _ENDIAN = 1;
#else
const int _ENDIAN = 0;
#endif

using namespace std;

static fk_IDAdmin			idAdmin(0);
static bool					initStatus = false;

fk_Model *fk_AudioBase::listenerCamera = NULL;


fk_AudioBase::fk_AudioBase(void)
{
	queueSize = FK_OV_DEFAULT_QUEUE_SIZE;
	format = AL_FORMAT_STEREO16;
	rate = 0;
	source_id = -1;
	source = 99999;
	gain = 1.0;
	loopMode = false;
	loopStartTime = 0.0;
	loopEndTime = -1.0;
	init();

	return;
}

fk_AudioBase::~fk_AudioBase()
{
	if(source_id != -1) idAdmin.EraseID(source_id);
	if(idAdmin.GetIDNum() != 0) return;

	if(initStatus) {
		if(!alutExit()) {
			cerr << alutGetErrorString(alutGetError()) << endl;
		}
		initStatus = false;
	}
}

bool fk_AudioBase::init(void)
{
	if(initStatus == false) {
		if(!alutInit(NULL, NULL)) {
			cerr << alutGetErrorString(alutGetError()) << endl;
			return false;
		}
	}
	initStatus = true;

	return true;
}

bool fk_AudioBase::getInit(void)
{
	return initStatus;
}

void fk_AudioBase::CreateID(void)
{
	source_id = idAdmin.CreateID();
	alGenSources(1, &source);
	alSourcef(source, AL_GAIN, ALfloat(gain));
	alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE);
	return;
}

void fk_AudioBase::EraseID(void)
{
	idAdmin.EraseID(source_id);
	source_id = -1;
	return;
}

void fk_AudioBase::setGain(double argGain)
{
	if(argGain < -0.00001 || argGain > 1.00001) return;
	gain = argGain;
	if(source_id != -1) {
		alSourcef(source, AL_GAIN, ALfloat(gain));
	}
	return;
}

double fk_AudioBase::getGain(void)
{
	return gain;
}


void fk_AudioBase::setQueueSize(int argSize)
{
	if(argSize < 1) return;
	queueSize = argSize;
	return;
}

int fk_AudioBase::getQueueSize(void)
{
	return queueSize;
}

void fk_AudioBase::setLoopMode(bool argMode)
{
	loopMode = argMode;
	return;
}

bool fk_AudioBase::getLoopMode(void)
{
	return loopMode;
}

void fk_AudioBase::setLoopArea(double argST, double argED)
{
	loopStartTime = argST;
	loopEndTime = argED;
	return;
}

double fk_AudioBase::getLoopStartTime(void)
{
	return loopStartTime;
}

double fk_AudioBase::getLoopEndTime(void)
{
	return loopEndTime;
}

void fk_AudioBase::MakeOVInfo(OggVorbis_File *argVF)
{
	vorbis_info		*info = NULL;

	info = ov_info(argVF, -1);
	if(info->channels == 1) {
		format = AL_FORMAT_MONO16;
	} else {
		format = AL_FORMAT_STEREO16;
	}
	rate = info->rate;

	return;
}

void fk_AudioBase::sleep(double argTime)
{
	alutSleep(float(argTime));
	return;
}

void fk_AudioBase::pause(void)
{
	ALint		status;

	if(source_id == -1) return;
	alGetSourcei(source, AL_SOURCE_STATE, &status);
	if(status == AL_PLAYING) {
		alSourcePause(source);
	}
	return;
}

void fk_AudioBase::setListenerModel(fk_Model *argModel)
{
	listenerCamera = argModel;
}

void fk_AudioBase::setListenerModel(fk_Model &argModel)
{
	listenerCamera = &argModel;
}

fk_Model * fk_AudioBase::getListenerModel(void)
{
	return listenerCamera;
}

void fk_AudioBase::UpdateListener(void)
{
	static fk_Vector	camPos, camVec, camUpvec;
	static ALfloat		orient[6];

	if(listenerCamera != NULL) {
		camPos = listenerCamera->getPosition();
		camVec = listenerCamera->getVec();
		camUpvec = listenerCamera->getUpvec();
		orient[0] = (float)camVec.x;	orient[1] = (float)camVec.y;	orient[2] = (float)camVec.z;
		orient[3] = (float)camUpvec.x;	orient[4] = (float)camUpvec.y;	orient[5] = (float)camUpvec.z;
		alListener3f(AL_POSITION, (float)camPos.x, (float)camPos.y, (float)camPos.z); 
		alListenerfv(AL_ORIENTATION, orient); 
	}

	return;
}
