#include "stdafx.h"
#include "DeviceSkia.h"
#include "Exception.h"
#include "RenderMgr.h"
#include "2D/Skia/Surface.h"
#include "2D/Skia/PangoMgr.h"

#ifdef GUI_ENABLE_SKIA

namespace gui {

	SkiaContext::SkiaContext(SkiaDevice *owner, GdkWindow *window, GdkGLContext *context)
		: Context(owner, window, context), device(owner) {

		gdk_gl_context_clear_current();
		gdk_gl_context_make_current(context);

		// We just made ourself current, make sure we note that we did strange things, or
		// "makeCurrent" will misbehave. Since we don't know if creation will succeed at this time,
		// it is safest to set current to null.
		device->current = null;

		// Try to get the current context and create an Interface for it.
		sk_sp<const GrGLInterface> interface;
		GdkDisplay *gdkDisplay = gdk_window_get_display(window);
		if (GDK_IS_WAYLAND_DISPLAY(gdkDisplay)) {
			// Try EGL.
			if (eglGetCurrentContext()) {
				interface = GrGLMakeAssembledGLESInterface(null, &egl_get);
			}
		} else if (GDK_IS_X11_DISPLAY(gdkDisplay)) {
			// Try GLX first, and then EGL. Note: It seems like Gtk does not attempt to use EGL on X11 at the moment.
			if (glXGetCurrentContext()) {
				interface = GrGLMakeAssembledGLESInterface(null, &glx_get);
			} else {
				interface = GrGLMakeAssembledGLESInterface(null, &egl_get);
			}
		}

		if (!interface)
			throw new (runtime::someEngine()) GuiError(S("Failed to initialize OpenGL with Skia."));

		skia = GrDirectContexts::MakeGL(interface);
		if (!skia)
			throw new (runtime::someEngine()) GuiError(S("Failed to initialize OpenGL with Skia."));
	}

	SkiaContext::~SkiaContext() {
		// Make sure we dont encounter errors when Skia flushes its buffers.
		makeCurrent();
		skia = sk_sp<GrDirectContext>();
		clearCurrent();
	}

	void SkiaContext::makeCurrent() {
		// This will try to avoid unneccessary calls to switch GL contexts.
		if (device->current != this) {
			gdk_gl_context_make_current(context);
			device->current = this;
		}
	}

	void SkiaContext::clearCurrent() {
		device->current = null;
	}


	SkiaDevice::SkiaDevice(Engine &e) : GLDevice(e), current(null) {}

	SkiaContext *SkiaDevice::createContext(GdkWindow *window, GdkGLContext *context) {
		return new SkiaContext(this, window, context);
	}

	Surface2D *SkiaDevice::createSurface2D(GtkWidget *widget, Context *context) {
		int scale = gtk_widget_get_scale_factor(widget);
		Size size(gtk_widget_get_allocated_width(widget) * scale,
				gtk_widget_get_allocated_height(widget) * scale);

		if (context->id == 0) {
			context->id = renderMgr(e)->allocId();
		}

		return new SkiaSurface(size, scale, static_cast<SkiaContext *>(context));
	}

	TextMgr *SkiaDevice::createTextMgr() {
		return new SkiaPangoMgr();
	}

}

#endif
