import java.io.*;
import java.util.ArrayList;

/**
 * Class to access a linux joystick
 * @author goskab
 *
 */
public class Joystick {
	private ArrayList<Integer> axes;
	private ArrayList<Boolean> buttons;
	
	private FileInputStream fd;
	
	/**
	 * opens the proper file, initializes things
	 * note that we don't support reading the number of 
	 * axes/buttons right now, just assume something
	 * @param file
	 */
	Joystick(String file) {
		this.axes = new ArrayList<Integer>();
		this.buttons = new ArrayList<Boolean>();
		try {
			fd = new FileInputStream(file);
		}
		catch (FileNotFoundException e) {
			System.out.println("Joystick not present.");
			fd = null;
			OswaldInterfaceTest oit = new OswaldInterfaceTest(axes);
		}
		EventUpdater up = new EventUpdater();
		up.start();
	}
	
	/**
	 * reads an event and updates the axes/button values
	 * @return true if event was read, false if not
	 */
	public boolean readEvent() throws IOException {
		byte[] bytes = new byte[8];
		int value;
		int type;
		int number;
		if (fd.read(bytes, 0, 8) != 8) //something bad happened, just ignore it
			return false;
		//translate the value bytes... this is basically magic
		value = (((bytes[5] + 128) << 8) + bytes[4] + 128) - ((1 << 15) + 128);
		type = bytes[6]; //type of event
		number = bytes[7]; //number associated with the event
		switch (type) {
			case 0x01: //button
				while (buttons.size() - 1 < number)
					buttons.add(false);
				buttons.set(number, (value == 1));
			break;
			case 0x02: //axis
				while (axes.size() - 1 < number)
					axes.add(0);
				axes.set(number, value);
			break;
			default:
				return false;
		}
		return true;
	}
	
	/**
	 * gets the state of a button
	 * @param number button number to return
	 * @return the state of the button 
	 */
	public synchronized boolean getButton(int number) {
		if (number < buttons.size())
			return buttons.get(number);
		return false;
	}
	
	/**
	 * gets the value of an axis
	 * @param number the axis number
	 * @return the value of the axis
	 */
	public synchronized int getAxis(int number) {
		if (number < axes.size())
			return axes.get(number);
		return 0;
	}
	
	/**
	 * runs the thread that updates the button values and calls the
	 * listeners (if any)
	 * @author goskab
	 */
	private class EventUpdater extends Thread {
		/**
		 * awesome run method
		 */
		public void run() {
			if (fd == null)
				return;
			while(true) {
				try {
					readEvent();
				}
				catch (Exception e) {
					return;
				}
				this.yield();
			}
		}
		
	}
}
