#include "boring_parts.h"



// TODO : only need OpenGL things, not GTK ones for now
//#include "gtk_includes.h"

#define RETURN_IF_FAIL(expr) do { \
	int res=(expr); \
	if ( res != 0 ) return res; \
} while(0)

// TODO : print streamsdk::getOpenCLErrorCodeStr(res)
#define CL_RETURN_VAL_IF_FAIL(val, expr) do { \
	cl_int res=(expr); \
	if ( res != CL_SUCCESS ) {	\
		std::cerr << "file " << __FILE__ << ": line " << __LINE__ << " (" << __PRETTY_FUNCTION__ \
			<< "): '" << "expr" << "' failed (return code : " << res << ")" << std::endl; \
		return val; \
	} \
} while(0)

int initLibs() {

#ifdef HAS_OPENCL
	RETURN_IF_FAIL( initOpenCL() );
#endif /*HAS_OPENCL*/

	return 0;
}

#ifdef HAS_OPENCL
int initOpenCL() {
	cl_uint id, numPlatforms, numDevices;
	char pbuf[100];
	std::string dTypeStr;
	cl_platform_id *platforms, platform;
	cl_device_id *devices, device;

	// Get platform count
	CL_RETURN_VAL_IF_FAIL(1,
		clGetPlatformIDs(0, NULL, &numPlatforms)
	);
	
	std::cout << "Detected " << numPlatforms << " platform(s)" << std::endl;
	if ( ! ( numPlatforms > 0 ) ) return 2;

	// Allocate room for all platform IDs
	platforms = new cl_platform_id[numPlatforms];

	// Get platform IDs
	CL_RETURN_VAL_IF_FAIL(3,
		clGetPlatformIDs(numPlatforms, platforms, &numPlatforms)
	);

	// Enumerate platforms and grab informations
	for(id=0;id<numPlatforms;id++) {
		CL_RETURN_VAL_IF_FAIL(4,
			clGetPlatformInfo(platforms[id], CL_PLATFORM_VENDOR, sizeof(pbuf), pbuf, NULL)
		);
		std::cout << "Platform " << id << " : " << pbuf << std::endl;
	}

	// Take the first one FIXME : do more !
	platform = platforms[0];

	// Get device count
	CL_RETURN_VAL_IF_FAIL(11,
		clGetDeviceIDs(platform,CL_DEVICE_TYPE_ALL,0,NULL,&numDevices)
	);

	std::cout << "\tDetected " << numDevices << " device(s) for platform " << platform << std::endl;
	if ( ! ( numDevices > 0 ) ) return 12;

	// Allocate room for all devices IDs
	devices = new cl_device_id[numDevices];

	// Get devices IDs
	CL_RETURN_VAL_IF_FAIL(13,
		clGetDeviceIDs(platform,CL_DEVICE_TYPE_ALL,numDevices,devices,&numDevices)
	);

	// Enumerate devices and grab informations
	for(id=0;id<numDevices;id++) {
		cl_device_type dType;

		CL_RETURN_VAL_IF_FAIL(14,
			clGetDeviceInfo(devices[id], CL_DEVICE_TYPE, sizeof(dType), &dType, NULL)
		);

		switch(dType) {
			case CL_DEVICE_TYPE_GPU: dTypeStr="gpu"; break;
			case CL_DEVICE_TYPE_CPU: dTypeStr="cpu"; break;
			default: dTypeStr="(not supported)"; break;
		}
		std::cout << "\tDevice " << id << " type is " << dTypeStr << std::endl;
	}

	// Take the first one FIXME : do more !
	device=devices[0];
	std::cout << "\tWill use device 0 (" << device << ")" << std::endl;

	delete [] devices;
	delete [] platforms;

/*
	if (!clGetGLContextInfoKHR)
	{
		clGetGLContextInfoKHR = (clGetGLContextInfoKHR_fn) clGetExtensionFunctionAddressForPlatform(platform, "clGetGLContextInfoKHR");
		if (!clGetGLContextInfoKHR)
		{
			std::cout << "Failed to query proc address for clGetGLContextInfoKHR";
		}
	}

    std::cout << "glXCreateContextAttribsARB "
      << (void*) glXGetProcAddress((const GLubyte*)"glXCreateContextAttribsARB")
      << std::endl;

    GLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB = (GLXCREATECONTEXTATTRIBSARBPROC)
      glXGetProcAddress((const GLubyte*)"glXCreateContextAttribsARB");

    int attribs[] = {
      GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
      GLX_CONTEXT_MINOR_VERSION_ARB, 0,
      0
    };

    GLXContext ctx = glXCreateContextAttribsARB(displayName, *fbc, 0, true, attribs);
*/


/*
	Ici, le contexte OpenGL du widget MyGTKGLSceneWidget est nécessaire.

	http://developer.gnome.org/gtkglext/stable/gtkglext-gdkglcontext.html
	glXMakeCurrent (displayName, win, ctx);
 */

	GLXContext gGlCtx = glXGetCurrentContext();
	std::cout << "gGlCtx == " << gGlCtx <<  std::endl;
	cl_context_properties cpsGL[] = { CL_CONTEXT_PLATFORM, (cl_context_properties)platform,
		CL_GLX_DISPLAY_KHR, (intptr_t) glXGetCurrentDisplay(),
		CL_GL_CONTEXT_KHR, (intptr_t) gGlCtx, 0
	};

	std::cout << "OpenCL initialization done." << std::endl;
	return 0;
}
#endif /*HAS_OPENCL*/

bool updateGLProjectionMatrix(Glib::RefPtr<Gdk::GL::Context> glCtx, Glib::RefPtr<Gdk::GL::Window> glWin, int width, int height) {

	GLdouble aspect = (GLdouble) width/height;

	// *** OpenGL BEGIN ***
	if (!glWin->gl_begin(glCtx)) return false;

	glViewport(0, 0, width, height);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(60.0, aspect, 0.1, 10.0);
	glMatrixMode(GL_MODELVIEW);

	glWin->gl_end();
	// *** OpenGL END ***

	return true;

}