#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <pspkernel.h>
#include <pspaudio.h>
#include <pspaudiolib.h>
#include <psputility_avmodules.h>
#include <string.h>
#include <stdio.h>
#include <malloc.h>
#include <pspthreadman.h>
#include <math.h>
#include <pspiofilemgr.h>
#include "share.h"
#include <oslib/oslib.h>
#include "mikmod.h"
#include "players/mp3playerME.h"
#include "players/oggplayer.h"
struct fileInfo{
    int fileType;
    int defaultCPUClock;
    int needsME;
	float fileSize;
	char layer[12];
	int kbit;
	long instantBitrate;
	long hz;
	char mode[52];
	char emphasis[20];
	long length;
	char strLength[12];
	long frames;
	long framesDecoded;
	int  encapsulatedPictureType;
	int  encapsulatedPictureOffset;
	int  encapsulatedPictureLength;
	char coverArtImageName[264];

    //Tag/comments:
	char album[260];
	char title[260];
	char artist[260];
	char genre[260];
    char year[8];
    char trackNumber[8];
};
static int mp3meplaying = 0;
static int mp3meload = 0;
static struct fileInfo tagInfo;
static int Mp3me_load(lua_State *L)
{
	if (mp3meload == 0){
		LoadMp3(luaL_checkstring(L, 1));
		tagInfo = Taginfo(luaL_checkstring(L, 1));
		mp3meload = 1;
	}
	return 0;
}
static int Mp3me_play(lua_State *L)
{
	if (mp3meplaying == 0){
		PlayMp3();
		mp3meplaying = 1;
	}
	return 0;
}
static int Mp3me_Stop(lua_State *L)
{
	if (mp3meplaying == 1){
		StopMp3();//MP3ME_End();
		mp3meplaying = 0;
		mp3meload = 0;
	}
	return 0;
}
static int Mp3me_EndOfStream(lua_State *L)
{
	lua_pushboolean(L, EOSMp3());
	return 1;
}
static int Mp3me_getTime(lua_State *L)
{
    	char timeString[9];
    	int secs = GetTime();
    	int hh = secs / 3600;
    	int mm = (secs - hh * 3600) / 60;
    	int ss = secs - hh * 3600 - mm * 60;
    	snprintf(timeString, sizeof(timeString), "%2.2i:%2.2i:%2.2i", hh, mm, ss);
    	lua_pushstring(L, timeString);
	return 1;
}
static int Mp3me_percent(lua_State *L)
{
	if (mp3meplaying == 1){
	lua_pushnumber(L, PercentMp3());
	}
	return 1;
}
static int Mp3me_pause(lua_State *L)
{
	if (mp3meplaying == 1){
	PauseMp3();
	}
	return 0;
}
static int Mp3me_songtime(lua_State *L)
{
	lua_pushstring(L, tagInfo.strLength);
	return 1;
}
static int Mp3me_artist(lua_State *L)
{
	lua_pushstring(L, tagInfo.artist);
	return 1;
}
static int Mp3me_title(lua_State *L)
{
	lua_pushstring(L, tagInfo.title);
	return 1;
}
static int Mp3me_album(lua_State *L)
{
	lua_pushstring(L, tagInfo.album);
	return 1;
}
static int Mp3me_genre(lua_State *L)
{
	lua_pushstring(L, tagInfo.genre);
	return 1;
}
static int Mp3me_year(lua_State *L)
{
	lua_pushstring(L, tagInfo.year);
	return 1;
}
static int Mp3me_trackNumber(lua_State *L)
{
	lua_pushstring(L, tagInfo.trackNumber);
	return 1;
}
static int Mp3me_layer(lua_State *L)
{
	lua_pushstring(L, tagInfo.layer);
	return 1;
}
static int Mp3me_kbit(lua_State *L)
{
	lua_pushnumber(L, tagInfo.kbit);
	return 1;
}
static int Mp3me_mode(lua_State *L)
{
	lua_pushstring(L, tagInfo.mode);
	return 1;
}
static int Mp3me_setVolume(lua_State *L)
{
	setvolume(luaL_checkint(L, 1));
	return 0;
}
static int Mp3me_setRLVolume(lua_State *L)
{
	pspAudioSetVolume(1, luaL_checkint(L, 1), luaL_checkint(L, 2));
	return 0;
}
static int Mp3me_rawtime(lua_State *L)
{
	lua_pushnumber(L, GetTime());
	return 1;
}
static int Mp3me_rawsongtime(lua_State *L)
{
	lua_pushnumber(L, rawlength());
	return 1;
}
static int Mp3me_visL(lua_State *L)
{
	int i = luaL_checknumber(L, 1);
	short *Mixing_Buffer;
    Mixing_Buffer = VisMp3();
	float y = ((Mixing_Buffer[(i * 2)] + 32767) * 0.002f);
	lua_pushnumber(L, y);
	return 1;
}
static int Mp3me_visR(lua_State *L)
{
	int i = luaL_checknumber(L, 1);
	short *Mixing_Buffer;
    Mixing_Buffer = VisMp3();
	float y = ((Mixing_Buffer[(i * 2) + 1] + 32767) * 0.002f);
	lua_pushnumber(L, y);
	return 1;
}
static int Mp3me_cart(lua_State *L)
{
	char imgdata[100000];
	int type = tagInfo.encapsulatedPictureType;
	char *path = luaL_checkstring(L, 2);
	if(type>0){
		int ofset = tagInfo.encapsulatedPictureOffset;
		int length = tagInfo.encapsulatedPictureLength;
		char * filename = luaL_checkstring(L, 1);
		SceUID fd = sceIoOpen(filename, PSP_O_RDONLY, 0777);
		sceIoLseek32(fd, ofset, SEEK_SET);
		sceIoRead(fd, imgdata, length);
		sceIoClose(fd);
		SceUID fd2;
		char buffid[256];
		if(type==1){
			sprintf(buffid,"%s.jpg",path);
			fd2 = sceIoOpen(buffid, PSP_O_RDWR|PSP_O_CREAT, 0777);
			sceIoWrite(fd2, imgdata, length);
			sceIoClose(fd2);
		}
		if(type==2){
			sprintf(buffid,"%s.png",path);
			fd2 = sceIoOpen(buffid, PSP_O_RDWR|PSP_O_CREAT, 0777);
			sceIoWrite(fd2, imgdata, length);
			sceIoClose(fd2);
		}
	}
	lua_pushnumber(L, type);
	return 1;
}
static int Mp3me_setpos(lua_State *L)
{
	lua_pushnumber(L, setPos(luaL_checknumber(L, 1)));
	return 1;
}
static int Mp3me_getpos(lua_State *L)
{
	lua_pushnumber(L, getPos());
	return 1;
}
static int Mp3me_info(lua_State *L)
{
	tagInfo = Taginfo2(luaL_checkstring(L, 1));
	return 0;
}
static int Mp3me_loop(lua_State *L)
{
	LoopMp3(luaL_checknumber(L, 1));
	return 0;
}
static const luaL_reg Mp3me_functions[] = {
  {"load",				Mp3me_load},
  {"play",				Mp3me_play},
  {"stop",				Mp3me_Stop},
  {"eos",				Mp3me_EndOfStream},
  {"gettime",				Mp3me_getTime},
  {"percent",				Mp3me_percent},
  {"pause",				Mp3me_pause},
  {"songTime",				Mp3me_songtime},
  {"artist",				Mp3me_artist},
  {"title",				Mp3me_title},
  {"album",				Mp3me_album},
  {"genre",				Mp3me_genre},
  {"year",				Mp3me_year},
  {"trackNumber",				Mp3me_trackNumber},
  {"layer",				Mp3me_layer},
  {"kbit",				Mp3me_kbit},
  {"mode",				Mp3me_mode},
  {"setVolume",				Mp3me_setVolume},
  {"setRLVolume",				Mp3me_setRLVolume},
  {"rawSongTime",				Mp3me_rawsongtime},
  {"rawTime",				Mp3me_rawtime},
  {"visL",				Mp3me_visL},
  {"visR",				Mp3me_visR},
  {"art",				Mp3me_cart},
  {"setPos",				Mp3me_setpos},
  {"getPos",				Mp3me_getpos},
  {"info",				Mp3me_info},
  {"loop",				Mp3me_loop},
  {0, 0}
};
/*
// Utility functions
// ------------------------------

static int lua_setSFXVolume(lua_State *L)
{
	int argc = lua_gettop(L);
	if(argc != 1 ) return luaL_error(L, "Nothing Expected");
	int arg = (int) luaL_checknumber(L, 1);

	setSFXVolume(arg);

	return 0;
}
static int lua_setReverb(lua_State *L)
{
	int argc = lua_gettop(L);
	if(argc != 1 ) return luaL_error(L, "Nothing Expected");
	int arg = (int) luaL_checknumber(L, 1);

	setReverb(arg);

	return 0;
}
static int lua_setPanSep(lua_State *L)
{
	int argc = lua_gettop(L);
	if(argc != 1 ) return luaL_error(L, "Nothing Expected");
	int arg = (int) luaL_checknumber(L, 1);

	setPanSep(arg);

	return 0;
}

static const luaL_reg SoundSystem_functions[] = {
  {"SFXVolume",          		lua_setSFXVolume},
  {"reverb",           			lua_setReverb},
  {"panoramicSeparation", 		lua_setPanSep},
  {0, 0}
};

*/
// The "Sound" userdata object.
// ------------------------------
// note: To implement a usedata object, see 
// http://lua-users.org/wiki/UserDataExample
UserdataStubs(Sound, OSL_SOUND*)

static int Sound_load(lua_State *L) {
	OSL_SOUND* newsound = oslLoadSoundFile(luaL_checkstring(L, 1),OSL_FMT_NONE);
	OSL_SOUND** luaNewsound = pushSound(L);
	*luaNewsound = newsound;
	return 1;
}
static int Sound_play(lua_State *L)
{
	if (lua_gettop(L) != 2){
		oslPlaySound(*toSound(L, 1),1);
	}else{
		oslPlaySound(*toSound(L, 1),luaL_checknumber(L, 2));
	}
	return 0;
}
static int Sound_stop(lua_State *L)
{
	oslStopSound(*toSound(L, 1));
	return 0;
}
static int Sound_pause(lua_State *L)
{
	oslPauseSound(*toSound(L, 1),luaL_checknumber(L, 1));
	return 0;
}
static int Sound_vol(lua_State *L)
{
	OSL_SOUND *sound = *toSound(L, 1);
	sound->volumeLeft = 327.68*luaL_checknumber(L, 2);
	sound->volumeRight = 327.68*luaL_checknumber(L, 3);
	return 0;
}
static int Sound_gc(lua_State *L) // garbage collect
{
	oslDeleteSound(*toSound(L, 1));
	return 0;
}
static int Sound_loop(lua_State *L) // garbage collect
{
	oslSoundLoopFunc(*toSound(L, 1), luaL_checknumber(L, 1));
	return 0;
}

static const luaL_reg Sound_methods[] = {
  {"load",          Sound_load},
  {"play", 			Sound_play},
  {"pause", 			Sound_pause},
  {"stop", 			Sound_stop},
  {"volume", 			Sound_vol},
  {"loop", 			Sound_loop},
  {0, 0}
};
static const luaL_reg Sound_meta[] = {
  {"__gc",       Sound_gc},
  {0, 0}
};

UserdataRegister(Sound, Sound_methods, Sound_meta)
/*static int AudioChannelThread(SceSize args, void *argp)
{
int done = 0;
  while (!done)
  {
    MikMod_Update();
    // We have to sleep here to allow other threads a chance to process.
    // with no sleep this thread will take over when the output is disabled via MikMod_DisableOutput()
    // co-operative threading sucks bigtime...
    sceKernelDelayThread(1);
  }
  return (0);
}
static void Music_init(void)
{
int mikModThreadID = -1;
MikMod_InitThreads();
MikMod_RegisterAllDrivers();
MikMod_RegisterAllLoaders();
md_mode = DMODE_16BITS|DMODE_STEREO|DMODE_SOFT_MUSIC;
md_reverb = 0;
md_pansep = 128;
MikMod_Init("");
MikMod_SetNumVoices(-1, 8);
MikMod_EnableOutput();
if((mikModThreadID = sceKernelCreateThread("MikMod" ,AudioChannelThread,0x12,0x10000,0,NULL)) > 0)
  {
    sceKernelStartThread(mikModThreadID, 0 , NULL);
  }
}

UserdataStubs(Music, MODULE*)
static int Music_load(lua_State *L)
{
	MODULE* newmusic = Player_Load(luaL_checkstring(L, 1), 128, 0);
	MODULE** luaNewmusic = pushMusic(L);
	*luaNewmusic = newmusic;
	return 1;
}
static int Music_play(lua_State *L)
{
	Player_Start(*toMusic(L, 1));
	return 0;
}
static int Music_stop(lua_State *L) // garbage collect
{
	Player_Stop();
	Player_Free(*toMusic(L, 1));
	return 0;
}
static int Music_vol(lua_State *L) // garbage collect
{
	Player_SetVolume(327.68*luaL_checknumber(L, 1));
	return 0;
}
static const luaL_reg Music_methods[] = {
  {"load",          Music_load},
  {"play",		Music_play},
  {"stop",		Music_play},
  {"volume",		Music_vol},
  {0, 0}
};
static const luaL_reg Music_meta[] = {
  {0, 0}
};
UserdataRegister(Music, Music_methods, Music_meta)*/
// The "Voice" userdata object.
// ------------------------------
// note: To implement a usedata object, see 
// http://lua-users.org/wiki/UserDataExample
void sound_init(lua_State *L) {
	Sound_register(L);
	luaL_openlib(L, "Mp3me", Mp3me_functions,0);
}

