/*===============================================================================================
 Native C code for accessing FMOD libraries.
 peter "pdx" drescher
 www.twittering.com

===============================================================================================*/

#include <jni.h>
#include <android/log.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include "../../fmodexapi/fmodeventapi/api/inc/fmod_event.h"
#include "../../fmodexapi/api/inc/fmod_errors.h"
#include "LSAland.h"

FMOD_EVENTSYSTEM *lEventSystem  = 0;
FMOD_MUSICSYSTEM *lMusicSystem  = 0;
FMOD_EVENT *lEvent = 0;
FMOD_MUSICPROMPT *landLevelMusic   = 0;
int lSegmentStart = 0;
int lCurrentKey = 0;
bool changeBGFlag = false;
bool frogEatenFlag = false;
bool keyChanged = false;
bool landAudioActive = false;
enum {KEY_OF_Cmin   = 0,
	  KEY_OF_Bbmin  = 1,
	  KEY_OF_Ab     = 2,
	  KEY_OF_Fsmin  = 3,
	  KEY_OF_Emaq   = 4,
	  KEY_OF_Dmin   = 5};

#define CHECK_RESULT(x) \
{ \
	FMOD_RESULT _result = x; \
	if (_result != FMOD_OK) \
	{ \
		__android_log_print(ANDROID_LOG_ERROR, "fmod", "FMOD error! (%d) %s\n%s:%d", _result, FMOD_ErrorString(_result), __FILE__, __LINE__); \
		exit(-1); \
	} \
}

void checkFrog()
{
	if (frogEatenFlag && keyChanged) {
		changeBGFlag = true;
		frogEatenFlag = false;
		keyChanged = false;
	}
}

FMOD_RESULT F_CALLBACK lSegmentCallback(FMOD_MUSIC_CALLBACKTYPE type, void *param1, void *param2, void *userdata)
{
	FMOD_RESULT result = FMOD_OK;
	FMOD_BOOL active;

	switch (type)
	{
		case FMOD_MUSIC_CALLBACKTYPE_SEGMENT_START:
		{
			lSegmentStart = (uintptr_t)param1;
			if (lSegmentStart == MUSICSEGMENT_LSALAND_LANDLEVEL_THEME_CBOND)  {
				lCurrentKey = KEY_OF_Cmin;
				checkFrog();
			} else
			if (lSegmentStart == MUSICSEGMENT_LSALAND_LANDLEVEL_THEME_BBBOURNE)  {
				lCurrentKey = KEY_OF_Bbmin;
				checkFrog();
			} else
			if (lSegmentStart == MUSICSEGMENT_LSALAND_LANDLEVEL_THEME_ABSAMBA)  {
				lCurrentKey = KEY_OF_Ab;
				checkFrog();
			} else
			if (lSegmentStart == MUSICSEGMENT_LSALAND_LANDLEVEL_THEME_FSSALSA)  {
				lCurrentKey = KEY_OF_Fsmin;
				checkFrog();
			} else
			if (lSegmentStart == MUSICSEGMENT_LSALAND_LANDLEVEL_THEME_EMAQQAM)  {
				lCurrentKey = KEY_OF_Emaq;
				checkFrog();
			} else
			if (lSegmentStart == MUSICSEGMENT_LSALAND_LANDLEVEL_THEME_DROCK)  {
				lCurrentKey = KEY_OF_Dmin;
				checkFrog();
			} else
			if (lSegmentStart == MUSICSEGMENT_LSALAND_LANDLEVEL_THEME_C2BB  ||
				lSegmentStart == MUSICSEGMENT_LSALAND_LANDLEVEL_THEME_BB2AB ||
				lSegmentStart == MUSICSEGMENT_LSALAND_LANDLEVEL_THEME_AB2FS ||
				lSegmentStart == MUSICSEGMENT_LSALAND_LANDLEVEL_THEME_FS2E  ||
				lSegmentStart == MUSICSEGMENT_LSALAND_LANDLEVEL_THEME_E2D 	||
				lSegmentStart == MUSICSEGMENT_LSALAND_LANDLEVEL_THEME_D2C) {
				result = FMOD_MusicSystem_SetParameterValue(lMusicSystem, MUSICPARAM_LSALAND_MODULATE, 0);
				CHECK_RESULT(result);
				keyChanged = true;
			}
			break;
		}
	}
	return FMOD_OK;
}

void Java_com_twittering_landseaair_FMODaudio_cInitLandAudio(JNIEnv *env, jobject thiz, jstring mediaPath)
{
	FMOD_RESULT result = FMOD_OK;
	time_t loadTime;
	lEventSystem = (FMOD_EVENTSYSTEM*) getEventSystem();
	lMusicSystem = (FMOD_MUSICSYSTEM*) getMusicSystem();
    const char *_mediaPath = (*env)->GetStringUTFChars (env, mediaPath, 0);

	//__android_log_print(ANDROID_LOG_ERROR, "fmod", "set media path= %s", _mediaPath);
	result = FMOD_EventSystem_SetMediaPath(lEventSystem, _mediaPath);
	CHECK_RESULT(result);
    (*env)->ReleaseStringUTFChars (env, mediaPath, _mediaPath);

	//__android_log_print(ANDROID_LOG_ERROR, "fmod", "load eventsystem");
	result = FMOD_EventSystem_Load(lEventSystem, "LSAland.fev", 0, 0);
	CHECK_RESULT(result);

	//__android_log_print(ANDROID_LOG_ERROR, "fmod", "get initial events");
	result = FMOD_EventSystem_GetEvent(lEventSystem, "LSAland/landLevelFX/rats", FMOD_EVENT_DEFAULT, &lEvent);
	CHECK_RESULT(result);
	result = FMOD_EventSystem_GetEvent(lEventSystem, "LSAland/landLevelFX/frogs", FMOD_EVENT_DEFAULT, &lEvent);
	CHECK_RESULT(result);

	loadTime = time (NULL);
	//__android_log_print(ANDROID_LOG_ERROR, "fmod", "load samples");
	result = FMOD_MusicSystem_LoadSoundData(lMusicSystem, FMOD_EVENT_RESOURCE_SAMPLES, FMOD_EVENT_DEFAULT);
	CHECK_RESULT(result);
	loadTime -= time(NULL);
	//__android_log_print(ANDROID_LOG_ERROR, "fmod", "load time = %ld", -loadTime);

	//__android_log_print(ANDROID_LOG_ERROR, "fmod", "prepare cues");
	result = FMOD_MusicSystem_PrepareCue(lMusicSystem, MUSICCUE_LSALAND_LANDLEVEL,  &landLevelMusic);
	CHECK_RESULT(result);

	//__android_log_print(ANDROID_LOG_ERROR, "fmod", "setCallback");
	result = FMOD_MusicSystem_SetCallback(lMusicSystem, lSegmentCallback, 0);
	CHECK_RESULT(result);

	//__android_log_print(ANDROID_LOG_ERROR, "fmod", "begin land level music");
	result = FMOD_MusicPrompt_Begin(landLevelMusic);
	CHECK_RESULT(result);

	changeBGFlag = false;
	frogEatenFlag = false;
	keyChanged = false;
	landAudioActive = true;
}

void Java_com_twittering_landseaair_FMODaudio_cStopLandAudio(JNIEnv *env, jobject thiz)
{
	FMOD_RESULT result = FMOD_OK;
	result = FMOD_MusicSystem_Reset(lMusicSystem);
	CHECK_RESULT(result);
	result = FMOD_EventSystem_Unload(lEventSystem);
	CHECK_RESULT(result);
	landAudioActive = false;
}

float getLPitch(int pitchDx)
{	//							0     1   2   3   4   5   6   //index
	const float CminScale[]  = {-4,  -2, -1,  1,  3,  6,  8};
	const float BbminScale[] = {-6,  -4, -3, -1,  1,  4,  6};
	const float AbMajScale[] = {-8,  -6, -4, -3, -1,  2,  4};
	const float FsminScale[] = {-10, -8, -7, -5, -3,  0,  2};
	const float EmaqScale[]  = { 0,  -7,  5,  0,  5,  7,  0};
	const float DminScale[]  = {-2,   0,  1,  3,  5,  8, 10};
	float pitch;

	switch(lCurrentKey) {
		case KEY_OF_Cmin:
			pitch = CminScale[pitchDx];
			break;
		case KEY_OF_Bbmin:
			pitch = BbminScale[pitchDx];
			break;
		case KEY_OF_Ab:
			pitch = AbMajScale[pitchDx];
			break;
		case KEY_OF_Fsmin:
			pitch = FsminScale[pitchDx];
			break;
		case KEY_OF_Emaq:
			pitch = EmaqScale[pitchDx];
			break;
		case KEY_OF_Dmin:
			pitch = DminScale[pitchDx];
			break;
		default:
			__android_log_print(ANDROID_LOG_ERROR, "landAudio", "getLPitch bad mojo");
			break;
	}
	return pitch;
}


void Java_com_twittering_landseaair_FMODaudio_cPlayRatSound(JNIEnv *env, jobject thiz)
{
	FMOD_RESULT result = FMOD_OK;
	FMOD_EVENT_PITCHUNITS units = FMOD_EVENT_PITCHUNITS_SEMITONES;
	int firstPitchDx;
	int secondPitchDx;

	if (landAudioActive) {
		// first, play random note from the current scale
		firstPitchDx = rand() % 7;
		result = FMOD_EventSystem_GetEvent(lEventSystem, "LSAland/landLevelFX/rats", FMOD_EVENT_DEFAULT, &lEvent);
		CHECK_RESULT(result);
		result = FMOD_Event_SetPitch(lEvent, getLPitch(firstPitchDx), units);
		CHECK_RESULT(result);
		result = FMOD_Event_Start(lEvent);
		CHECK_RESULT(result);

		// then, play a second note in a consonant interval (except for maqam)
		if (lCurrentKey == KEY_OF_Emaq) {
			secondPitchDx = firstPitchDx;
		} else {
			switch (firstPitchDx) {
				case 0: secondPitchDx = 2; break;
				case 1: secondPitchDx = 3; break;
				case 2: secondPitchDx = 4; break;
				case 3: secondPitchDx = 1; break;
				case 4: secondPitchDx = 5; break;
				case 5: secondPitchDx = 1; break;
				case 6: secondPitchDx = 2; break;
			}
			result = FMOD_EventSystem_GetEvent(lEventSystem, "LSAland/landLevelFX/rats", FMOD_EVENT_DEFAULT, &lEvent);
			CHECK_RESULT(result);
			result = FMOD_Event_SetPitch(lEvent, getLPitch(secondPitchDx), units);
			CHECK_RESULT(result);
			result = FMOD_Event_Start(lEvent);
			CHECK_RESULT(result);
		}
	}
}

void Java_com_twittering_landseaair_FMODaudio_cPlayFrogSound(JNIEnv *env, jobject thiz)
{
	FMOD_RESULT result = FMOD_OK;

	if (landAudioActive) {
		// froglix samples will play sequentially, one for each key ...
		result = FMOD_EventSystem_GetEvent(lEventSystem, "LSAland/landLevelFX/frogs", FMOD_EVENT_DEFAULT, &lEvent);
		CHECK_RESULT(result);
		result = FMOD_Event_Start(lEvent);
		CHECK_RESULT(result);

		// set flag and paramater to modulate to next key
		result = FMOD_MusicSystem_SetParameterValue(lMusicSystem, MUSICPARAM_LSALAND_MODULATE, 1.0f);
		CHECK_RESULT(result);
		frogEatenFlag = true;
	}
}

jboolean Java_com_twittering_landseaair_FMODaudio_cCheckBGflag(JNIEnv *env, jobject thiz)
{
	if (changeBGFlag) {
		changeBGFlag = false;
		return true;
	} else {
		return false;
	}
}
