#include <SDL/SDL.h>
#include <SDL/SDL_audio.h>

#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#include <emscripten/html5.h>
#endif
#include "spiel.hpp"
#include "meanbot15x15.xpm"

template<unsigned short SCRNW, unsigned short SCRNH, unsigned short FPS>
class Shit : public Api
{
	SDL_Surface* screen;

	Gen sndgen;
	Gen * sndgenQe;
	Uint16 sndgenQeIndex;


	int ScrW()
	{
		// detect screen resize and scale accordingly
		return SCRNW*_SCALEW;
	}

	int ScrH()
	{
		return SCRNH*_SCALEH;
	}

	static void audio_callback(void *userdata, Uint8 *_stream, int len) {
        /*
		Shit * shit = (Shit*) userdata;
		time_t nowms = time(NULL);
		time_t nowfq = (nowms*_RATE)/1000;
		for (int i = 0; i < len; i++)
		_stream[i] = shit->sndgen(nowfq+i);
		shit->NextSndGen();
        */
	}

	void NextSndGen()
	{
        /*
		if (this->sndgenQe == 0) return;
		unsigned i = this->sndgenQeIndex;

		if (this->sndgenQe[i] == 0) i = 0;
		this->sndgen = this->sndgenQe[i];
		i++;

		this->sndgenQeIndex = i;
        */
	}
	public:
	Shit()
	{

		//this->sndgenQe = GammeSineWave<_RATE>();
		this->sndgenQe = RickRoll<_RATE>();
		this->sndgenQeIndex = 0;
		this->sndgen = Mute<_RATE>;
		SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO);

		SDL_Surface *screen = SDL_SetVideoMode(this->ScrW(), this->ScrH(), 32, SDL_SWSURFACE);
		this->screen = screen;

		SDL_AudioSpec spec;
		spec.freq = _RATE;
		spec.format = AUDIO_U8;
		spec.channels = 1;
		spec.samples = 8192;
		spec.callback = Shit::audio_callback;
		spec.userdata = this;
		SDL_AudioSpec obtainedSpec;
		SDL_OpenAudio(&spec, &obtainedSpec);
		SDL_PauseAudio(0);

	}
	~Shit()
	{
		this->Gtfo();
	}

	void Delay(int delay)
	{
		#ifdef __EMSCRIPTEN__
		emscripten_sleep(delay);
		#else
		SDL_Delay(delay);
		#endif
	}

	bool Quit()
	{
		SDL_Event e;
		while( SDL_PollEvent( &e ) != 0 )
		{
		    //User requests quit
		    if( e.type == SDL_QUIT )
		    {
			    return true;
		    }
		}
		return false;
	}


	void Gtfo()
	{
		SDL_CloseAudio();
		#ifdef __EMSCRIPTEN__
		emscripten_cancel_main_loop();
		#else
		SDL_Quit();
		#endif
	}
	void Lock()
	{
		if (SDL_MUSTLOCK(this->screen)) SDL_LockSurface(this->screen);
	}
	void Unlock()
	{
		if (SDL_MUSTLOCK(this->screen)) SDL_UnlockSurface(this->screen);
	}
	void Refresh()
	{
		SDL_Flip(this->screen);
	}
	Uint32 Color(Uint8 R, Uint8 G, Uint8 B)
	{
		return SDL_MapRGBA(this->screen->format, R, G, B, 255);
	}

	void Plot(Uint16 x, Uint16 y, Uint32 color)
	{
		Uint16 xx = x*_SCALEW,
		       yy = y*_SCALEH;
		for (int i = 0; i < _SCALEW; i++)
		for (int j = 0; j < _SCALEH; j++)
		if (i == 2 || j == 2) *((Uint32*)this->screen->pixels + ((xx+i) * this->ScrW()) + (yy+j)) = 0;
		else *((Uint32*)this->screen->pixels + ((xx+i) * this->ScrW()) + (yy+j)) = color;
	}
	void SetSeq(Gen * seq)
	{
		SDL_LockAudio();

		this->sndgenQe = seq;
		this->sndgenQeIndex = 0;

		SDL_UnlockAudio();
	}
};

/*
	new asm like interface
	will have a video segment like B800 or A000
	and the main will update the sdl screen with this

	fuck the oop
	all sdl will be handled here
	the rest of the code in pure abstraction
*/

void Delay(int delay)
{
	#ifdef __EMSCRIPTEN__
	emscripten_sleep(delay);
	#else
	SDL_Delay(delay);
	#endif
}

bool Quit()
{
	SDL_Event e;
	while( SDL_PollEvent( &e ) != 0 )
	{
		//User requests quit
		if( e.type == SDL_QUIT )
		{
			return true;
		}
	}
	return false;
}

void RefreshScreen(Uint8 * buffer, SDL_Surface * screen)
{
	Uint32 colors[] = {
		0x00000000,
		0x00FF0000,
		0x0000FF00,
		0x000000FF
	};
	Uint16	scrnw = _SCRNW * _SCALEW,
			scrnh = _SCRNH * _SCALEH;
	if (SDL_MUSTLOCK(screen)) SDL_LockSurface(screen);
	for (int x = 0; x < _SCRNW; x++)
	for (int y = 0; y < _SCRNH; y++)
	{
		Uint16	xx = x*_SCALEW,
				yy = y*_SCALEH;
		Uint8 pixel = buffer[x+(y*_SCRNW)];
		Uint32 color = colors[pixel];
		for (int i = 0; i < _SCALEW; i++)
		for (int j = 0; j < _SCALEH; j++)
		if (i == _SCALEW-1 || j == _SCALEH-1) *((Uint32*)screen->pixels + ((xx+i) * scrnw) + (yy+j)) = 0;
		else *((Uint32*)screen->pixels + ((xx+i) * scrnw) + (yy+j)) = color;
	}
	if (SDL_MUSTLOCK(screen)) SDL_UnlockSurface(screen);
	SDL_Flip(screen);
}

extern "C" int main(int argc, char** argv) {
	printf("hello, world!\n");
	// SDL INIT
		Gen sndgen;
		Gen * sndgenQe;
		Uint16 sndgenQeIndex;
		//sndgenQe = GammeSineWave<_RATE>();
		sndgenQe = RickRoll<_RATE>();
		sndgenQeIndex = 0;
		sndgen = Mute<_RATE>;
		SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO);

		SDL_Surface *screen = SDL_SetVideoMode(_SCRNW * _SCALEW, _SCRNH * _SCALEH, 32, SDL_SWSURFACE);

		SDL_AudioSpec spec;
		spec.freq = _RATE;
		spec.format = AUDIO_U8;
		spec.channels = 1;
		spec.samples = 8192;
		//spec.callback = Shit::audio_callback;
		//spec.userdata = this;
		SDL_AudioSpec obtainedSpec;
		SDL_OpenAudio(&spec, &obtainedSpec);
		SDL_PauseAudio(0);

	// BEGIN	

	Gen gens [] = {
		SquareWave<440,_RATE>,
		SineWave<440,_RATE>,
		0
	};

	//Api * shit = new Shit<_SCRNW,_SCRNH,_FPS>();
	//shit->sndgenQe = gens;
	printf("B==D\n");
/*
	Cunt * cunts[] = {
		new MapRGB(),
		new DrawShit(),
		new EveryFrame(),
		new AudioFrame()
	};
	Cunt * frm = new Cos<Api*>(cunts);

        while( 1 ) frm->Routine(shit);
*/


	// SDL END
		SDL_CloseAudio();
		#ifdef __EMSCRIPTEN__
		emscripten_cancel_main_loop();
		#else
		SDL_Quit();
		#endif
	// GTFO
	return 0;
}

