#include "Salamander.h"
#include "SDLVisualManager.h"

#include "SDLInclude.h"
#include "SDLBlendMapping.h"

namespace Salamander
{

defineUniqueId(SDLVisualManager);
SDLVisualManager::SDLVisualManager()
{
	window_ = NULL;
}

SDLVisualManager::~SDLVisualManager()
{
}

bool SDLVisualManager::startup()
{
	// Video context
    if (SDL_Init(SDL_INIT_VIDEO) != 0)
	{
        fileio().error("Could not create video context");
        return false;
    }

	// Double buffer
    SDL_GL_SetAttribute(SDL_GL_RED_SIZE,     1);
    SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE,   1);
    SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE,    1);
    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);

	// Rendering window
	Vec2 resolution = screen().getResolution();
	window_ = SDL_SetVideoMode(int(resolution.x_), int(resolution.y_), 32, SDL_OPENGL);

    if (!window_)
    {
        fileio().error("Could not create window");
        return NULL;
    }

    SDL_WM_SetCaption("Salamander", "");
    //SDL_WM_SetCaption — Sets the window title and icon name.
    //SDL_WM_SetIcon — Sets the icon for the display window.
    //SDL_WM_IconifyWindow — Iconify/Minimise the window.
    //SDL_WM_ToggleFullScreen — Toggles fullscreen mode.
    //SDL_WM_GrabInput — Grabs mouse and keyboard input.

	// Create the OpenGL context
	glEnable(GL_BLEND);
	glEnable(GL_TEXTURE_2D);
	glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // TODO
    glClearColor(255, 255, 255, 0);
    glViewport(0, 0, int(resolution.x_), int(resolution.y_));
    glClear(GL_COLOR_BUFFER_BIT);

	glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0, resolution.x_, resolution.y_, 0, -1, 1);

	glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    // loaded fine
    return true;
}

bool SDLVisualManager::shutdown()
{
	// Free the rendering window
	SDL_FreeSurface(window_);

	return true;
}

void SDLVisualManager::preRender()
{
	// clear
	glClear(GL_COLOR_BUFFER_BIT);
}

void SDLVisualManager::render(const Visual& visual)
{
	// TODO : Visuals can reference same data instances - all sprites ref same colours but different positions
	// compiled into display lists somewhere

	// Pull per-vertex properties from the underlying geometry.
	const Stream* coordinateStream = visual.getStream(StreamCoordinates::TypeId);
	const Stream* colourStream = visual.getStream(StreamColour::TypeId);
	const Stream* vertexStream = visual.getStream(StreamVertex::TypeId);

	// If we don't have any vertices, don't bother drawing anything.
	if(!vertexStream || !vertexStream->size())
		return;

	// Pull full-mesh properties from the visual.
	const Mat2& transform = visual.getTransform();
	const Colour& colour = visual.getColour();
	const BlendMode& blendMode = visual.getBlendMode();

	// TODO : Texture
	if(visual.getTexture())
	{
		glBindTexture(GL_TEXTURE_2D, visual.getTexture()->boundTexture_);
	}
	else
	{
		// TODO probably should be included in above statement where boundTexture_ is null - why doesn't this work?
		glBindTexture(GL_TEXTURE_2D, 0);
	}

	// Apply properties.
	glPushMatrix();

	glColor4d(colour.x_, colour.y_, colour.z_, colour.w_);
	glTranslated(transform.getTranslation().x_, transform.getTranslation().y_, 0.0);
	glRotated(transform.getRotation() * RADIANS_TO_DEGREES, 0.0, 0.0, 1.0);
	glScaled(transform.getScale().x_, transform.getScale().y_, 1.0f);

	//glBlendFunc(SDLBlendMapping(blendMode.sourceMode_),
	//			SDLBlendMapping(blendMode.destinationMode_));

	// Draw all points in the stream, and any properties that have been set up for them.
	glBegin(GL_TRIANGLE_STRIP);
	for(unsigned int i = 0; i < vertexStream->size(); i++)
	{
		if(coordinateStream)
			glTexCoord2fv(coordinateStream->get(i));
		
		if(colourStream)
			glColor4fv(colourStream->get(i));

		// We know this stream exists, so we don't have to check.
		glVertex3fv(vertexStream->get(i));
	}

	// Finish drawing and restore the previous state.
    glEnd();
	glPopMatrix();
}

void SDLVisualManager::postRender()
{
	// update the screen
	SDL_GL_SwapBuffers();
}

}