#include <iostream>
#include <string>
#include <SDL.h>
#include <SDL_image.h>
#include <GL/glew.h>

#include "Desktoplauncher.h"
#include "DarkRP2D.h"
#include "Utility.h"

using namespace std;

static SDL_Window *gWindow = NULL;
static SDL_GLContext glcontext;
static bool gameQuit = false;

void dispose();
bool initSDL();

int main(int argc, char *argv[])
{
	//Init SDL_Window, SDL_Surface, SDL_Renderer
	if (!initSDL())
	{
		dispose();
		return 1;
	}

	//While application is running
	DarkRP2D resA(gWindow);
	resA.create();
	unsigned int lastTime = SDL_GetTicks(), currentTime, elapsedTime;
	while (!gameQuit)
	{
		currentTime = SDL_GetTicks();
		elapsedTime = currentTime - lastTime;
		lastTime = currentTime;
		resA.loop(elapsedTime);
	}

	dispose();
	return 0;
}

void Game::exit()
{
	gameQuit = true;
}

namespace Game
{
float DDPI, HDPI, VDPI;
}

bool initSDL()
{
	int result = SetProcessDPIAware(); // NEEDED or SDL_GetDisplayDPI returns wrong numbers
	cout << "Result: " << result << endl;
	//Init SDL
	if (SDL_Init(SDL_INIT_VIDEO) < 0)
	{
		cout << "SDL could not initialize! SDL_Error: " << SDL_GetError() << endl;
		return false;
	}
	//Init Window
	uint32_t WindowFlags = SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_OPENGL;
	gWindow = SDL_CreateWindow("SDL TEST", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, Game::SCREEN_WIDTH, Game::SCREEN_HEIGHT, WindowFlags);
	if (gWindow == NULL)
	{
		cout << "Window could not be created! SDL_Error: " << SDL_GetError() << endl;
		return false;
	}
	//Read in Display DPI
	int returnDisplayDPI = SDL_GetDisplayDPI(SDL_GetWindowDisplayIndex(gWindow), &Game::DDPI, &Game::HDPI, &Game::VDPI);
	if (returnDisplayDPI != 0)
	{
		cout << "DisplayDPI cannot be loaded! SDL_ERROR: " << SDL_GetError() << endl;
	}
	cout << "DPI: DDPI: " << Game::DDPI << " HDPI: " << Game::HDPI << " VPDI: " << Game::VDPI << endl;
	//Mask deprectated functions
	SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
#ifndef NDEBUG
	SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG);
#endif
	//Init OpenGL Renderer
	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
	glcontext = SDL_GL_CreateContext(gWindow);
	if (glcontext == NULL)
	{
		cout << "Could not create OpenGL Context: " << SDL_GetError() << endl;
		return false;
	}
	//Init GLEW
	glewExperimental = GL_TRUE;
	GLenum err = glewInit();
	if (GLEW_OK != err)
	{
		cout << "Init of Glew failed: " << glewGetErrorString(err) << endl;
		return false;
	}
//Init debug callback function
#ifndef NDEBUG
	if (GLEW_ARB_debug_output)
	{
		Utility::printInfo(Utility::GLEW, "Supporting ARB debug output!");
	}
	if (GLEW_AMD_debug_output)
	{
		Utility::printInfo(Utility::GLEW, "Supporting AMD debug output!");
	}
	if (GLEW_KHR_debug)
	{
		Utility::printInfo(Utility::GLEW, "Supporting KHR debug output!");
	}

	if (glDebugMessageCallback)
	{
		glEnable(GL_DEBUG_OUTPUT);
		Utility::printInfo(Utility::OpenGL, "Register OpenGL debug callback");
		glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
		glDebugMessageCallback(Utility::openglCallbackFunction, nullptr);
		GLuint unusedIds = 0;
		glDebugMessageControl(GL_DONT_CARE,
							  GL_DONT_CARE,
							  GL_DONT_CARE,
							  0,
							  &unusedIds,
							  true);
	}
	else
	{
		Utility::printWarning(Utility::OpenGL, "glDebugMessageCallback not available");
	}
#endif
	return true;
}

void dispose()
{
	SDL_GL_DeleteContext(glcontext);
	SDL_DestroyWindow(gWindow);
	SDL_Quit();
}
