package phunky;

import com.buglabs.application.AbstractServiceTracker;
import com.buglabs.application.MainApplicationThread;

import java.io.IOException;
import java.util.*;

import com.buglabs.bug.accelerometer.pub.AccelerometerSample;
import com.buglabs.bug.accelerometer.pub.AccelerometerSampleStream;
import com.buglabs.bug.accelerometer.pub.IAccelerometerSampleFeed;
import com.buglabs.bug.module.audio.pub.IModuleAudioPlayer;

/**
 * PhunkyApplication Main application thread. The run method is invoked by the
 * applications service tracker when all services are accounted for.
 * 
 */
public class PhunkyApplication extends MainApplicationThread {
	private static final int MAX_ACCELEROMETER_TRIES = 100;
	private AbstractServiceTracker serviceTracker;
	private boolean ran;

	public PhunkyApplication(AbstractServiceTracker serviceTracker) {
		this.serviceTracker = serviceTracker;
		ran = false;
	}

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

	private void ran() {
		ran = true;
	}

	/**
	 * This method is invoked as a result of all services becoming available for
	 * the application. The list of services is obtained from the getServices()
	 * method.
	 */
	public void run() {
		System.out.println("Running: PhunkyApplication");
		
		final AccelerometerSampleStream is = getIAccelerometerSampleFeed().getSampleInputStream();
		final IModuleAudioPlayer audioPlayer = getIAudioPlayer();
		SampleStream sampleStream = null;
		int accelerometerTries = 0;
		boolean needToWait = false;
		
		// start playing our stream. it's okay that we haven't put
		// any data in it yet - it will handle that for us.
		try {
			sampleStream = new SampleStream(serviceTracker.getBundleContext());
			audioPlayer.play(sampleStream);			
		}
		catch (IOException e) {
			e.printStackTrace();
			
			// if we couldn't start playing then no point in looping
			tearDownRequested = true;
		}
		
		// provide input data ad infinitum as fast as we can.
		// the samples output aren't tied to our speed though,
		// just the rate of change of samples is.
		while (!tearDownRequested) {
			try {
				final AccelerometerSample sample = is.readSample();
				if (sample != null) {
					sampleStream.update(
							sample.getAccelerationX(),
							sample.getAccelerationY(),
							sample.getAccelerationZ());
				} else {
					System.err.println("got a null sample");
					
					// don't thrash if this happens
					needToWait = true;
				}

			} catch (IOException e) {
				e.printStackTrace();

				if (accelerometerTries++ < MAX_ACCELEROMETER_TRIES) {
					// don't thrash if this happens
					System.err.println("Attempt " + accelerometerTries + " to get stream");
					needToWait = true;					
				} else {
					// too many times; say bye bye
					tearDownRequested = true;
				}
			}
			
			if (needToWait) {
				try {
					sleep(50);
				} catch (InterruptedException e) {
					// s'ok
				}
			}
		}

		sampleStream.stop();
		System.out.println("PhunkyApplication stopped");
		ran();
	}

	/**
	 * Provides a list of service names that this application depends on.
	 * 
	 */
	public List getServices() {
		List services = new ArrayList();
		services.add("com.buglabs.bug.accelerometer.pub.IAccelerometerSampleFeed");
		services.add("com.buglabs.bug.module.audio.pub.IModuleAudioPlayer");
		return services;
	}

	/**
	 * Queries the service provider for IAccelerometerSampleFeed.
	 * 
	 * @return a handle to the a(n) IAccelerometerSampleFeed service.
	 */
	private IAccelerometerSampleFeed getIAccelerometerSampleFeed() {
		return (IAccelerometerSampleFeed) serviceTracker
				.getService(IAccelerometerSampleFeed.class);
	}

	/**
	 * Queries the service provider for IAudioPlayer.
	 * 
	 * @return a handle to the a(n) IAudioPlayer service.
	 */
	private IModuleAudioPlayer getIAudioPlayer() {
		return (IModuleAudioPlayer) serviceTracker.getService(IModuleAudioPlayer.class);
	}
}