/* Vessel SDL Joystick Config Detector Thing
 * Written by Ethan "flibitijibibo" Lee
 * http://www.flibitijibibo.com/
 *
 * Released under public domain.
 * No warranty implied; use at your own risk.
 *
 * Directions:
 * 1. gcc VesselJoystickDetector.c `sdl-config --libs`
 * 2. ./a.out
 * 3. ?????
 * 4. PROFIT!!!
 */

#include <stdio.h>
#include <SDL/SDL.h>
#include <SDL/SDL_main.h>

int main(int argc, char* argv[])
{
	// Initialize SDL, set up filler video mode.
	SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK);
	SDL_SetVideoMode(1, 1, 32, 0);

	// Open the first joystick.
	SDL_Joystick *theDevice = SDL_JoystickOpen(0);

	// Just in case...
	if (!SDL_JoystickOpened(0))
	{
		printf("Joystick failed to open! Exiting...\n");
		SDL_Quit();
		return 0;
	}

	// Gather our information about the opened joystick.
	int numAxes = SDL_JoystickNumAxes(theDevice);
	int numHats = SDL_JoystickNumHats(theDevice) * 4; // Up/Down/Left/Right
	int numButtons = SDL_JoystickNumButtons(theDevice);

	// Print the joystick information, including the device name.
	printf("Gamepad: %s\n", SDL_JoystickName(0));
	printf("\tNumber of axes: %d\n", numAxes);
	printf("\tNumber of hats: %d\n", numHats);
	printf("\tNumber of buttons: %d\n", numButtons);

	/* The actual joystick query loop. 
	 * Listens for joystick actions and prints the Vessel config value.
	 * Note that repeating the same joystick value does not repeat output!
	 */
	SDL_Event evt;
	int newQuery = 1;
	// We cache these to avoid repeating value prints.
	int cachedAxis = -1;
	int cachedHat = -1, cachedHatDir = -1;
	int cachedButton = -1;
	for (SDL_PollEvent(&evt); evt.type != SDL_QUIT; SDL_PollEvent(&evt))
	{
		// Print message only if we've not already asked!
		if (newQuery == 1)
		{
			newQuery = 0;
			printf("\nAwaiting new joystick input...\n");
		}

		// Don't even bother with other stuff.
		if (	evt.type != SDL_JOYAXISMOTION &&
			evt.type != SDL_JOYHATMOTION &&
			evt.type != SDL_JOYBUTTONDOWN
		) continue;

		// Axis check
		if (evt.type == SDL_JOYAXISMOTION)
		{
			// Check against cache.
			if (evt.jaxis.axis == cachedAxis)
				continue;

			// We do this to avoid excess fighting between axes.
			if (abs(evt.jaxis.value) < 16384)
				continue;

			// And we do this to prevent spam from idle analog
			// buttons (such as Sixaxis) - Thanks John Drinkwater!
			if (abs(evt.jaxis.value) == 32768)
				continue;

			// Print our result.
			printf(
				"\nAxis #%d, Config value: %d\n",
				evt.jaxis.axis,
				evt.jaxis.axis
			);

			// Cache values.
			cachedAxis = evt.jaxis.axis;

			// Now we can ask for a new value.
			newQuery = 1;
		}
		// Hat check
		else if (evt.type == SDL_JOYHATMOTION)
		{
			// Check the direction.
			char* direction;
			int dirOffset;
			if (evt.jhat.value & SDL_HAT_UP)
			{
				direction = "Up";
				dirOffset = 0;
			}
			else if (evt.jhat.value & SDL_HAT_DOWN)
			{
				direction = "Down";
				dirOffset = 1;
			}
			else if (evt.jhat.value & SDL_HAT_LEFT)
			{
				direction = "Left";
				dirOffset = 2;
			}
			else if (evt.jhat.value & SDL_HAT_RIGHT)
			{
				direction = "Right";
				dirOffset = 3;
			}
			else // lolwut
				continue;

			// Check against cache.
			if (	evt.jhat.hat == cachedHat &&
				(evt.jhat.hat + dirOffset) == cachedHatDir
			) continue;

			// Print our result.
			printf(
				"\nHat #%d, Direction %s, Config value: %d\n",
				evt.jhat.hat,
				direction,
				evt.jhat.hat + dirOffset + numAxes
			);

			// Cache values.
			cachedHat = evt.jhat.hat;
			cachedHatDir = evt.jhat.hat + dirOffset;

			// Now we can ask for a new value.
			newQuery = 1;
		}
		// Button check
		else if (evt.type == SDL_JOYBUTTONDOWN)
		{
			// Check against cache.
			if (evt.jbutton.button == cachedButton)
				continue;

			// Print our result.
			printf(
				"\nButton #%d, Config value: %d\n",
				evt.jbutton.button,
				evt.jbutton.button + numAxes + numHats
			);

			// Cache values.
			cachedButton = evt.jbutton.button;

			// Now we can ask for a new value.
			newQuery = 1;
		}
	}

	// Clean up and get out.
	printf("Goodbye!\n");
	SDL_JoystickClose(theDevice);
	SDL_Quit();
	return 0;
}
