
#include <iostream>
#include <Spectre/Display/Display.h>
#include <Spectre/Display/GLContext.h>
#include <Spectre/Graphics/Image.h>
#include <Platform/PlatformDisplay.h>

namespace sp {

#define CAPTION_DEFAULT "Spectre"
#define ICON_DEFAULT "./assets/app.ico"

Display::Display()
{
	m_caption = CAPTION_DEFAULT;
	m_fmode = WINDOWED;

	m_context = GLContext::create();
	m_impl = PlatformDisplay::make(this);
}

Display::~Display()
{
	delete m_context;
	delete m_impl;
}

bool Display::create(DisplayDescription description)
{
	destroy();

	if (!m_impl->create(description)) {
		return false;
	}

	if (!m_context->create(m_impl)) {
		return false;
	}

	init();

	m_description = description;

	return true;
}

void Display::init()
{
	m_impl->setCaption(m_caption);

	setIcon(ICON_DEFAULT);

	activate(true);

	enableVSync(false);
	showCursor(true);
}

void Display::destroy()
{
	m_context->destroy();

	m_impl->destroy();
}

void Display::setCaption(const std::string& caption)
{
	m_caption = caption;
	m_impl->setCaption(m_caption);
}

const std::string& Display::getCaption() const
{
	return m_caption;
}

void Display::setIcon(const std::string& filename)
{
	Image img;

	if (img.loadFromFile(filename)) {
		setIcon(img.getWidth(), img.getHeight(), img.getPixels());
	}
}

void Display::setIcon(unsigned int width, unsigned int height, const uint8_t *pixels)
{
	m_impl->setIcon(width, height, pixels);
}

void Display::setSize(unsigned int width, unsigned int height)
{
	m_description.mode.width = width;
	m_description.mode.height = height;

	m_impl->setSize(width, height);
}

void Display::setVideoMode(Mode mode)
{
	if (m_fmode == mode) {
		return;
	}

	if (mode != FULLSCREEN) {
		m_impl->exitFullscreen();
	}

	// Cache window position when entering fullscreen.
	if (mode == FULLSCREEN || mode == WINDOWEDFULLSCREEN) {
		m_cachePos = m_impl->getPosition();
	}

	// True fullscreen
	if (mode == FULLSCREEN) {
		m_impl->enterFullscreen(m_description.mode);
	}
	// Windowed fullscreen.
	else if (mode == WINDOWEDFULLSCREEN) {
		DisplayMode desktop = DisplayMode::getDesktopMode();
		m_impl->setDecoration(DisplayDecorate::Empty);
		m_impl->setSize(desktop.width, desktop.height);
		m_impl->setPosition(0, 0);
	}
	// Window mode.
	else {
		// Set stored decoration.
		m_impl->setDecoration(m_description.decoration);

		// Restore size and position.
		m_impl->setSize(m_description.mode.width, m_description.mode.height);
		m_impl->setPosition(m_cachePos.x, m_cachePos.y);
	}

	m_fmode = mode;
}

enum Display::Mode Display::getVideoMode() const
{
	return m_fmode;
}

void Display::setVisible(bool visible)
{
	m_impl->setVisible(visible);
}

void Display::showCursor(bool value)
{
	m_impl->showCursor(value);
}

void Display::grabCursor(bool value)
{
	m_impl->grabCursor(value);
}

bool Display::activate(bool value)
{
	if (value) {
		return m_context->activate();
	}
	return m_context->deactivate();
}

bool Display::enableVSync(bool value)
{
	return m_context->setSwapInterval(value ? 1 : 0);
}

void Display::swapBuffers()
{
	if (activate(true)) {
		m_context->swapBuffers();
	}
}

void Display::onReshape(int width, int height)
{
	// Resize context if the windows resizes.
	m_context->setSize(width, height);
}

} // namespace sp
