#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <dlfcn.h>
#include <pthread.h>
//#include <gtk/gtk.h>
#include "adl_api.h"
#include "ls_gtk.h"
#include "ls_pth.h"

//extern void* Main_Memory_Buffer;
extern const char *ADL_Func_Names[LSADL_FUNCS]; 
extern char ADL_Func_Enabled[LSADL_FUNCS];
extern char ADL_Func_Notes[LSADL_FUNCS];
//extern LPAdapterInfo lpAdapterInfo;
//extern LPADLMemoryInfo lpADLMemoryInfo;
struct ADLMemoryInfo lpADLMemoryInfo;
struct AdapterInfo *lpAdapterInfo;
extern int iNumberAdapters;
extern ADLTemperature iTemperature;
extern int iAdapterIndex;
extern struct OverDrive5s od5;

//extern pthread_mutex_t Mutex1;

extern int No_Exit;
//#define LSAD_THREADS 2

// Memory allocation function
void* __stdcall ADL_Main_Memory_Alloc ( int iSize )
{
    void* lpBuffer = malloc ( iSize );
    return lpBuffer;
}




int main(int argc, char **argv){
	void *so_handle = dlopen( "libatiadlxx.so", RTLD_LAZY|RTLD_GLOBAL);
	int num1 = 0;
	int ret_val = 0;

	//pthread_t *Actions_thread_ptrs = (pthread_t *)malloc(sizeof(pthread_t) * LSAD_THREADS );
	//pthread_t Gtk_thread_ptr;
	//pthread_t Refresh_thread_ptr;

	//unsigned int *Actions_t_ids    = (unsigned int *)malloc( sizeof(unsigned int) * LSAD_THREADS );
	//Actions_t_info = (struct Thread_I *)malloc( sizeof(struct Thread_I) * Threads );

	//ret_val = pthread_mutex_init(&Mutex1, NULL);
	//if(ret_val != 0){
	//	printf("Error: pthread_mutex_init returned %d\n", ret_val);
	//	free(Gtk_thread_ptr);
	//	free(Refresh_thread_ptr);
	//	dlclose(so_handle);
	//	exit(1);
	//}

	(void)DL_and_Check(so_handle);

	//void* lpBuffer = malloc(iSize);

	//ADL_Main_Control_Create (ADL_Main_Memory_Alloc, 1) )
	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");
		//free(Gtk_thread_ptr);
		//free(Refresh_thread_ptr);
		//(void)pthread_mutex_destroy(&Mutexe1);
		dlclose(so_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");
		free(Gtk_thread_ptr);
		free(Refresh_thread_ptr);
		(void)pthread_mutex_destroy(&Mutexe1);
		LSADL_Main_Control_Destroy();
		dlclose(so_handle);
		exit(1);
	}


	lpAdapterInfo = malloc(sizeof(struct AdapterInfo)*iNumberAdapters);
	(void)memset((void *)lpAdapterInfo,'\0', sizeof(struct AdapterInfo)*iNumberAdapters);
	//lpADLMemoryInfo = malloc(sizeof(struct ADLMemoryInfo));
	(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(Gtk_thread_ptr);
		free(Refresh_thread_ptr);
		(void)pthread_mutex_destroy(&Mutexe1);
		free(lpAdapterInfo);
		LSADL_Main_Control_Destroy();
		dlclose(so_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(Gtk_thread_ptr);
		free(Refresh_thread_ptr);
		(void)pthread_mutex_destroy(&Mutexe1);
		free(lpAdapterInfo);
		LSADL_Main_Control_Destroy();
		dlclose(so_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(Gtk_thread_ptr);
		free(Refresh_thread_ptr);
		(void)pthread_mutex_destroy(&Mutexe1);
		free(lpAdapterInfo);
		LSADL_Main_Control_Destroy();
		dlclose(so_handle);
		exit(1);
	}

	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);


	gtk_init(&argc, &argv);


	//Refresh_Func();

	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(Gtk_thread_ptr);
        free(Refresh_thread_ptr);
        (void)pthread_mutex_destroy(&Mutexe1);
        free(lpAdapterInfo);
        LSADL_Main_Control_Destroy();
        dlclose(so_handle);
        exit(1);
	}
	//GTK_Func();

	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(Gtk_thread_ptr);
        free(Refresh_thread_ptr);
        (void)pthread_mutex_destroy(&Mutexe1);
        free(lpAdapterInfo);
        LSADL_Main_Control_Destroy();
        dlclose(so_handle);
        exit(1);
	}
	//Refresh_Func();


	if(pthread_join(Gtk_thread_ptr, NULL) != 0){
		printf("Error: pthread_join failed to join Gtk thread!\n");
		printf("\tExiting!\n");
		free(Gtk_thread_ptr);
		free(Refresh_thread_ptr);
		(void)pthread_mutex_destroy(&Mutexe1);
		free(lpAdapterInfo);
		LSADL_Main_Control_Destroy();
		dlclose(so_handle);
		exit(1);
	}

	if(pthread_join(Refresh_thread_ptr, NULL) != 0){
		printf("Error: pthread_join failed to join Refresh thread!\n");
		printf("\tExiting!\n");
		free(Gtk_thread_ptr);
		free(Refresh_thread_ptr);
		(void)pthread_mutex_destroy(&Mutexe1);
		free(lpAdapterInfo);
		LSADL_Main_Control_Destroy();
		dlclose(so_handle);
		exit(1);
	}

	//printf("here 1\n");

	//ADL_Main_Memory_Free(&lpBuffer);

	//Print_Code(LSADL_Main_Control_Destroy());
	LSADL_Main_Control_Destroy();
	(void)pthread_mutex_destroy(&Region_Mutexes[n1]);
	free(Gtk_thread_ptr);
	free(Refresh_thread_ptr);
	//printf("here 2\n");
	free(lpAdapterInfo);
	//ADL_Main_Memory_Free((void **)&lpADLMemoryInfo);
	//ADL_Main_Memory_Free((void **)&lpAdapterInfo);
	//free(lpAdapterInfo);
	//free(lpADLMemoryInfo);
	//printf("here 3\n");
	dlclose(so_handle);
	//free(Main_Memory_Buffer);
	//printf("here 4\n");
	//	Print_Code(LSADL_Main_Control_DESTROY());

	return 0;
}