package de.reinhardt_karlheinz.pcc.android.plugins.remote_minecraft;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.os.RemoteException;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.FrameLayout;

public class RemoteMinecraftActivity extends Activity implements
		SensorEventListener, OnClickListener {

	private static final String TAG = "RemoteMinecraftActivity";

	// private SensorManager sm;
	/* sensor data */
	// @http://pastebin.com/c1MNT5x7
	SensorManager m_sensorManager;

	float[] m_lastMagFields;

	float[] m_lastAccels;

	private float[] m_rotationMatrix = new float[16];

	private float[] m_remappedR = new float[16];

	private float[] m_orientation = new float[4];

	/* fix random noise by averaging tilt values */
	final static int AVERAGE_BUFFER = 30;

	float[] m_prevPitch = new float[AVERAGE_BUFFER];

	float m_lastPitch = 0.f;

	float m_lastYaw = 0.f;

	/* current index int m_prevEasts */
	int m_pitchIndex = 0;

	float[] m_prevRoll = new float[AVERAGE_BUFFER];

	float m_lastRoll = 0.f;

	/* current index into m_prevTilts */
	int m_rollIndex = 0;

	/* center of the rotation */
	private float m_tiltCentreX = 0.f;

	private float m_tiltCentreY = 0.f;

	private float m_tiltCentreZ = 0.f;

	private Button leftClickBtn, rightClickBtn, spaceBtn;
	private boolean alreadyStarted = false;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		if (alreadyStarted == false) {
			super.onCreate(savedInstanceState);
			setContentView(R.layout.minecraft);
			leftClickBtn = (Button) findViewById(R.id.button2);
			rightClickBtn = (Button) findViewById(R.id.button3);
			spaceBtn = (Button) findViewById(R.id.button4);
			leftClickBtn.setOnClickListener(this);
			rightClickBtn.setOnClickListener(this);
			spaceBtn.setOnClickListener(this);
			// setViews();//FIXME
			Log.d(TAG, "act started");
			m_sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
			registerListeners();
			// TiltCalc tc = new TiltCalc(getBaseContext());
			bindToPCCService();
			alreadyStarted = true;
		}
	}

	// FIXME
	private void setViews() {
		setContentView(R.layout.pcc_rmt_mc);
		FrameLayout left = (FrameLayout) findViewById(R.id.frameLayout1);
		FrameLayout right = (FrameLayout) findViewById(R.id.frameLayout2);
		View leftView = findViewById(R.layout.headctrl);
		left.addView(leftView);
		View rightView = findViewById(R.layout.move_btns);
		right.addView(rightView);
	}

	private void registerListeners() {
		m_sensorManager.registerListener(this,
				m_sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD),
				SensorManager.SENSOR_DELAY_GAME);
		m_sensorManager.registerListener(this,
				m_sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
				SensorManager.SENSOR_DELAY_GAME);
	}

	private void unregisterListeners() {
		m_sensorManager.unregisterListener(this);
	}

	/**
	 * not needed yet
	 */
	double delayYaw = 5;

	double delayRoll = 7.5f;

	double delayPitch = 7.5f;

	private void computeOrientation() {
		if (SensorManager.getRotationMatrix(m_rotationMatrix, null,
				m_lastAccels, m_lastMagFields)) {
			SensorManager.getOrientation(m_rotationMatrix, m_orientation);

			/* 1 radian = 57.2957795 degrees */
			/*
			 * [0] : yaw, rotation around z axis [1] : pitch, rotation around x
			 * axis [2] : roll, rotation around y axis
			 */
			float yaw = m_orientation[0] * 57.2957795f;
			float pitch = m_orientation[1] * 57.2957795f;
			float roll = m_orientation[2] * 57.2957795f;

			/* append returns an average of the last 10 values */
			m_lastYaw = m_filters[0].append(yaw);
			m_lastPitch = m_filters[1].append(pitch);
			m_lastRoll = m_filters[2].append(roll);
			// TextView rt = (TextView) findViewById(R.id.roll);
			// TextView pt = (TextView) findViewById(R.id.pitch);
			// TextView yt = (TextView) findViewById(R.id.yaw);
			// yt.setText("azi z: " + m_lastYaw);
			// pt.setText("pitch x: " + m_lastPitch);
			// rt.setText("roll y: " + m_lastRoll);
			// Log.d("tag", "yaw: " + m_lastYaw + " pitch: " + m_lastPitch
			// + " roll: " + m_lastRoll);
			// pitch //TODO shorter
			if (m_lastPitch >= delayRoll) {
				ptch = 1;
			}
			if (m_lastPitch <= -delayRoll) {
				ptch = -1;
			}
			if (m_lastPitch < delayRoll && m_lastPitch > -delayRoll) {
				ptch = 0;
			}
			// send pitch
			if (lastptch != ptch) {
				try {
					pccSvConn.getPccService().sendMsg("ptch_" + ptch);
				} catch (RemoteException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}// FIXME
				lastptch = ptch;
			}
			// roll
			if (m_lastRoll >= delayPitch) {
				rll = 1;
			} else {
				if (m_lastRoll <= -delayPitch) {
					rll = -1;
				} else {
					rll = 0;
				}
			}
			// send roll
			if (lastrll != rll) {
				try {
					pccSvConn.getPccService().sendMsg("rll_" + rll);
				} catch (RemoteException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}// FIXME
				lastrll = rll;
			}
		}
	}

	int rll = 0;

	int ptch = 0;

	int lastptch = 0;

	int lastrll = 0;

	// @Override
	// protected void onResume() {
	// super.onResume();
	// // Sensor acc_sensor = sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
	//
	// // register this class as a listener for the orientation and
	// // accelerometer sensors
	// // sm.registerListener(this, acc_sensor, SensorManager.SENSOR_DELAY_UI);
	// }

	private final TouchVector referenceVector = new TouchVector(0, 0, 0, 1);

	float lastXPos = 0;

	float lastYPos = 0;

	@Override
	public boolean onTouchEvent(MotionEvent me) {
		// TODO set intervall
		int action = me.getAction();
		float currentXPosition = me.getX();
		float currentYPosition = me.getY();

		// Log.v(TAG, "Action = " + action);
		// Log.v(TAG, "X = " + currentXPosition + "Y = " + currentYPosition);
		if (action == MotionEvent.ACTION_DOWN) {
			// lastXPos = 0;
			// lastYPos = 0;
			lastXPos = me.getX();
			lastYPos = me.getY();
		}
		if (action == MotionEvent.ACTION_MOVE) {
			// calculate vector
			TouchVector vector = new TouchVector(lastXPos, currentXPosition,
					lastYPos, currentYPosition);

			// McGlobals.svr.sendMsg("angl("+ angle+")lnght("+length+")");
			try {
				pccSvConn.getPccService().sendMsg(
						"X(" + vector.getX() + ")Y(" + vector.getY() + ")");
			} catch (RemoteException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}// FIXME

			// Toast.makeText(getBaseContext(), "" + angle, 10).show();

			// do something
			lastXPos = currentXPosition;
			lastYPos = currentYPosition;

		}

		if (action == MotionEvent.ACTION_UP) {
			// do something
			// lastXPos = 0;
			// lastYPos = 0;
			Log.v(TAG, "finger released");
		}

		return true;
	}

	@Override
	public void onDestroy() {
		unregisterListeners();
		unbindService(pccSvConn);
		super.onDestroy();
	}

	@Override
	public void onPause() {
		unregisterListeners();
		super.onPause();
	}

	@Override
	public void onResume() {
		registerListeners();
		super.onResume();
	}

	@Override
	public void onAccuracyChanged(Sensor sensor, int accuracy) {
		// TODO Auto-generated method stub

	}

	@Override
	public void onSensorChanged(SensorEvent event) {
		if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
			accel(event);
		}
		if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
			mag(event);
		}
	}

	private void accel(SensorEvent event) {
		if (m_lastAccels == null) {
			m_lastAccels = new float[3];
		}

		System.arraycopy(event.values, 0, m_lastAccels, 0, 3);

		/*
		 * if (m_lastMagFields != null) { computeOrientation(); }
		 */
	}

	private void mag(SensorEvent event) {
		if (m_lastMagFields == null) {
			m_lastMagFields = new float[3];
		}

		System.arraycopy(event.values, 0, m_lastMagFields, 0, 3);

		if (m_lastAccels != null) {
			computeOrientation();
		}
	}

	Filter[] m_filters = { new Filter(), new Filter(), new Filter() };

	private class Filter {
		static final int AVERAGE_BUFFER = 10;

		float[] m_arr = new float[AVERAGE_BUFFER];

		int m_idx = 0;

		public float append(float val) {
			m_arr[m_idx] = val;
			m_idx++;
			if (m_idx == AVERAGE_BUFFER)
				m_idx = 0;
			return avg();
		}

		public float avg() {
			float sum = 0;
			for (float x : m_arr)
				sum += x;
			return sum / AVERAGE_BUFFER;
		}

	}

	// @Override
	// public void onAccuracyChanged(Sensor sensor, int accuracy) {
	// // TODO Auto-generated method stub

	// }

	// float[] values;
	//
	// @Override
	// public void onSensorChanged(SensorEvent event) {
	// values = event.values;
	// float[] R = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
	// float[] orientation = sm.getOrientation(R, values);
	// Log.d("SENSOR LISTENER", "X: " + orientation[1] + "Y: "
	// + orientation[2] + "Z: " + orientation[0]);
	// }
	//
	// @Override
	// protected void onStop() {
	// // unregister listener
	// sm.unregisterListener(this);
	// super.onStop();
	// }
	// stuff for connection to PCC SERVICE
	private PCCServiceConnection pccSvConn;

	private static final String ACTION_PICK_SERVICE = "pcc.intent.action.PICK_PCCSERVICE";

	private static final String CATEG = "pcc.intent.category.PCC_PCCSERVICE";

	public void bindToPCCService() {
		Log.d("mcAct", "binding");
		pccSvConn = new PCCServiceConnection();
		Intent i = new Intent(ACTION_PICK_SERVICE);
		i.addCategory(CATEG);
		this.bindService(i, pccSvConn, Context.BIND_DEBUG_UNBIND);
	}

	@Override
	public void onClick(View v) {
		if (leftClickBtn == v) {
			try {
				pccSvConn.getPccService().sendMsg("MOUSE_LEFT");
			} catch (RemoteException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		if (rightClickBtn == v) {

		}
		if (spaceBtn == v) {

		}
	}

}
