package app.brest.utils;

import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.provider.Settings;
import android.support.v4.app.ActivityCompat;

import app.brest.testmin3d.ARActivity;
import app.brest.utils.geometry.GPSPoint;

/**
 * Created by ptitcois on 18/08/16.
 */
public class SensorsManager implements SensorEventListener, LocationListener {

    private SensorManager mSensorManager;
    private Sensor mAccelerometer;
    private Sensor mMagnetometer;
    private float[] mLastAccelerometer = new float[3];
    private float[] mLastMagnetometer = new float[3];
    private boolean mLastAccelerometerSet = false;
    private boolean mLastMagnetometerSet = false;
    private float[] mR = new float[9];
    private float[] mOrientation = new float[3];
    private float mCurrentDegreeX = 0f;
    private float mCurrentDegreeY = 0f;
    private float mCurrentDegreeZ = 0f;
    private SlideBuffer mBufferX;
    private SlideBuffer mBufferY;
    private SlideBuffer mBufferZ;
    private LocationManager mLocationManager;

    private double mLatitude;
    private double mLongitude;
    private float mAccuracy;
    private boolean mIsLocalised = false;
    private ARActivity mParent;

    public float getAzimuth() {
        return mBufferX.average();
    }


    public float getAzimuthStep() {
        return ((int)mBufferX.average()/10)*10;
    }

    public float getAngleY() {
        return mBufferY.average();
    }

    public float getAngleZ() {
        return mBufferZ.average();
    }

    public float getOrientation() {
        return getAzimuth();
    }

    public GPSPoint getPosition()
    {
        if(!mIsLocalised) return null;
        return new GPSPoint(mLongitude, mLatitude, mAccuracy);
    }

    public SensorsManager(ARActivity parent ){
        mParent = parent;
        mLocationManager = (LocationManager) parent.getSystemService(parent.LOCATION_SERVICE);

        mSensorManager = (SensorManager) parent.getSystemService(parent.SENSOR_SERVICE);
        mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        mMagnetometer = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
        mBufferX = new SlideBuffer(16);
        mBufferY = new SlideBuffer(8);
        mBufferZ = new SlideBuffer(8);

        if (ActivityCompat.checkSelfPermission(mParent, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
                ActivityCompat.checkSelfPermission(mParent, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {

        }

        mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
    }

    public void onResume() {
        mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_GAME);
        mSensorManager.registerListener(this, mMagnetometer, SensorManager.SENSOR_DELAY_GAME);

        if (ActivityCompat.checkSelfPermission(mParent, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
                ActivityCompat.checkSelfPermission(mParent, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {

        }

        if (!mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
            Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
            mParent.startActivity(intent);
        }

        mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 400, 1, this);
        mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 400, 1, this);
    }

    public void onPause() {
        mSensorManager.unregisterListener(this, mAccelerometer);
        mSensorManager.unregisterListener(this, mMagnetometer);
        if (ActivityCompat.checkSelfPermission(mParent, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
                && ActivityCompat.checkSelfPermission(mParent, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            return;
        }
        mLocationManager.removeUpdates(this);
    }

    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);
            float azimuthInRadians = mOrientation[0];
            float azimuthInDegress = (float)(Math.toDegrees(azimuthInRadians)+360)%360;

            mCurrentDegreeX = -azimuthInDegress;
            while(mCurrentDegreeX<0) mCurrentDegreeX+=360;
            mBufferX.enqueue(mCurrentDegreeX);

            mBufferY.enqueue((float)(Math.toDegrees(mOrientation[1])+360)%360);
            mBufferZ.enqueue((float)(Math.toDegrees(mOrientation[2])+360)%360);
        }
    }

    /*
     *
     * GPS
     *
     */


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


    @Override
    public void onLocationChanged(Location location) {
        mIsLocalised=true;
        mLongitude=location.getLongitude();
        mLatitude=location.getLatitude();
        mAccuracy=location.getAccuracy();

        mParent.setGpsText(mLatitude, mLongitude);
        //Toast.makeText(mParent,  "Longitude: "+location.getLongitude()+ " Latitude: "+location.getLatitude(), Toast.LENGTH_LONG).show();
    }



    @Override
    public void onStatusChanged(String s, int i, Bundle bundle) {}

    @Override
    public void onProviderEnabled(String s) {}

    @Override
    public void onProviderDisabled(String s) {}
}
