package com.authorwjf.whichwayisup;

// Based on
//    https://www.techrepublic.com/article/pro-tip-create-your-own-magnetic-compass-using-androids-internal-sensors/
//  with addtitions of pitch and roll read-outs.
//
//  The blogpost above mentions math here as being complex, but it fact it's
//    really simple: the azimuth is the angle between the y-axis of the phone in
//    portrait mode and the magnetic north, counted counterclockwise (as is the
//    convention in math). The only confusion comes from Android image rotation API,
//    which interprets its angles _clockwise_, so you need to negate the angle to
//    get the needle to point to the azimuth. Easy.
//
// What is the Rotation Matrix and why was it introduced?
//    The older sensor API, Sensor.TYPE_ORIENTATION, was simpler, and just supplied
//    three angles: azimuth, pitch, and roll, assuming the y-axis of the sensor system
//    was always aligned with the longer side of the phone in portrait mode. Since
//    the sensor is fixed in the phone, its coordinate system is also fixed, and remains
//    the same no matter how you flip the phone.
//
//    However, that did not play well with devices that were meant to be used in landscape
//    mode by default. In the end, the problem was recognized to be about there being _two_
//    distinct coordinate systems involved: once for the sensors (fixed), one for the Views
//    (exchanging x-axis and y-axis directions on flip). The new API provides a rotation
//    matrix to translate between the two systems (getRotationMatrix), and a simple translation
//    function that applies this transform, getOrientation(..). It's not that hard.
//
//    For details see https://android-developers.googleblog.com/2010/09/one-screen-turn-deserves-another.html


import android.app.Activity;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.util.Log;
import android.widget.ImageView;
import android.widget.TextView;

import android.view.animation.Animation;
import android.view.animation.RotateAnimation;

public class MainActivity extends Activity implements SensorEventListener {
	
	private ImageView mNeedle;
	private SensorManager mSensorManager;

    private Sensor mAccelerometer;
    private Sensor mMagnetometer;

    private float[] mLastAccelerometer = new float[3]; // (x, y, z) measurements
    private float[] mLastMagnetometer = new float[3];

    private boolean mLastAccelerometerSet = false;
    private boolean mLastMagnetometerSet = false;

    private float[] mR = new float[9];   // Rotation matrix

    private float[] mOrientation = new float[3]; // (azimuth, pitch, roll)

    // private float mCurrentDegree = 0f; // -- used for rotation animations

    TextView tp;
    TextView tr;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
	    mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
	    mMagnetometer = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);

	    mNeedle = findViewById(R.id.pointer);

	    tp = findViewById(R.id.pitch);
	    tr = findViewById(R.id.roll);
	}

	@Override
	protected void onResume() {
	    super.onResume();
	    mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_GAME);
        mSensorManager.registerListener(this, mMagnetometer, SensorManager.SENSOR_DELAY_GAME);
    }

    @Override
	protected void onPause() {
	    super.onPause();
	    mSensorManager.unregisterListener(this, mAccelerometer);
        mSensorManager.unregisterListener(this, mMagnetometer);
	}

	@Override
	public void onSensorChanged(SensorEvent event) {

	    if (event.sensor == mAccelerometer) {
            System.arraycopy(event.values, 0, mLastAccelerometer, 0, event.values.length);
            mLastAccelerometerSet = true;

	    } else if (event.sensor == mMagnetometer) {
            System.arraycopy(event.values, 0, mLastMagnetometer, 0, event.values.length);
            mLastMagnetometerSet = true;
        }

        if (mLastAccelerometerSet && mLastMagnetometerSet) {

            SensorManager.getRotationMatrix(mR, null, mLastAccelerometer, mLastMagnetometer);
            SensorManager.getOrientation(mR, mOrientation); // matrix multiplication!

            float azimuthInRadians = mOrientation[0];
            float azimuthInDegrees = (float)(Math.toDegrees(azimuthInRadians));

            Log.d("ANGLE", "Rad: " + azimuthInRadians + " Deg: " + azimuthInDegrees);

            double pitch =  Math.toDegrees(mOrientation[1]);
            double roll =   Math.toDegrees(mOrientation[2]);
            Log.d("ANGLE", "Pitch: " + pitch + "Roll: " + roll );


            /*  Original code animated the turn of the arrow. I found it unnecessary.
            RotateAnimation ra = new RotateAnimation(
            		-mCurrentDegree,
                    -azimuthInDegrees,
                    Animation.RELATIVE_TO_SELF,
                    0.5f,
                    Animation.RELATIVE_TO_SELF,
                    0.5f);
     
            ra.setDuration(250);
            ra.setFillAfter(true);
            mPointer.startAnimation(ra);

            mCurrentDegree = azimuthInDegrees;
            */

            // Just set the rotation of the image.
            // setRotation is _clockwise_, whereas the azimuth angle is counterclockwise!
            //   Negation accounts for this disparity.
            mNeedle.setRotation( -azimuthInDegrees );


            tp.setText( "Pitch: " + Math.round(pitch) );
            tr.setText( "Roll: "  + Math.round(roll) );

            // If you want more decimal digits, say, two:
            // tp.setText( "Pitch: " + Math.round(pitch*100.0)/100.0 );
            // tr.setText( "Roll: " + Math.round(roll*100.0)/100.0 );
        }
	}

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

}
