/*
    lsadl is a frontend/wrapper to the adl_sdk using gtk
    Copyright (C) 2011  Sterling Pickens

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <dlfcn.h>
#include "config.h"
#include "Globals.h"
#ifdef HAVE_PTHREAD_H
#include <pthread.h>
#elif HAVE_PTHREADS_H
#include <pthreads.h>
#endif
#include "adl_api.h"
#include "ls_gtk.h"
#include "ls_pth.h"
#include "ls_gl.h"

extern const char *ADL_Func_Names[LSADL_FUNCS];
extern char ADL_Func_Enabled[LSADL_FUNCS];
extern char ADL_Func_Notes[LSADL_FUNCS];
struct ADLMemoryInfo lpADLMemoryInfo;
struct AdapterInfo *lpAdapterInfo;
extern int iNumberAdapters;
extern ADLTemperature iTemperature;
extern int iAdapterIndex;
extern struct OverDrive5s od5;
extern int No_Exit;
extern pthread_t Gtk_thread_ptr;
extern pthread_t Refresh_thread_ptr;
extern pthread_mutex_t Mutex1;
extern long long total_gmem;

int main(int argc, char **argv){
	printf("\t%s\n\thttp:/", PACKAGE_STRING);
	printf("/%s\n\t%s\n\n", PACKAGE_URL, PACKAGE_BUGREPORT);

	printf("WARNING: This can be Dangerous Software!\n");
	//printf("\tBy using this program you acknowledge:\n");
	//printf("\t\tYour hardware/software can be permanently damaged!\n");
	//printf("\tSelect Quit from the menu if you did not know this!\n");
	printf("\tUse at your own risk!\n");
	void *glso_handle = dlopen( "libGL.so.1", RTLD_LAZY|RTLD_GLOBAL);
	void *so_handle = dlopen( "libatiadlxx.so", RTLD_LAZY|RTLD_GLOBAL);
	int num1 = 0;
	int ret_val = 0;
	No_Exit = 1;

//	GLuint fbo;
//	glGenFramebuffersEXT(1, &fbo);
//	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);

	GLInitWindow(argc, argv);
//glutInit(&argc, argv);
//	    glutInitContextVersion(4, 0);
//	    glutInitContextFlags(GLUT_FORWARD_COMPATIBLE);
//	    glutInitContextProfile(GLUT_CORE_PROFILE);

    //glutInit(&argc,argv);
    //glutInitDisplayMode (GLUT_DOUBLE| GLUT_RGB | GLUT_DEPTH);


//GLXContext glXCreateContext(Display *  dpy,  XVisualInfo *  vis,  GLXContext  shareList,  Bool  direct);

	//Display *  dpy;
	//XVisualInfo *  vis;
	//GLXContext context;

	//context = glXCreateContext(dpy,vis,NULL, TRUE);

	Initialize_GL(glso_handle);
	(void)DL_and_Check(so_handle);

	ret_val = LSADL_Main_Control_Create(ADL_Main_Memory_Alloc, 1);
	if(ret_val != ADL_OK){
		printf("ADL Initialization Error!\n");
		Print_Code(ret_val);
		printf("Exiting!\n");
		dlclose(so_handle);
		dlclose(glso_handle);
		exit(1);
	}

	ret_val = LSADL_Adapter_NumberOfAdapters_Get(&iNumberAdapters);
	if(ret_val != ADL_OK){
		printf("Cannot get the number of adapters!\n");
		Print_Code(ret_val);
		printf("Exiting!\n");
		LSADL_Main_Control_Destroy();
		dlclose(so_handle);
		dlclose(glso_handle);
		exit(1);
	}


	lpAdapterInfo = malloc(sizeof(struct AdapterInfo)*iNumberAdapters);
	(void)memset((void *)lpAdapterInfo,'\0', sizeof(struct AdapterInfo)*iNumberAdapters);
	(void)memset((void *)&lpADLMemoryInfo,'\0', sizeof(struct ADLMemoryInfo));

	ret_val = LSADL_Adapter_AdapterInfo_Get(lpAdapterInfo, sizeof(struct AdapterInfo)*iNumberAdapters);
	if(ret_val != ADL_OK){
		printf("Cannot get the number of adapter info!\n");
		Print_Code(ret_val);
		printf("Exiting!\n");
		free(lpAdapterInfo);
		LSADL_Main_Control_Destroy();
		dlclose(so_handle);
		dlclose(glso_handle);
		exit(1);
	}

	printf("Num Adapters(active and non-active): %d\n", iNumberAdapters);
	iAdapterIndex = lpAdapterInfo[num1].iAdapterIndex;

	ret_val = LSADL_Adapter_MemoryInfo_Get(iAdapterIndex, &lpADLMemoryInfo);
	if(ret_val != ADL_OK){
		printf("Cannot get the number of memory info!\n");
		Print_Code(ret_val);
		printf("Exiting!\n");
		free(lpAdapterInfo);
		LSADL_Main_Control_Destroy();
		dlclose(so_handle);
		dlclose(glso_handle);
		exit(1);
	}
	ret_val = LSADL_OD5_Temperature_Get(iAdapterIndex, 0, &iTemperature);
	if(ret_val != ADL_OK){
		printf("Cannot get the number of od5 temperature!\n");
		Print_Code(ret_val);
		printf("Exiting!\n");
		free(lpAdapterInfo);
		LSADL_Main_Control_Destroy();
		dlclose(so_handle);
		dlclose(glso_handle);
		exit(1);
	}
	total_gmem = lpADLMemoryInfo.iMemorySize;
	printf("Mem Size: %lld\n", lpADLMemoryInfo.iMemorySize);
	printf("Mem Type: %s\n", lpADLMemoryInfo.strMemoryType);
	printf("Mem Bandwidth: %lld\n", lpADLMemoryInfo.iMemoryBandwidth);
	printf("Temp: %d\n", iTemperature.iTemperature);

	if(Perf_Alloc() == FALSE){
		printf("Perf_Alloc: memory allocation error!\n");
		printf("Exiting!\n");
		free(lpAdapterInfo);
		LSADL_Main_Control_Destroy();
		dlclose(so_handle);
		dlclose(glso_handle);
		exit(1);
	}

	g_thread_init(NULL);
	gdk_threads_init();
	gdk_threads_enter();
	gtk_init(&argc, &argv);

	if(pthread_create(&Gtk_thread_ptr, NULL, GTK_Func, NULL) != 0){
		printf("Error: pthread_create failed to launch Gtk thread !\n");
		printf("Exiting!\n");
		free(lpAdapterInfo);
		LSADL_Main_Control_Destroy();
		dlclose(so_handle);
		dlclose(glso_handle);
		exit(1);
	}
	if(pthread_create(&Refresh_thread_ptr, NULL, Refresh_Func, NULL) != 0){
		printf("Error: pthread_create failed to launch Refresh thread !\n");
		printf("Exiting!\n");
		//fixme kill other thread
		free(lpAdapterInfo);
		LSADL_Main_Control_Destroy();
		dlclose(so_handle);
		dlclose(glso_handle);
		exit(1);
	}
	if(pthread_join(Gtk_thread_ptr, NULL) != 0){
		printf("Error: pthread_join failed to join Gtk thread!\n");
		printf("\tExiting!\n");
		free(lpAdapterInfo);
		LSADL_Main_Control_Destroy();
		dlclose(so_handle);
		dlclose(glso_handle);
		exit(1);
	}
	gdk_threads_leave();
	if(pthread_join(Refresh_thread_ptr, NULL) != 0){
		printf("Error: pthread_join failed to join Refresh thread!\n");
		printf("\tExiting!\n");
		free(lpAdapterInfo);
		LSADL_Main_Control_Destroy();
		dlclose(so_handle);
		dlclose(glso_handle);
		exit(1);
	}
	//gdk_threads_leave();
	if(Perf_Dealloc() == FALSE){
		printf("Perf_Delloc: memory allocation error!\n");
	}

	LSADL_Main_Control_Destroy();
	free(lpAdapterInfo);
	dlclose(so_handle);
	dlclose(glso_handle);
	return 0;
}