/*********************************************************\
         __      __           __  __
        / /     / / _____    / / / / ______   __     __
       / /     / / /___  \  / / / / / ___  | / /    / /
      / /_____/ / _____| / / / / / / /__/ / / /    / /
     / ______  / / ___  / / / / / / _____/ / /    / /
    / /     / / / /__/ / / / / / / |____  / |____/ /
   /_/     /_/ |______/ /_/ /_/  \_____/  \_____  /
                                         ______/ /
            High Level Game Framework   /_______/

  ------------------------------------------------------

  Copyright (c) 2007 - Rodrigo Braz Monteiro.
  This file is subject to the terms of license.txt.

\*********************************************************/

#include "SDL.h"
#include "SDL_opengl.h"
#include "SDL_syswm.h"
#include "video.h"
#include "exception.h"
using namespace Halley;

#pragma comment(lib,"glew32.lib")

#ifdef _MSC_VER
static void ClientResize(HWND hWnd, int nWidth, int nHeight)
{
	RECT rcClient, rcWindow;
	POINT ptDiff;
	GetClientRect(hWnd, &rcClient);
	GetWindowRect(hWnd, &rcWindow);
	ptDiff.x = (rcWindow.right - rcWindow.left) - rcClient.right;
	ptDiff.y = (rcWindow.bottom - rcWindow.top) - rcClient.bottom;
	MoveWindow(hWnd,rcWindow.left, rcWindow.top, nWidth + ptDiff.x, nHeight + ptDiff.y, TRUE);
}
#endif


///////////////
// Constructor
Video::Video()
{
	fullscreen = false;
}

/////////////
// Set video
void Video::SetVideo(bool _fullscreen, Vector2i windowSize, Vector2f virtualSize)
{
	char buffer[1024];
	std::cout << "Initializing video: " << SDL_VideoDriverName(buffer, 1024) << std::endl;

	// Set flags
	int flags = SDL_OPENGL;
	if (_fullscreen) flags |= SDL_FULLSCREEN;
	//else flags |= SDL_NOFRAME;

	// Set GL attributes
	SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 24);
	SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
	SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 1);

	// Calculate virtualSize
	Vector2f p1; // Bottom-left
	Vector2f p2; // Top-right
	float scale;
	if (virtualSize.x == 0 || virtualSize.y == 0) {
		virtualSize = Vector2f(windowSize);
		p2 = virtualSize;
		scale = 1;
	} else {
		float wAR = (float) windowSize.x / (float) windowSize.y;
		float vAR = virtualSize.x / virtualSize.y;
		p2 = virtualSize;
		if (wAR > vAR) {
			// Letterbox on left/right
			float border = (virtualSize.y * wAR - virtualSize.x) * 0.5f;
			p1.x -= border;
			p2.x += border;
			scale = windowSize.y / virtualSize.y;
		} else {
			// Letterbox on top/bottom
			//float border = windowSize.y - windowSize.x / vAR;
			float border = (virtualSize.x / wAR - virtualSize.y) * 0.5f;
			p1.y -= border;
			p2.y += border;
			scale = windowSize.x / virtualSize.x;
		}
	}
	p1 += Vector2f(0.5f, 0.5f);
	p2 += Vector2f(0.5f, 0.5f);

	// Store values
	spVideo vid = Get();
	vid->windowSize = windowSize;
	vid->virtualSize = virtualSize;
	vid->fullscreen = _fullscreen;
	vid->p1 = p1;
	vid->p2 = p2;
	vid->scale = scale;

	// Set video mode
	if (!_fullscreen) SDL_putenv("SDL_VIDEO_CENTERED=center");
	SDL_Surface *result = SDL_SetVideoMode(windowSize.x, windowSize.y, 32, flags);
	if (result == NULL) {
		throw Exception(SDL_GetError());
	}

	// Print OpenGL data
	std::cout << "OpenGL initialized." << std::endl;
	std::cout << "\tVendor: " << glGetString(GL_VENDOR) << std::endl;
	std::cout << "\tRenderer: " << glGetString(GL_RENDERER) << std::endl;
	std::cout << "\tVersion: " << glGetString(GL_VERSION) << std::endl;
	//std::cout << "\tGLSL Version: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << std::endl;
	//std::cout << "\tExtensions: " << glGetString(GL_EXTENSIONS) << std::endl;

	// Initialize GL projection
	glClearColor(0,0,0,0);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(p1.x, p2.x, p1.y, p2.y, -1000, 1000);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	glClear(GL_COLOR_BUFFER_BIT);
	SDL_GL_SwapBuffers();

	// Initialize GLEW
	GLenum err = glewInit();
	if (err != GLEW_OK) {
		throw Exception((char*)(glewGetErrorString(err)));
	}

	// Ensure the right size of window
#ifdef _MSC_VER
	if (!_fullscreen) {
		SDL_SysWMinfo info;
		SDL_VERSION(&info.version);
		if (SDL_GetWMInfo(&info) == 1) {
			ClientResize(info.window, windowSize.x, windowSize.y);
		}
	}
#endif
}


////////////////
// Get instance
spVideo Video::Get()
{
	if (!instance) instance = spVideo(new Video());
	return instance;
}
spVideo Video::instance;



Vector2i Video::GetScreenSize()
{
	const SDL_VideoInfo* info = SDL_GetVideoInfo();
	return Vector2i(info->current_w, info->current_h);
}
