/*
    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"

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;

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 *so_handle = dlopen( "libatiadlxx.so", RTLD_LAZY|RTLD_GLOBAL);
	int num1 = 0;
	int ret_val = 0;
	No_Exit = 1;
	(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);
		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);
		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);
		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);
		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);
		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);

	if(Perf_Alloc() == FALSE){
		printf("Perf_Alloc: memory allocation error!\n");
		printf("Exiting!\n");
		free(lpAdapterInfo);
		LSADL_Main_Control_Destroy();
		dlclose(so_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);
		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);
		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);
		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);
		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);
	return 0;
}