#include "cVideo.hpp"

/*** Custom Header Files ***/
#include "cRenderer.hpp"
#include "../UtilityEngine/cUtility.hpp"

using VideoEngine::cVideo;
using VideoEngine::cRenderer;
using UtilityEngine::cUtility;

/*static*/ cVideo* cVideo::sp_inst = nullptr;

cVideo::cVideo()
: m_xPos(100), m_yPos(100), m_width(640), m_height(480), m_colour(32), 
	m_hardwareVideo(false), m_fullscreen(false), m_vsync(false),
	m_videoSettings(SDL_RENDERER_SOFTWARE), mp_window(nullptr),
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
		m_rmask(0xff000000),
		m_gmask(0x00ff0000),
		m_bmask(0x0000ff00),
		m_amask(0x000000ff)
#else
		m_rmask(0x000000ff),
		m_gmask(0x0000ff00),
		m_bmask(0x00ff0000),
		m_amask(0xff000000)
#endif
{}

cVideo::~cVideo()
{
	CleanUp();
}

///Functions
/*static*/ cVideo& cVideo::Inst()
{
	if (sp_inst == nullptr)
		sp_inst = new cVideo();
	return *sp_inst;
}

/*static*/ void cVideo::Delete()
{
	delete sp_inst;
	sp_inst = nullptr;
}

const bool cVideo::Initialize() const
{
	bool rtn = IsInit();

	if (rtn == false) {
		if(SDL_InitSubSystem(SDL_INIT_VIDEO) == 0) {
			cUtility::Inst().Message("Video Initialized.");
			rtn = true;
		} else
			cUtility::Inst().Message("Could not initialize Video. SDL_InitSubSystem():", __AT__, cUtility::eTypeSDL::SDL);
	}

	return rtn;
}

const bool cVideo::Setup()
{
	bool rtn = false;
	CleanUp();
	VideoSettings();

	mp_window = SDL_CreateWindow("Hello World!", 100, 100, m_width, m_height, SDL_WINDOW_SHOWN);
    if (mp_window == nullptr)
		cUtility::Inst().Message("Unable to set Window. SDL_CreateWindow():", __AT__, cUtility::eTypeSDL::SDL);
	else
		rtn = true;
	return rtn;
}

void cVideo::CleanUp()
{
	SDL_DestroyWindow(mp_window);
	mp_window = nullptr;
}

void cVideo::Display()
{
	SDL_RenderPresent(cRenderer::Inst().getRenderer());
}

void cVideo::ScreenShot( const cString& filename, const cString& dir /*= ""*/ )
{
	VideoEngine::cRenderer::Inst().ScreenShot(filename, dir);
}

SDL_Renderer* cVideo::CreateRender()
{
	SDL_Renderer* rtn = nullptr;
	if (mp_window != nullptr)
		rtn = SDL_CreateRenderer(mp_window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE);

	if (rtn == nullptr)
		cUtility::Inst().Message("Unable to set Renderer. SDL_CreateRenderer():", __AT__, cUtility::eTypeSDL::SDL);

	return rtn;
}


void cVideo::VideoSettings()
{
	m_videoSettings = 0;
	
	if (m_hardwareVideo == true)
	{
		m_videoSettings = (m_videoSettings | SDL_RENDERER_ACCELERATED);
		if (m_vsync == true)
			m_videoSettings = (m_videoSettings | SDL_RENDERER_PRESENTVSYNC);
	}
	else
	{
		m_videoSettings = (m_videoSettings | SDL_RENDERER_SOFTWARE);
		m_vsync = false;
	}
	
	if (m_fullscreen == true)
		m_videoSettings = (m_videoSettings | SDL_WINDOW_FULLSCREEN);
}

///Set's
void cVideo::setWidth( const unsigned long int width /*= 640*/ )
{
	m_width = width;
}

void cVideo::setHeight( const unsigned long int height /*= 480*/ )
{
	m_height = height;
}

void cVideo::setColour( const unsigned long int colour /*= 32*/ )
{
	m_colour = colour;
}

void cVideo::setCaption( const cString& caption /*= ""*/ )
{
	if (mp_window != nullptr)
		SDL_SetWindowTitle(mp_window, caption.c_str());
	else
		cUtility::Inst().Message("No window to set caption to.");
}

void cVideo::setHardwareVideo( const bool hardware /*= false*/ )
{
	m_hardwareVideo = hardware;
	VideoSettings();
}

void cVideo::setFullScreen( const bool fullscreen /*= false*/ )
{
	m_fullscreen = fullscreen;
	VideoSettings();
}

void cVideo::setVSync( const bool vsync /*= false*/ )
{
	m_vsync = vsync;
	VideoSettings();
}

void cVideo::setDisplayMode( const SDL_DisplayMode& mode )
{
	if (SDL_SetWindowDisplayMode(mp_window, &mode) < 0)
		cUtility::Inst().Message("Unable to set display mode. SDL_SetWindowDisplayMode()", __AT__, cUtility::eTypeSDL::SDL);
}

///Gets
const bool cVideo::IsInit() const
{
	bool rtn = false;

	if (SDL_WasInit(SDL_INIT_VIDEO) != 0) {
		cUtility::Inst().Message("Video is initialized.");
		rtn = true;
	} else
		cUtility::Inst().Message("Video is not initialized.");

	return rtn;
}

const unsigned long int cVideo::getWidth() const
{
	return m_width;
}

const unsigned long int cVideo::getHeight() const
{
	return m_height;
}

const unsigned long int cVideo::getColour() const
{
	return m_colour;
}

const cString cVideo::getCaption() const
{
	cString rtn = "";
	
	if (mp_window != nullptr)
		rtn = SDL_GetWindowTitle(mp_window);
	else
		cUtility::Inst().Message("No window to get caption from.");

	return rtn;
}

const bool cVideo::getHardwareVideo() const
{
	return m_hardwareVideo;
}

const bool cVideo::getFullScreen() const
{
	return m_fullscreen;
}

const bool cVideo::getVSync() const
{
	return m_vsync;
}

const unsigned long int cVideo::getVideoSettings() const
{
	return m_videoSettings;
}

SDL_Window* cVideo::getWindow()
{
	return mp_window;
}

SDL_DisplayMode cVideo::getDisplayMode() const
{
	SDL_DisplayMode display;

	if (SDL_GetWindowDisplayMode(mp_window, &display) < 0 )
		cUtility::Inst().Message("Could not get display mode. SDL_GetWindowDisplayMode():", __AT__, cUtility::eTypeSDL::SDL);

	return display;
}

const unsigned long int cVideo::getRmask() const
{
	return m_rmask;
}

const unsigned long int cVideo::getGmask() const
{
	return m_gmask;
}

const unsigned long int cVideo::getBmask() const
{
	return m_bmask;
}

const unsigned long int cVideo::getAmask() const
{
	return m_amask;
}
