#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>

#include "fmod.h"
#include "fmod_errors.h"

//typedef int (*song_gettime) (lua_State *L)

FMOD_CHANNEL *channel;
FMOD_SOUND *song;
FMOD_SYSTEM *fmod_system; 

int res_w = 0;
int res_h = 0;
int res_override = 0;

static int song_getmillis(lua_State *L) {
	unsigned int songtime = 0;
	FMOD_Channel_GetPosition(channel, &songtime, FMOD_TIMEUNIT_MS);
	lua_pushnumber(L, songtime);
	return 1;
}

static int song_getorder(lua_State *L) {
	unsigned int songorder = 0;
	FMOD_Channel_GetPosition(channel, &songorder, FMOD_TIMEUNIT_MODORDER);
	lua_pushnumber(L, songorder);
	return 1;
}

static int song_getrow(lua_State *L) {
	unsigned int songrow = 0;
	FMOD_Channel_GetPosition(channel, &songrow, FMOD_TIMEUNIT_MODROW);
	lua_pushnumber(L, songrow);
	return 1;
}

static int song_getlength(lua_State* L) {
	unsigned int lenms;
	FMOD_Sound_GetLength(song, &lenms, FMOD_TIMEUNIT_MS);
	lua_pushnumber(L, lenms);
	return 1;
}

static int song_pause(lua_State *L) {
	int action = lua_tonumber(L, 1);
	switch(action) {
		case 0:
			FMOD_Channel_SetPaused(channel, 1);
			break;
		case 1:
			FMOD_Channel_SetPaused(channel, 0);
			break;
	}
	return 0;
}

static int song_play(lua_State *L) {
	FMOD_RESULT result = FMOD_System_PlaySound(fmod_system, 0, song, 0, &channel);
	if (result != FMOD_OK) {
		printf("FMOD error! (%d) %s\n", result, FMOD_ErrorString(result));
	}
	return 0;
}

static int song_seek(lua_State *L) {
	int action = lua_tonumber(L, 1);
	unsigned int songtime = 0;
	FMOD_Channel_GetPosition(channel, &songtime, FMOD_TIMEUNIT_MS);
 
	switch(action) {
		case 0:
			FMOD_Channel_SetPosition(channel, songtime-250, FMOD_TIMEUNIT_MS);
			break;
		case 1:
			FMOD_Channel_SetPosition(channel, songtime+250, FMOD_TIMEUNIT_MS);
			break;
		case 2:
			FMOD_Channel_SetPosition(channel, songtime+1000, FMOD_TIMEUNIT_MS);
			break;
		case 3:
			FMOD_Channel_SetPosition(channel, songtime-1000, FMOD_TIMEUNIT_MS);
			break;
		case 4:
			FMOD_Channel_SetPosition(channel, songtime-10, FMOD_TIMEUNIT_MS);
			break;
		case 5:
			FMOD_Channel_SetPosition(channel, songtime+10, FMOD_TIMEUNIT_MS);
			break;

	}
	return 0;
}

static int song_spectrum(lua_State *L) {
	//const float* spectrum = FSOUND_DSP_GetSpectrum();
	float* spectrum = (float*)malloc(sizeof(float)*512); 
	int i,table;

	FMOD_System_GetSpectrum(fmod_system, spectrum, 512, 0, FMOD_DSP_FFT_WINDOW_TRIANGLE);

	lua_createtable(L, 512, 0);
	table = lua_gettop(L);
	for (i = 0; i < 512; i++) {
		lua_pushnumber(L, spectrum[i]);
		lua_rawseti(L, table, i);
	}
	
	free(spectrum);
	
	return 1;
}

static int song_getfmodversion(lua_State *L) {
	unsigned int version;
	FMOD_System_GetVersion(fmod_system, &version);
	lua_pushnumber(L, version);
	return 1;
}

static int demo_getresolution(lua_State *L) {
	unsigned int w;
	unsigned int h;
	unsigned int override;

	override = res_override;
	w = res_w;
	h = res_h;

	lua_pushnumber(L, res_override);
	lua_pushnumber(L, w);
	lua_pushnumber(L, h);

	return 3;
}

int main(int argc, char *argv[]) {
	int error;
	FMOD_RESULT result;

	if (argc >= 3) {
		res_w = atoi(argv[1]);
		res_h = atoi(argv[2]);
		res_override = 1;
	}

	result = FMOD_System_Create(&fmod_system);          // Create the main system object. 
	if (result != FMOD_OK) { 
		printf("FMOD error! (%d) %s\n", result, FMOD_ErrorString(result)); 
		return -1;
	}

	lua_State *L = lua_open();
	luaL_openlibs(L);

	lua_register(L, "song_getmillis", song_getmillis);
	lua_register(L, "song_getorder", song_getorder);
	lua_register(L, "song_getrow", song_getrow);
	lua_register(L, "song_pause", song_pause);
	lua_register(L, "song_play", song_play);
	lua_register(L, "song_seek", song_seek);
	lua_register(L, "song_spectrum", song_spectrum);
	lua_register(L, "song_getfmodversion", song_getfmodversion);
	lua_register(L, "song_getlength", song_getlength);
	lua_register(L, "demo_getresolution", demo_getresolution);
	

	result = FMOD_System_Init(fmod_system, 100, FMOD_INIT_NORMAL, 0);        // Initialize FMOD. 
	if (result != FMOD_OK) { 
		printf("FMOD error! (%d) %s\n", result, FMOD_ErrorString(result)); 
		return -1;
	}
	
	result = FMOD_System_CreateSound(fmod_system, "song", FMOD_SOFTWARE, 0, &song);
	if (result != FMOD_OK) {
		printf("Could not load soundtrack from file song\n");
		return -1;
	}

	error = luaL_loadfile(L, "script.lua") || lua_pcall(L, 0, 0, 0);

	if (error) {
		fprintf(stderr, "%s\n", lua_tostring(L, -1));
		lua_pop(L, 1);  /* pop error message from the stack */
	}

	lua_close(L);

	FMOD_System_Release(fmod_system);
	
	return 0;
}
