package puck;

import com.buglabs.application.IServiceProvider;
import com.buglabs.application.MainApplicationThread;

import java.awt.BorderLayout;
import java.awt.Frame;
import java.io.IOException;
import java.util.*;

import com.buglabs.bug.accelerometer.pub.AccelerometerConfiguration;
import com.buglabs.bug.accelerometer.pub.AccelerometerSample;
import com.buglabs.bug.accelerometer.pub.AccelerometerSampleStream;
import com.buglabs.bug.accelerometer.pub.IAccelerometerControl;
import com.buglabs.bug.accelerometer.pub.IAccelerometerSampleFeed;
import com.buglabs.bug.module.lcd.pub.IModuleDisplay;

public class PuckApp extends MainApplicationThread {
	private IServiceProvider serviceProvider;
	private boolean ran;
	private PuckPanel puckPanel;
	private Frame frame;

	public PuckApp(IServiceProvider serviceProvider) {
		this.serviceProvider = serviceProvider;
		ran = false;
	}

	/**
	 * Informs the caller whether this thread ran.
n.	 */
	public boolean getRan() {
		return ran;
	}

	private void ran() {
		ran = true;
	}

	public void run() {
		createUI();
		dumpAccelerometerConfig();
		setupAccelerometer();
		
		
		
		AccelerometerSampleStream is = createAccelerometerInputStream();
		System.out.println("Got accelerometer sample stream: "+is);
		dumpAccelerometerConfig();
		// These values were obtained empirically, with the Bug
		// sitting on my desk; ymmv.
		// orientations are relative to the BUGview being in slot 1 (the top-right one)
		
		//final float xMax = 0.70F; // left
		//final float xMin = -1.29F; // right
		final float xZero = -0.30F;
				
		//final float yMax = 0.84F; // top
		//final float yMin = -1.10F; // bottom
		final float yZero = -0.17F;
		
		final float xFix = xZero * -1;
		final float yFix = yZero * -1;
		
		/// arbitrary multiplier to make the puck move at a decent rate
		final int speedMultiplier = 30;
		
		// correction multipliers so that left tilt moves left and not right,
		// and forward tilt moves up, not down. Again, orientations are
		// from the BUGview in slot 1's perspective, not the perspective
		// of the BUGbase (so tilting toward the top of the BUGview display is
		// actually tilting to the left of the BUGbase).
		final int xAxisMultiplier = 1;
		final int yAxisMultiplier = 1;
		
		try {
			while (!isInterrupted() && !tearDownRequested) {
				final AccelerometerSample sample = is.readSample();
				if (sample != null) {
					final int yMove = (int) ((sample.getAccelerationX() + xFix) * speedMultiplier) * xAxisMultiplier;
					final int xMove = (int) ((sample.getAccelerationY() + yFix) * speedMultiplier) * yAxisMultiplier;
					puckPanel.movePuck(xMove, yMove);
				}
			}
			is.close();
		} 
			
		catch (IOException e) {
			e.printStackTrace();
		} finally {
			destroyUI();
			ran();
			System.out.println("Puck stopped; closing accelerometer sample stream");	
			}
		}
	

	
	private void setupAccelerometer() {
		// THIS DOES NOT WORK IF cfg.setDelayMode((byte) 0); is set
		// see http://bugcommunity.com/bugzilla/show_bug.cgi?id=288
		IAccelerometerControl c = (IAccelerometerControl) serviceProvider.getService(IAccelerometerControl.class);
		AccelerometerConfiguration cfg = c.getConfiguration();
		
		// use a sample rate of ~1ms (actually 1.024ms)
		// see http://bugcommunity.com/wiki/images/b/b3/AccelerometerAPI_v1_1.pdf
		//cfg.setDelayMode((byte) 0);
		cfg.setDelayResolution((byte) 3);
		cfg.setDelay((short) 500);
		cfg.setReadQueueSize(1);
		cfg.setReadQueueThreshold(1);
		c.setConfiguration(cfg);
	}		

	private void dumpAccelerometerConfig() {
		IAccelerometerControl c = (IAccelerometerControl) serviceProvider.getService(IAccelerometerControl.class);
		AccelerometerConfiguration cfg = c.getConfiguration();
		System.out.println("Config:");
		System.out.println("read_queue_size="+cfg.getReadQueueSize());
		System.out.println("read_queue_threshold="+cfg.getReadQueueThreshold());
		System.out.println("delay="+cfg.getDelay()); 
		System.out.println("delay_resolution="+cfg.getDelayResolution()); 
		System.out.println("delay_mode="+cfg.getDelayMode());
		System.out.println("run="+cfg.getRun());
		System.out.println("sensitivity="+cfg.getSensitivity());
	}
	
	private AccelerometerSampleStream createAccelerometerInputStream() {
		IAccelerometerSampleFeed isp = (IAccelerometerSampleFeed) serviceProvider.getService(IAccelerometerSampleFeed.class);
		return isp.getSampleInputStream();
	}

	public List getServices() {
		List services = new ArrayList();
		services.add(IModuleDisplay.class.getName());
		services.add(IAccelerometerSampleFeed.class.getName());
		services.add(IAccelerometerControl.class.getName());
		return services;
	}

	private IModuleDisplay getIModuleDisplay() {
		return (IModuleDisplay) serviceProvider.getService(IModuleDisplay.class);
	}
	
	private void createUI(){
		frame = getIModuleDisplay().getFrame();
		frame.setTitle("Puck");
		frame.setLayout(new BorderLayout());
		puckPanel = new PuckPanel();
		frame.add(puckPanel, BorderLayout.CENTER);		
		frame.show();
	}
	private void destroyUI(){
		frame.dispose();
		frame = null;
		puckPanel = null;

	}
}