/*******************************************************************************
 * Copyright (c) 2013 See AUTHORS file.
 * 
 * This file is part of SleepFighter.
 * 
 * SleepFighter is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * SleepFighter is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with SleepFighter. If not, see <http://www.gnu.org/licenses/>.
 ******************************************************************************/
package se.chalmers.dat255.sleepfighter.challenge;

import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;

import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.widget.ProgressBar;
import android.widget.TextView;
import se.chalmers.dat255.sleepfighter.R;
import se.chalmers.dat255.sleepfighter.activity.ChallengeActivity;
import se.chalmers.dat255.sleepfighter.model.challenge.ChallengeType;

/**
 * A challenge where the user have to shake the device to complete it.
 */
public class ShakeChallenge implements Challenge {

	public static class PrototypeDefinition extends ChallengePrototypeDefinition {{
		setType(ChallengeType.SHAKE);
	}}

	private static final float GOAL = 5000;
	private static final String KEY_PROGRESS_FLOAT = "progress";

	private ChallengeActivity activity;
	private ProgressBar progressBar;
	private TextView progressText;

	private SensorManager sensorManager;
	private Sensor accelerometer;

	private float progress = 0;
	private Vector3D lastVector;

	@Override
	public void start(ChallengeActivity activity, ChallengeResolvedParams params) {
		start(activity, params, null);
	}
	
	@Override
	public void start(ChallengeActivity activity,
			ChallengeResolvedParams params, Bundle state) {
		this.activity = activity;
		this.activity.setContentView(R.layout.challenge_shake);


		// Get view references
		this.progressBar = (ProgressBar) this.activity
				.findViewById(R.id.progressBar);
		this.progressText = (TextView) this.activity
				.findViewById(R.id.progressText);

		// Get progress from bundle
		if(state != null) {
			this.progress = state.getFloat(KEY_PROGRESS_FLOAT);
		}
	
		// Register to get acceleration events
		this.sensorManager = (SensorManager) activity
				.getSystemService(Context.SENSOR_SERVICE);
		this.accelerometer = sensorManager
				.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
	}
	
	private SensorEventListener sensorEventListener = new SensorEventListener() {

		@Override
		public void onSensorChanged(SensorEvent event) {
			float x = event.values[0];
			float y = event.values[1];
			float z = event.values[2];
			Vector3D vector = new Vector3D(x, y, z);
			onAccelerationChange(vector);
		}

		@Override
		public void onAccuracyChanged(Sensor sensor, int accuracy) {}
	};

	/**
	 * Handle an acceleration change event.
	 * 
	 * @param vector
	 *            the current acceleration vector
	 */
	private void onAccelerationChange(Vector3D vector) {
		// Only take vector difference into account, need a last vector
		if (lastVector != null) {
			// The difference of the vectors
			Vector3D diff = vector.subtract(lastVector);

			// The one dimensional "size" of the difference, there are probably
			// better things to measure
			double work = diff.getNorm();

			// Increase the accumulator
			this.progress += work;

			updateProgress();

			checkIfCompleted();
		}
		this.lastVector = vector;
	}

	private void updateProgress() {
		// Change the progress bar and text to show how near completion
		int percentage = Math.min(100, Math.round(100 * (progress / GOAL)));
		this.progressBar.setProgress(percentage);
		this.progressText.setText(percentage + "%");
	}

	private void checkIfCompleted() {
		if (progress >= GOAL) {
			// Unregister when done
			this.sensorManager.unregisterListener(sensorEventListener);
			this.activity.complete();
		}
	}

	@Override
	public Bundle savedState() {
		Bundle state = new Bundle();
		state.putFloat(KEY_PROGRESS_FLOAT, this.progress);
		return state;
	}

	@Override
	public void onPause() {
		this.sensorManager.unregisterListener(sensorEventListener);
	}

	@Override
	public void onResume() {
		this.sensorManager.registerListener(this.sensorEventListener,
				accelerometer, SensorManager.SENSOR_DELAY_GAME);
	}

	@Override
	public void onDestroy() {
	}
}

@@ -1040,16 +1040,58 @@
 ontext;%0A
+import android.content.pm.PackageManager;%0A
 import a
@@ -1114,16 +1114,16 @@
 Sensor;%0A
-
 import a
@@ -1261,16 +1261,41 @@
 Bundle;%0A
+import android.util.Log;%0A
 import a
@@ -1664,16 +1664,70 @@
 enge %7B%0A%0A
+%09private static final String TAG = %22ShakeChallenge%22;%0A%0A
 %09public 
@@ -2809,17 +2809,455 @@
 T);%0A%09%09%7D%0A
-%09
+%0A%09%09// Check if required sensor is available%0A%09%09boolean hasAccelerometer = activity.getPackageManager()%0A%09%09%09%09.hasSystemFeature(PackageManager.FEATURE_SENSOR_ACCELEROMETER);%0A%09%09if(!hasAccelerometer) %7B%0A%09%09%09// Complete right away, for now. Checking if device has required%0A%09%09%09// hardware could perhaps be done before the challenge is started.%0A%09%09%09Log.e(TAG, %22Device lacks required sensor for ShakeChallenge%22);%0A%09%09%09activity.complete();%0A%09%09%09return;%0A%09%09%7D%0A
 %0A%09%09// Re

Check if sensor available in ShakeChallenge