#include "NativeRootWindow.h"
#include "Log.h"

#include <stdexcept>

//////////////////////////////////////////////////////////////
namespace Dubious {
namespace Utility {

namespace {

EGLint GetConfig( EGLDisplay Display, EGLConfig Config, EGLint Attrib )
{
	EGLint Value;
	eglGetConfigAttrib( Display, Config, Attrib, &Value );
	return Value;
}

void EnumerateConfigs( EGLDisplay Display )
{
	const EGLint Attribs[] = {
			EGL_NONE
	};
	EGLint 		NumConfigs;
	EGLConfig 	Config[100];
	if (eglGetConfigs( Display, Config, 100, &NumConfigs ) != EGL_TRUE ) {
		return;
	}
	LOG_INFO( "Num Configs Returned: " << NumConfigs );
	for (int i=0; i<NumConfigs; ++i) {
		LOG_INFO( "Config " << i );
		EGLint Value;
		eglGetConfigAttrib( Display, Config[i], EGL_DEPTH_SIZE, &Value );
		LOG_INFO( "   Type   : " << GetConfig( Display, Config[i], EGL_SURFACE_TYPE ));
		LOG_INFO( "   Depth  : " << GetConfig( Display, Config[i], EGL_DEPTH_SIZE ));
		LOG_INFO( "   Stencil: " << GetConfig( Display, Config[i], EGL_STENCIL_SIZE ));
		LOG_INFO( "   Red    : " << GetConfig( Display, Config[i], EGL_RED_SIZE ));
		LOG_INFO( "   Green  : " << GetConfig( Display, Config[i], EGL_GREEN_SIZE ));
		LOG_INFO( "   Blue   : " << GetConfig( Display, Config[i], EGL_BLUE_SIZE ));
		LOG_INFO( "   Alpha  : " << GetConfig( Display, Config[i], EGL_ALPHA_SIZE ));

	}
}

}

NativeRootWindow::NativeRootWindow( ANativeWindow* Window )
	: m_Animate( false )
	, m_Display( EGL_NO_DISPLAY )
	, m_Context( EGL_NO_CONTEXT )
	, m_Surface( EGL_NO_SURFACE )
{
	LOG_INFO( "NativeRootWindow Constructor called" );
	try {
		m_Display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
		if (m_Display == EGL_NO_DISPLAY) {
			throw std::runtime_error( "eglGetDisplay failed" );
		}

		if (eglInitialize( m_Display, NULL, NULL ) != EGL_TRUE) {
			throw std::runtime_error( "eglInitialize failed" );
		}

		// Simple config selection code from a native activity sample.  We
		// will just be using the first config returned.  Perhaps in the future
		// I will need to figure out how to select a different one?
		const EGLint Attribs[] = {
				EGL_SURFACE_TYPE,	EGL_WINDOW_BIT,
				EGL_DEPTH_SIZE, 	16,
				EGL_STENCIL_SIZE,	8,
				EGL_BLUE_SIZE, 		8,
				EGL_GREEN_SIZE, 	8,
				EGL_RED_SIZE, 		8,
				EGL_ALPHA_SIZE, 	8,
				EGL_NONE
		};
		EGLint 		NumConfigs;
		EGLConfig 	Config;
//		EnumerateConfigs( m_Display );
		if (eglChooseConfig( m_Display, Attribs, &Config, 1, &NumConfigs ) != EGL_TRUE) {
			throw std::runtime_error( "eglChooseConfig failed" );
		}
		LOG_INFO( "eglChooseConfig returned " << NumConfigs << " configs" );
		if (NumConfigs == 0) {
			throw std::runtime_error( "No Screen Configs found.  Can not run on this device" );
		}

		EGLint 		Format;
		// Taken from NativeActivity sample:
		// EGL_NATIVE_VISUAL_ID is an attribute of the EGLConfig that is
		// guaranteed to be accepted by ANativeWindow_setBuffersGeometry().
		// As soon as we picked a EGLConfig, we can safely reconfigure the
		// ANativeWindow buffers to match, using EGL_NATIVE_VISUAL_ID.
		eglGetConfigAttrib( m_Display, Config, EGL_NATIVE_VISUAL_ID, &Format );
		ANativeWindow_setBuffersGeometry( Window, 0, 0, Format );

		m_Surface = eglCreateWindowSurface( m_Display, Config, Window, NULL );
		m_Context = eglCreateContext( m_Display, Config, EGL_NO_CONTEXT, NULL);

		if (eglMakeCurrent( m_Display, m_Surface, m_Surface, m_Context) == EGL_FALSE ) {
			throw std::runtime_error( "Unable to eglMakeCurrent" );
		}

		EGLint Width, Height;
		eglQuerySurface( m_Display, m_Surface, EGL_WIDTH, &Width );
		eglQuerySurface( m_Display, m_Surface, EGL_HEIGHT, &Height );
		m_Dimensions = Dubious::Math::Size( Width, Height );
	}
	catch (const std::exception& e) {
		LOG_WARN( "Exception caught.  Calling DestroyRootWindow: " << e.what() );
		// Destroy is smart enough to only destroy the parts
		// that were partially created by this function
		Destroy();
		throw;
	}
    LOG_INFO( "Created root window.  Dimensions=" << m_Dimensions );
}

NativeRootWindow::~NativeRootWindow()
{
	try {
		Destroy();
	}
	catch (...) {
	}
}

void NativeRootWindow::Destroy()
{
	LOG_INFO( "Destroy called" );
	// Remember that this function has to be smart enough to handle the cases where some
	// of the memebers have been set up and some have not.  It might be called from
	// constructor when things go bad.
    if (m_Display != EGL_NO_DISPLAY) {
        eglMakeCurrent( m_Display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
        if (m_Context != EGL_NO_CONTEXT) {
            eglDestroyContext( m_Display, m_Context );
        }
        if (m_Surface != EGL_NO_SURFACE) {
            eglDestroySurface( m_Display, m_Surface );
        }
        eglTerminate( m_Display );
    }
    m_Animate = false;
    m_Display = EGL_NO_DISPLAY;
    m_Context = EGL_NO_CONTEXT;
    m_Surface = EGL_NO_SURFACE;
}

void NativeRootWindow::SwapBuffers()
{
    eglSwapBuffers(m_Display, m_Surface);
}


}}
