int main(int argc, char* argv[])
{
	unsigned char r, g, b;
	struct timespec tms;
	const sensors_chip_name *chip;
	const sensors_feature *feature;
	int nr, subfeat_nr;
	double temp, used_temp, cpu_percent, ram_free_percent;
	FILE *cpufile;
	
	// Open the sensors
	if(sensors_init(NULL) != 0)
	{
		printf("Error initializing the sensors\n");
		return 1;
	}
	atexit(sensors_cleanup);
	

	// Ready to open lights
	// Open the device using the VID, PID
	handle = hid_open(0x1770, 0xff00, NULL);
	if (!handle)
	{
		printf("Unable to open MSI Led device.\n");
 		return 1;
	}
	signal(SIGINT, signal_callback_handler);
	
	while(1)
	{
		nr = 0;
		used_temp = 0;
		while((chip = sensors_get_detected_chips(NULL, &nr)) != NULL)
		{
			subfeat_nr = 0;
			while((feature = sensors_get_features(chip, &subfeat_nr)) != NULL)
			{
				// Uncomment the next printfs to get your device and subdevice ID
				//printf("%s [%d,%d] ", sensors_get_label(chip, feature), nr-1, subfeat_nr-1);
				if(sensors_get_value(chip, subfeat_nr-1, &temp) == 0)
				{
					//printf(" = %.2fºC\n", temp);
				}
				else
				{
					//printf(" = NO DATA\n");
				}
				
				if(nr-1 == DEVICE_ID && subfeat_nr-1 == SUBDEV_ID)
					used_temp = temp;
			}
		}
		
		if(used_temp <= 0)
			r = 0; // No data. Make it full green (zero red)
		else
			r =  CLAMP(0, 0xFF*(used_temp - TEMP_LOW)/(TEMP_HIGH - TEMP_LOW), 0xFF);
		
		g = 0xFF - r; // Fade from red to green
		b = 0;
		
		commit(handle, MODE_NORMAL); // You have to commit first in GE60 (?)
		sendActivateArea(handle, AREA_LEFT, r, g, b);
		
		// Get CPU info

		cpu_percent = 0.0;
		cpufile = fopen("/proc/loadavg", "r");
		if(cpufile)
		{
			fscanf(cpufile, "%lf", &cpu_percent);
			fclose(cpufile);
		}
		cpu_percent /= NUMBER_CPUS;
		r = 0;
		g = 0xFF;
		b = CLAMP(0, 0xFF * cpu_percent, 0xFF);
		//printf("CPU: %.2f\n", cpu_percent * 100.0);
		
		sendActivateArea(handle, AREA_MIDDLE, r, g, b);
		
		// Get RAM info
		ram_free_percent = get_ram_free();

		//printf("RAM: %.2lf\n", ram_used_percent);

		b = CLAMP(0, 0xFF * ram_free_percent, 0xFF);
		r = 0xFF - b;
		g = 0;
		
		sendActivateArea(handle, AREA_RIGHT, r, g, b);

		tms.tv_sec = REFRESH_INTERVAL;
		tms.tv_nsec = 0;
		nanosleep(&tms, NULL);
	}


	// This should never be executed tho...
	hid_close(handle);
	handle = NULL;
	hid_exit();

	return 0;
}
int 
main(int argc, char* argv[]) {

  	/** set default values to std */
	unsigned char cMODE_BREATHING = MODE_BREATHING_STD;
	unsigned char cMODE_WAVE      = MODE_WAVE_STD;
	double dPERIOD_WAVE	      = PERIOD_WAVE_STD;
	double dPERIOD_BREATHING      = PERIOD_BREATHING_STD;

	unsigned char arguments[kSize]; arguments[kIdle] = 0x00;
	colors allowedColors;
	rgb color1, color2, color3, speedColor1, speedColor2, speedColor3; 
	hid_device *handle;

#ifdef WIN32
	UNREFERENCED_PARAMETER(argc);
	UNREFERENCED_PARAMETER(argv);
#endif

	memset(&arguments, UCHAR_MAX, kSize);

	if (argc == 2 && (strcmp(argv[1], PARAM_HELP_SHORT) == 0 || strcmp(argv[1], PARAM_HELP) == 0)) {

		printf("%s", usage);
		return 1;
	} else if (argc == 2 && (strcmp(argv[1], PARAM_VERS_SHORT) == 0 || strcmp(argv[1], PARAM_VERS) == 0)) {

		printf("%s", version);
		return 1;
	} else if (argc < 3) {

		printf("%s", usage);
		return 1;
	} else {

		// Get arguments for program
		for (int x = 1; x < argc; x++) {

			// The params needs to start with "-"
			if (argv[x][0] == '-') {

				if (!argv[x + 1]) {

					printf("Invalid parameter(s). Use --help for more information\n\n");
					return 1;

				} else if (strcmp(argv[x], PARAM_MODE) == 0) {

					if (strcmp(argv[x + 1], VALUE_MODE_DISABLE) == 0) {

						arguments[kMode] = MODE_DISABLE;

					} else if (strcmp(argv[x + 1], VALUE_MODE_NORMAL) == 0) {

						arguments[kMode] = MODE_NORMAL;

					} else if (strcmp(argv[x + 1], VALUE_MODE_GAMING) == 0) {

						arguments[kMode] = MODE_GAMING;

					} else if (strcmp(argv[x + 1], VALUE_MODE_BREATHING) == 0) {

						arguments[kMode] = cMODE_BREATHING;

					} else if (strcmp(argv[x + 1], VALUE_MODE_WAVE) == 0) {

						arguments[kMode] = cMODE_WAVE;
					
					} else if (strcmp(argv[x + 1], VALUE_MODE_DUALCOLOR) == 0) {

						arguments[kMode] = MODE_DUAL_COLOR;
					}

				} else if (strcmp(argv[x], PARAM_COLOR1) == 0) {

					arguments[kColor1] = parseColor(argv[x + 1]);
				
				} else if (strcmp(argv[x], PARAM_COLOR2) == 0) {

					arguments[kColor2] = parseColor(argv[x + 1]);
				
				} else if (strcmp(argv[x], PARAM_COLOR3) == 0) {

					arguments[kColor3] = parseColor(argv[x + 1]);				

				} else if (strcmp(argv[x], PARAM_LEVEL) == 0) {
					
					arguments[kLevel] = convertLevel(argv[x + 1]);

				} else if (strcmp(argv[x], PARAM_IDLE) == 0) {

					arguments[kIdle] = convertIdle(argv[x + 1]);
				}
			}
		}
	}

	// Check required params
	if (arguments[kMode] == UCHAR_MAX) {
		printf("No mode specified. (-mode). Use --help for more information\n\n");
		return 1;
	}

	if ((arguments[kColor1] == UCHAR_MAX && arguments[kMode] != MODE_DISABLE)
		|| (arguments[kColor2] == UCHAR_MAX && arguments[kMode] == MODE_DUAL_COLOR)
		|| ((arguments[kColor2] == UCHAR_MAX || arguments[kColor3] == UCHAR_MAX) && (arguments[kMode] == cMODE_WAVE || arguments[kMode] == cMODE_BREATHING))) {
		printf("No color specified. (-color1). Use --help for more information\n\n");
		return 1;
	}

	if (arguments[kLevel] == UCHAR_MAX && (arguments[kMode] == MODE_NORMAL || arguments[kMode] == MODE_GAMING)) {
		printf("No intensity level specified. (-level). Use --help for more information\n\n");
		return 1;
	}

	// Ready to open lights
	// Open the device using the VID, PID
	handle = hid_open(0x1770, 0xff00, NULL);
	if (!handle) {
		printf("Unable to open MSI Led device.\n");
 		return 1;
	}

	// Check Modes
	if (arguments[kMode] == MODE_DISABLE) {

		// Disable mode = turn off keyboard led
		commit(handle, MODE_DISABLE);

	} else if (arguments[kMode] == MODE_NORMAL) {

		//Gaming mode = full keyboard illumination 
		if (arguments[kColor3] == UCHAR_MAX && arguments[kColor2] == UCHAR_MAX) {

			sendActivateArea(handle, 0x42, AREA_LEFT, arguments[kColor1], arguments[kLevel], 0x00);
			sendActivateArea(handle, 0x42, AREA_MIDDLE, arguments[kColor1], arguments[kLevel], 0x00);
			sendActivateArea(handle, 0x42, AREA_RIGHT, arguments[kColor1], arguments[kLevel], 0x00);

		} else {

			//Normal mode = full keyboard illumination, 3 colors
			sendActivateArea(handle, 0x42, AREA_LEFT, arguments[kColor1], arguments[kLevel], 0x00);
			sendActivateArea(handle, 0x42, AREA_MIDDLE, arguments[kColor2], arguments[kLevel], 0x00);
			sendActivateArea(handle, 0x42, AREA_RIGHT, arguments[kColor3], arguments[kLevel], 0x00);
		}
		commit(handle, MODE_NORMAL);

	} else if (arguments[kMode] == MODE_GAMING) {

		//Gaming mode = only left area on 1 color with a intensity level
		sendActivateArea(handle, 0x42, AREA_LEFT, arguments[kColor1], arguments[kLevel], 0x00);
		commit(handle, MODE_GAMING);

	} else if (arguments[kMode] == cMODE_BREATHING) {

		if (arguments[kIdle] == 1) {
			dPERIOD_BREATHING = PERIOD_BREATHING_IDLE; cMODE_BREATHING = MODE_BREATHING_IDLE;
		}

		//Breathing mode = 3 areas colors blink with a intensity level of 2
		color1.setRGBvalues(identifyRGBcolor(allowedColors, arguments[kColor1])); color2.setRGBvalues(identifyRGBcolor(allowedColors, arguments[kColor2])); color3.setRGBvalues(identifyRGBcolor(allowedColors, arguments[kColor3]));
    		speedColor1.r = computeRampSpeed(color1.r, 0x00, dPERIOD_BREATHING); speedColor1.g = computeRampSpeed(color1.g, 0x00, dPERIOD_BREATHING); speedColor1.b = computeRampSpeed(color1.b, 0x00, dPERIOD_BREATHING);
		speedColor2.r = computeRampSpeed(color2.r, 0x00, dPERIOD_BREATHING); speedColor2.g = computeRampSpeed(color2.g, 0x00, dPERIOD_BREATHING); speedColor2.b = computeRampSpeed(color2.b, 0x00, dPERIOD_BREATHING);
		speedColor3.r = computeRampSpeed(color3.r, 0x00, dPERIOD_BREATHING); speedColor3.g = computeRampSpeed(color3.g, 0x00, dPERIOD_BREATHING); speedColor3.b = computeRampSpeed(color3.b, 0x00, dPERIOD_BREATHING);

		sendActivateArea(handle, 0x43, AREA_LEFT, arguments[kColor1], LEVEL_2, 0x00);
		sendActivateArea(handle, 0x43, AREA_MIDDLE, 0x00, LEVEL_2, 0x00);
		sendActivateArea(handle, 0x43, AREA_RIGHT, speedColor1.r, speedColor1.g, speedColor1.b);
		sendActivateArea(handle, 0x43, AREA_LEFT+3, arguments[kColor2], LEVEL_2, 0x00);
		sendActivateArea(handle, 0x43, AREA_MIDDLE+3, 0x00, LEVEL_2, 0x00);
		sendActivateArea(handle, 0x43, AREA_RIGHT+3, speedColor2.r, speedColor2.g, speedColor2.b);
		sendActivateArea(handle, 0x43, AREA_LEFT+6, arguments[kColor3], LEVEL_2, 0x00);
		sendActivateArea(handle, 0x43, AREA_MIDDLE+6, 0x00, LEVEL_2, 0x00);
		sendActivateArea(handle, 0x43, AREA_RIGHT+6, speedColor3.r, speedColor3.g, speedColor3.b);
		commit(handle, cMODE_BREATHING);

	} else if (arguments[kMode] == cMODE_WAVE) {

		if (arguments[kIdle] == 1) {
			dPERIOD_WAVE = PERIOD_WAVE_IDLE; cMODE_WAVE = MODE_WAVE_IDLE;
		}

		//Wave mode = 3 areas colors blink with a intensity level of 2
		color1.setRGBvalues(identifyRGBcolor(allowedColors, arguments[kColor1])); color2.setRGBvalues(identifyRGBcolor(allowedColors, arguments[kColor2])); color3.setRGBvalues(identifyRGBcolor(allowedColors, arguments[kColor3]));
    		speedColor1.r = computeRampSpeed(color1.r, 0x00, dPERIOD_WAVE); speedColor1.g = computeRampSpeed(color1.g, 0x00, dPERIOD_WAVE); speedColor1.b = computeRampSpeed(color1.b, 0x00, dPERIOD_WAVE);
		speedColor2.r = computeRampSpeed(color2.r, 0x00, dPERIOD_WAVE); speedColor2.g = computeRampSpeed(color2.g, 0x00, dPERIOD_WAVE); speedColor2.b = computeRampSpeed(color2.b, 0x00, dPERIOD_WAVE);
		speedColor3.r = computeRampSpeed(color3.r, 0x00, dPERIOD_WAVE); speedColor3.g = computeRampSpeed(color3.g, 0x00, dPERIOD_WAVE); speedColor3.b = computeRampSpeed(color3.b, 0x00, dPERIOD_WAVE);

		sendActivateArea(handle, 0x43, AREA_LEFT, arguments[kColor1], LEVEL_2, 0x00);
		sendActivateArea(handle, 0x43, AREA_MIDDLE, 0x00, LEVEL_2, 0x00);
		sendActivateArea(handle, 0x43, AREA_RIGHT, speedColor1.r, speedColor1.g, speedColor1.b);
		sendActivateArea(handle, 0x43, AREA_LEFT+3, arguments[kColor2], LEVEL_2, 0x00);
		sendActivateArea(handle, 0x43, AREA_MIDDLE+3, 0x00, LEVEL_2, 0x00);
		sendActivateArea(handle, 0x43, AREA_RIGHT+3, speedColor2.r, speedColor2.g, speedColor2.b);
		sendActivateArea(handle, 0x43, AREA_LEFT+6, arguments[kColor3], LEVEL_2, 0x00);
		sendActivateArea(handle, 0x43, AREA_MIDDLE+6, 0x00, LEVEL_2, 0x00);
		sendActivateArea(handle, 0x43, AREA_RIGHT+6, speedColor3.r, speedColor3.g, speedColor3.b);
		commit(handle, cMODE_WAVE);

	} else if (arguments[kMode] == MODE_DUAL_COLOR) {

		//Dual color mode = 2 areas colors blink with a intensity level of 2
		color1.setRGBvalues(identifyRGBcolor(allowedColors, arguments[kColor1])); color2.setRGBvalues(identifyRGBcolor(allowedColors, arguments[kColor2]));
    		speedColor1.r = computeRampSpeed(color1.r, color2.r, PERIOD_DUAL_COLOR); 
	  	speedColor1.g = computeRampSpeed(color1.g, color2.g, PERIOD_DUAL_COLOR); 
		speedColor1.b = computeRampSpeed(color1.b, color2.b, PERIOD_DUAL_COLOR);

		sendActivateArea(handle, 0x43, AREA_LEFT, arguments[kColor1], filterLevel(arguments[kColor1], LEVEL_2), 0x00);
		sendActivateArea(handle, 0x43, AREA_MIDDLE, arguments[kColor2], filterLevel(arguments[kColor2], LEVEL_2), 0x00);
		sendActivateArea(handle, 0x43, AREA_RIGHT, speedColor1.r, speedColor1.g, speedColor1.b);
		sendActivateArea(handle, 0x43, AREA_LEFT+3, arguments[kColor1], filterLevel(arguments[kColor1], LEVEL_2), 0x00);
		sendActivateArea(handle, 0x43, AREA_MIDDLE+3, arguments[kColor2], filterLevel(arguments[kColor2], LEVEL_2), 0x00);
		sendActivateArea(handle, 0x43, AREA_RIGHT+3, speedColor1.r, speedColor1.g, speedColor1.b);
		sendActivateArea(handle, 0x43, AREA_LEFT+6, arguments[kColor1], filterLevel(arguments[kColor1], LEVEL_2), 0x00);
		sendActivateArea(handle, 0x43, AREA_MIDDLE+6, arguments[kColor2], filterLevel(arguments[kColor2], LEVEL_2), 0x00);
		sendActivateArea(handle, 0x43, AREA_RIGHT+6, speedColor1.r, speedColor1.g, speedColor1.b);
		commit(handle, MODE_DUAL_COLOR);
	}

	// close actual HID handler
	hid_close(handle);

	// Free static HIDAPI objects. 
	hid_exit();

#ifdef WIN32
	system("pause");
#endif

	return 0;
}