#include "ls_gl.h"

int use_VBO = 0;
int use_FBO = 0;
int use_TFM = 0;
GLuint g_imageTexture;
GLuint g_fb;


//typedef int(*LSGLGETSTRING)(const char *);
//typedef int(*LSGLGETSTRINGI)(const char *, int *);
//LSGLGETSTRING  lsglGetString;
//LSGLGETSTRINGI lsglGetStringi;

void Print_GL_Error(int error){
	if(error == GL_NO_ERROR)
		printf("GL_NO_ERROR: No error has been recorded.\n");
	else if(error == GL_INVALID_ENUM)
		printf("GL_INVALID_ENUM: An unacceptable value is specified for an enumerated argument.\n");
	else if(error == GL_INVALID_VALUE)
		printf("GL_INVALID_VALUE: A numeric argument is out of range.\n");
	else if(error == GL_INVALID_OPERATION)
		printf("GL_INVALID_OPERATION: The specified operation is not allowed in the current state.\n");
	else if(error == GL_STACK_OVERFLOW)
		printf("GL_STACK_OVERFLOW: This command would cause a stack overflow.\n");
	else if(error == GL_STACK_UNDERFLOW)
		printf("GL_STACK_UNDERFLOW: This command would cause a stack underflow.\n");
	else if(error == GL_OUT_OF_MEMORY)
		printf("GL_OUT_OF_MEMORY: There is not enough memory left to execute the command.\n");
	//GL_TABLE_TOO_LARGE was introduced in GL version 1.2
	else if(error == GL_TABLE_TOO_LARGE)
		printf("GL_TABLE_TOO_LARGE: The specified table exceeds the implementation's maximum supported table size.\n");
	else
		printf("Unknown OpenGL Error Code!\n");
}

static void display(void){
	//while(1){
		sleep(1);
	//}
	glutPostRedisplay();
}
void GLInitWindow(int argc, char* argv[]){
	//glutInitDisplayMode (GLUT_DOUBLE| GLUT_RGB | GLUT_DEPTH);
	//glutInitWindowSize(100, 100);
    //glutInitWindowPosition(0, 0);
    //glutCreateWindow("bla");
    //glutDisplayFunc(display);
    //glutReshapeFunc(reshape);
    //glutIgnoreKeyRepeat(0);
    //glutSpecialFunc(special);
    //glutKeyboardFunc(keyboard);
    //glutMouseFunc(mouse);
    //glutPassiveMotionFunc(mouse_pos);


//GLuint g_imageTexture;
//GLuint g_fb;

    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_ALPHA | GLUT_DEPTH);
    glutInitWindowSize(10, 10);
    glutCreateWindow(argv[0]);

    glGenTextures(1, &g_imageTexture);
    glGenFramebuffersEXT(1, &g_fb);
    glActiveTextureARB(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D, g_imageTexture);

    //glutMainLoop();
}


void Initialize_GL(void *hDLL){
	int have_string = 0;
	int have_stringi = 0;
	int num_exts = 0;
	int num1 = 0;
	int tmp[3] = {0, 0, 0};
	GLubyte *extension = NULL;
	GLubyte *str_tmp = NULL;
	char *ext_tmp = NULL;
	int str_len = 0;
	char *tmp_ptr = NULL;
	//glutInit(&argc,argv);
	//glutInitDisplayMode (GLUT_DOUBLE| GLUT_RGB | GLUT_DEPTH);
	//GLuint fbo; glGenFramebuffersEXT(1, &fbo);
	if( (lsglGetString = (LSGLGETSTRING)glXGetProcAddress("glGetString")) == NULL)
	//if( (lsglGetString = (LSGLGETSTRING)GetProcAddress(hDLL, "glGetString")) == NULL)
		have_string = 0;
	else
		have_string = 1;

	if( (lsglGetStringi = (LSGLGETSTRINGI)glXGetProcAddress("glGetStringi")) == NULL)
	//if( (lsglGetStringi = (LSGLGETSTRINGI)GetProcAddress(hDLL, "glGetStringi")) == NULL)
		have_stringi = 0;
	else
		have_stringi = 1;

	//printf("have_string: %d have_stringi %d\n", have_string, have_stringi);
	//printf("OpenGL Version: %s\n", glGetString(GL_VERSION));
	//if(glGetString(GL_VERSION) != 0)
	//printf("OpenGL Version: %s\n", glGetString(GL_VERSION));


	//return;

	if( (str_tmp = (GLubyte *)glGetString(GL_VERSION)) != 0){
	//str_tmp = (GLubyte *)lsglGetString(GL_VERSION);
		printf("OpenGL Version: %s\n", str_tmp);
	}else{
		Print_GL_Error(glGetError());
	}
	//They do not change from release to release --opengl.org
	str_tmp = (GLubyte *)glGetString(GL_VENDOR);
	if(str_tmp != 0){
		printf("OpenGL Vendor: %s\n", str_tmp);
	}else{
		Print_GL_Error(glGetError());
	}
	str_tmp = (GLubyte *)glGetString(GL_RENDERER);
	if(str_tmp != 0){
		printf("OpenGL Renderer: %s\n", str_tmp);
	}else{
		Print_GL_Error(glGetError());
	}
	//GL_SHADING_LANGUAGE_VERSION is available only if the GL version is 2.0 or greater.
	str_tmp = (GLubyte *)glGetString(GL_SHADING_LANGUAGE_VERSION);
	if(str_tmp != 0){
		printf("OpenGL glsl version: %s\n", str_tmp);
	}else{
		Print_GL_Error(glGetError());
	}
	glGetIntegerv(GL_NUM_EXTENSIONS, (GLint *)&num_exts);
	//Print_GL_Error(glGetError());
	//if(glGetError() != GL_NO_ERROR){ Print_GL_Error(glGetError()); exit(1);}
	printf("Have %d OpenGL extensions\n", num_exts);
	if(have_stringi){
		for(num1=0; num1<num_exts; num1++){
			extension = (GLubyte *)lsglGetStringi(GL_EXTENSIONS, num1);
			if(strstr((const char *)extension,"ARB_vertex_buffer_object") != NULL){
				//we have this 
				//use_VBO = 1;
				tmp[0] = 1;
			}
			if(strstr((const char *)extension,"EXT_framebuffer_object") != NULL){
				tmp[1] = 1;
			}
		}
	}else if(have_string){
		ext_tmp = (char *)lsglGetString(GL_EXTENSIONS);
		//ARB_vertex_buffer_object + ' ' or '\0'
		//str_len = strlen(ext_tmp);
		//24
		//21  strchr(pch+1,'s');
		//for(num1=0; num1<str_len; num1++){
		str_len = strlen("EXT_framebuffer_object");
		tmp_ptr = strstr((const char *)ext_tmp,"EXT_framebuffer_object");
		while(tmp_ptr != NULL){
			if(tmp_ptr[str_len] == ' ' || tmp_ptr[str_len] == '\0'){
				//found
				tmp[0] = 1;
			}
			tmp_ptr = &tmp_ptr[str_len];
			tmp_ptr = strstr((const char *)tmp_ptr,"EXT_framebuffer_object");
		}
		str_len = strlen("ARB_vertex_buffer_object");
		tmp_ptr = strstr((const char *)ext_tmp,"ARB_vertex_buffer_object");
		while(tmp_ptr != NULL){
			if(tmp_ptr[str_len] == ' ' || tmp_ptr[str_len] == '\0'){
				tmp[1] = 1;
			}
			tmp_ptr = &tmp_ptr[str_len];
			tmp_ptr = strstr((const char *)ext_tmp,"ARB_vertex_buffer_object");
		}
	}else{
		//some error
		printf("Could not find glGetString or glGetStringi !\n");
	}
	//just in case
	//shouldn't need these as function should only be called once
	use_VBO = 0;
	use_FBO = 0;
	use_TFM = 0;

	if(tmp[0])
		use_VBO = 1;
	else if(tmp[1])
		use_FBO = 1;
	else
		use_TFM = 1;
}

int GL_Mem_Free(void){
	int params[4];
	if(use_VBO){
#ifdef GL_VBO_FREE_MEMORY_ATI
		glGetIntegerv(GL_VBO_FREE_MEMORY_ATI, (GLint *)params);
#elif defined(VBO_FREE_MEMORY_ATI)
		glGetIntegerv(VBO_FREE_MEMORY_ATI, (GLint *)params);
#else
		glGetIntegerv(0x87FB, (GLint *)params);
#endif
	}else if(use_FBO){
#ifdef GL_RENDERBUFFER_FREE_MEMORY_ATI
		glGetIntegerv(GL_RENDERBUFFER_FREE_MEMORY_ATI, (GLint *)params);
#elif defined(RENDERBUFFER_FREE_MEMORY_ATI)
		glGetIntegerv(RENDERBUFFER_FREE_MEMORY_ATI, (GLint *)params);
#else
		glGetIntegerv(0x87FD, (GLint *)params);
#endif
	}else if(use_TFM){
#ifdef GL_TEXTURE_FREE_MEMORY_ATI
		glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, (GLint *)params);
#elif defined(TEXTURE_FREE_MEMORY_ATI)
		glGetIntegerv(TEXTURE_FREE_MEMORY_ATI, (GLint *)params);
#else
		glGetIntegerv(0x87FC, (GLint *)params);
#endif
	}else{
		//error
		printf("ERROR: Could not locate OpenGL extensions for free mem check!\n");
		return 0;
	}
	return params[0];
}


/*
glGetString(GL_VERSION) 
Alternatively, you can use glGetIntegerv(GL_MAJOR_VERSION, *) and glGetIntegerv(GL_MINOR_VERSION, *). These require GL 3.0 or greater. 

int gl_has_extension(const char *extension){
#ifdef < OpenGL_3.1 bla !
	const unsigned char *supported = glGetString(GL_EXTENSIONS);
#else
	int num_exts = 0;
	glGetIntegerv(GL_NUM_EXTENSIONS, &num_exts);
	const unsigned char *supported = glGetStringi(GL_EXTENSIONS, num_exts);
#endif
	char *ret_val = NULL;

	
}
*/
//int gl_free_mem(){
//	GLint param[4];
	/*
	If ARB_vertex_buffer_object or OpenGL version 1.5 is supportedd, then
    the query for VBO_FREE_MEMORY_ATI is available.

	Dependencies on EXT_framebuffer_object

    If EXT_framebuffer_object is implemented, then the query for
    RENDERBUFFER_FREE_MEMORY_ATI is available.
	*/
/*
#ifdef ARB_vertex_buffer_object
	glGetIntegerv(GL_VBO_FREE_MEMORY_ATI, param);
EXT_framebuffer_object
	RENDERBUFFER_FREE_MEMORY_ATI
else
	TEXTURE_FREE_MEMORY_ATI
*/
/*
        VBO_FREE_MEMORY_ATI                     0x87FB
        TEXTURE_FREE_MEMORY_ATI                 0x87FC
        RENDERBUFFER_FREE_MEMORY_ATI            0x87FD

#ifndef GL_ATI_meminfo
#define GL_VBO_FREE_MEMORY_ATI            0x87FB
#define GL_TEXTURE_FREE_MEMORY_ATI        0x87FC
#define GL_RENDERBUFFER_FREE_MEMORY_ATI   0x87FD
#endif

#ifndef GL_ATI_meminfo
#define GL_ATI_meminfo 1
#endif

      param[0] - total memory free in the pool
      param[1] - largest available free block in the pool
      param[2] - total auxiliary memory free
      param[3] - largest auxiliary free block
*/

//}