/*
Copyright (c) 2000-2001 Olivier Dagenais

This software is provided 'as-is', without any express or implied warranty. In
no event will the authors be held liable for any damages arising from the use
of this software.

Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:

1. The origin of this software must not be misrepresented; you must not claim
that you wrote the original software. If you use this software in a product,
an acknowledgment in the product documentation would be appreciated but is not
required.

2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.

3. This notice may not be removed or altered from any source distribution.
*/

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

#ifdef WIN32
#include <windows.h>
#endif
#include "SDL.h"
#include "SDL_mixer.h"
#include "SDL_config.h"
#include "GopherCore.h"


// arguments:
// {useOpenGL} {library} {function} [arg1 [arg2..]]
int main ( int argc, char * argv [ ] )
{
	unsigned long howFar = 0;
	DemoStruct actualDemo;
	SDL_Config_Struct config;
	SDL_Surface * screen;
	void * libraryHandle;
	void * gopher_Quit;
	PARAM allParams[16];
	PARAM oneParam[1];

	try
	{
		// Check number of arguments
		if ( argc < 5 ) {
			fprintf ( stderr, "Not enough arguments:  Feed me, Seymore!\n" );
			fprintf ( stderr, "Usage:\n" );
			fprintf ( stderr, "  GopherTester {useOpenGL} {library} {function} [arg1 [arg2..]]\n" );
			fprintf ( stderr, "Example:\n" );
			fprintf ( stderr, "  GopherTester 1 Rabbit.DLL Triangle 42 69 0\n\n" );
			throw 0;
		}

		// TODO:  check validity of arguments

		// assign args to an array
		for ( int c = 0, d = 4; d < argc; c++, d++ ) {
			allParams[c] = atoi ( argv[d] );
		}

		// Initialize SDL by reading options from ".\SDL.ini"
		SDL_Config_DefaultConfig ( &config );
		config.subSystems = SDL_INIT_TIMER | SDL_INIT_VIDEO;
		if ( SDL_Config_LoadConfig ( "SDL.ini", &config ) < 0 )
		{
			throw 0;
		}
		howFar = 1;

		actualDemo.useOpenGL = ( 1 == atoi ( argv[1] ) );
		if ( actualDemo.useOpenGL )
		{
			//config.videoFlags |= SDL_OPENGLBLIT;
			config.videoFlags |= SDL_OPENGL;
		}
		if ( ( screen = SDL_Config_Init ( &config ) ) == NULL )
		{
			throw 0;
		}
		howFar = 2;

		// Create the inputSurfaces and the outputSurfaces
		actualDemo.numInputSurfaces = 30;
		actualDemo.numOutputSurfaces = 2;
		if ( createSurfaces ( actualDemo, config, screen ) < 0 )
		{
			throw 0;
		}
		howFar = 3;

		// Load the library
		if ( ( libraryHandle = SDL_LoadObject ( argv[2] ) ) == NULL )
		{
			fprintf ( stderr, "Couldn't load library '%s'!\n", argv[2] );
			return ( -1 );
		}

		// Load the function pointers
		void * gopher_Init;
		if ( ( gopher_Init = SDL_LoadFunction ( libraryHandle, "Gopher_Init" ) ) == NULL )
		{
			fprintf ( stderr, "Couldn't load function 'Gopher_Init' from library '%s'!\n", argv[2] );
			return ( -1 );
		}

		if ( ( gopher_Quit = SDL_LoadFunction ( libraryHandle, "Gopher_Quit" ) ) == NULL )
		{
			fprintf ( stderr, "Couldn't load function 'Gopher_Quit' from library '%s'!\n", argv[2] );
			return ( -1 );
		}

		void * gopher_BeginNewFrame;
		if ( ( gopher_BeginNewFrame = SDL_LoadFunction ( libraryHandle, "Gopher_BeginNewFrame" ) ) == NULL )
		{
			fprintf ( stderr, "Couldn't load function 'Gopher_BeginNewFrame' from library '%s'!\n", argv[2] );
			return ( -1 );
		}

		void * function;
		if ( ( function = SDL_LoadFunction ( libraryHandle, argv[3] ) ) == NULL )
		{
			fprintf ( stderr, "Couldn't load function '%s' from library '%s'!\n", argv[3], argv[2] );
			return ( -1 );
		}
		howFar = 4;


		// Call Gopher_Init, then Gopher_BeginNewFrame
		if ( !execute ( gopher_Init, 0, NULL ) ) {
			throw;
		}
		howFar = 5;

		oneParam[0] = 0;
		if ( !execute ( gopher_BeginNewFrame, 1, oneParam ) ) {
			throw;
		}
		howFar = 6;


		
		bool done = false;
			while ( !done ) {
			if ( !execute ( function, c - 1, allParams ) ) {
				throw;
			}
		
			// Show it on screen
			if ( actualDemo.useOpenGL )
			{
				SDL_GL_SwapBuffers ( );
			}
			else {
				SDL_BlitSurface ( actualDemo.outputSurfaces[0], NULL, screen, NULL );
				SDL_Flip ( screen );
			}

			// Wait for someone to hit escape or close the window.
			done = checkUserInput ( );
		}
		howFar = 7;
	}
	catch ( ... )
	{
		fprintf ( stderr, "Something went horribly wrong.  Stopped at step '%d'.\n", howFar );
		SDL_Delay ( 1000 );
	}


	switch ( howFar )
	{
		case 7:
		case 6:
		case 5:
			// call Gopher_Quit
			execute ( gopher_Quit, 0, NULL );
		case 4:
			// free library
			SDL_UnloadObject ( libraryHandle );
		case 3:
			// destroy surfaces
			destroySurfaces ( actualDemo );
		case 2:
		case 1:
			break;
	}

	if ( 7 == howFar )
	{
		return ( 0 );
	}
	else
	{
		return ( 1 );
	}
}


