package ie.hennisoft.zumocontrol;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
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.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.widget.CompoundButton;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.Switch;
import android.widget.TextView;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;

import java.io.IOException;
import java.io.OutputStream;
import java.util.UUID;

public class MainActivity extends AppCompatActivity implements SensorEventListener {
    ImageButton functionF, functionB, functionL, functionR;
    SeekBar mySeekbar;
    TextView myTextview;
    ImageView myImageView;

    Switch switch_button;

    private SensorManager sensorManager;
    private final float[] accelerometerReading = new float[3];
    private final float[] magnetometerReading = new float[3];

    private final float[] rotationMatrix = new float[9];
    private final float[] orientationAngles = new float[3];

    private BluetoothAdapter btAdapter = null;
    private BluetoothSocket btSocket = null;
    private OutputStream outStream = null;

    private int speed = 30;
    private boolean inclineEnabled = false;


    // SPP UUID service - this should work for most devices
    private static final UUID BTMODULEUUID = UUID.fromString("94f39d29-7d6d-437d-973b-fba39e49d4ee");

    // String for MAC address
    //private static String address;
    private static String address = "B8:27:EB:66:C5:26";

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item)  {
       /* switch(item.getItemId()) {
            case R.id.opt_beenden:
                finish();
                break;
            // ...
            default:
        } */
        if (item.getItemId() == R.id.opt_beenden) {
            finish();
        }

        return super.onOptionsItemSelected(item);
    }

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

        // add logo + name
        getSupportActionBar().setDisplayShowHomeEnabled(true);
        getSupportActionBar().setLogo(R.mipmap.ic_launcher_zumocontrol_round);
        getSupportActionBar().setDisplayUseLogoEnabled(true);

        //Link the buttons and textViews to respective views
        // Initialize buttons in the view
        functionF = findViewById(R.id.imageButton_up);
        functionB = findViewById(R.id.imageButton_down);
        functionL = findViewById(R.id.imageButton_left);
        functionR = findViewById(R.id.imageButton_right);

        mySeekbar = findViewById(R.id.seekBar_speed);
        myTextview = findViewById(R.id.textView_info);
        myImageView = findViewById(R.id.imageView_status);

        mySeekbar.setProgress(speed); // set/show initial speed
        myTextview.setText(getString(R.string.txt_speedchanged) + speed); // show speedvalue

        sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);

        switch_button = findViewById(R.id.switchBotton1);

        btAdapter = BluetoothAdapter.getDefaultAdapter();       // get Bluetooth adapter
        checkBTState();

        // set a checked state listener for switch button
        switch_button.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                if (isChecked) {
                    functionF.setEnabled(false);
                    functionB.setEnabled(false);
                    functionL.setEnabled(false);
                    functionR.setEnabled(false);

                    inclineEnabled = true;

                } else {
                    functionF.setEnabled(true);
                    functionB.setEnabled(true);
                    functionL.setEnabled(true);
                    functionR.setEnabled(true);

                    inclineEnabled = false;

                }
            }
        });

        // setup onTouch listeners for buttons to send commmands via BT to Raspi
        functionF.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (event.getAction() == MotionEvent.ACTION_DOWN){
                    sendData("g");
                    myImageView.setImageResource(R.drawable.ic_bigup);
                }
                if(event.getAction() == MotionEvent.ACTION_UP){
                    sendData("r");
                    myImageView.setImageResource(R.drawable.ic_bigstop);
                }
                return true;
            }
        });

        functionB.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (event.getAction() == MotionEvent.ACTION_DOWN){
                    sendData("b");
                    myImageView.setImageResource(R.drawable.ic_bigdown);

                }
                if(event.getAction() == MotionEvent.ACTION_UP) {
                    sendData("r");
                    myImageView.setImageResource(R.drawable.ic_bigstop);
                }
                return true;
            }
        });

        functionL.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (event.getAction() == MotionEvent.ACTION_DOWN) {
                    sendData("o");
                    myImageView.setImageResource(R.drawable.ic_bigleft);
                }
                if (event.getAction() == MotionEvent.ACTION_UP) {
                    sendData("r");
                    myImageView.setImageResource(R.drawable.ic_bigstop);
                }
                return true;
            }
        });

        functionR.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (event.getAction() == MotionEvent.ACTION_DOWN) {
                    sendData("a");
                    myImageView.setImageResource(R.drawable.ic_bigright);
                }
                if (event.getAction() == MotionEvent.ACTION_UP) {
                    sendData("r");
                    myImageView.setImageResource(R.drawable.ic_bigstop);
                }
                return true;
            }
        });

        // setup seekBar change listener to react on speed change request
        mySeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
                myTextview.setText(getString(R.string.txt_speedchanged) + seekBar.getProgress());
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {
                // bla
            }
            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
                speed = seekBar.getProgress();
                sendData("*" + speed + "~");
            }
        });

    }
/*
    //creates secure outgoing connection with BT device using UUID
    private BluetoothSocket createBluetoothSocket(BluetoothDevice device) throws IOException {
        return  device.createRfcommSocketToServiceRecord(BTMODULEUUID);
    }
*/
    @Override
    public void onResume() {
        super.onResume();

        Sensor accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        if (accelerometer != null) {
            sensorManager.registerListener(this, accelerometer,
                    SensorManager.SENSOR_DELAY_NORMAL, SensorManager.SENSOR_DELAY_UI);
        }
        Sensor magneticField = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
        if (magneticField != null) {
            sensorManager.registerListener(this, magneticField,
                    SensorManager.SENSOR_DELAY_NORMAL, SensorManager.SENSOR_DELAY_UI);
        }

        //create device and set the MAC address
        BluetoothDevice device = btAdapter.getRemoteDevice(address);

        try {
            //btSocket = createBluetoothSocket(device);
            btSocket = device.createRfcommSocketToServiceRecord(BTMODULEUUID);
        } catch (IOException e) {
            Toast.makeText(getBaseContext(), getString(R.string.err_nobtsocket), Toast.LENGTH_LONG).show();
        }

        // Establish the Bluetooth socket connection.
        try
        {
            Toast.makeText(getBaseContext(), getString(R.string.txt_connecting), Toast.LENGTH_LONG).show();
            btSocket.connect();
        } catch (IOException e) {
            try
            {
                btSocket.close();
            } catch (IOException e2)
            {
                Toast.makeText(getBaseContext(), getString(R.string.err_noclosebtsocket), Toast.LENGTH_SHORT).show();
            }
        }

        // Create a data stream so we can talk to the device
        try {
            outStream = btSocket.getOutputStream();
        } catch (IOException e) {
            Toast.makeText(getBaseContext(), getString(R.string.err_nobtoutstream), Toast.LENGTH_SHORT).show();
        }

        // When activity is resumed, attempt to send a piece of junk data ('x') so that it will fail if not connected
        // i.e don't wait for a user to press button to recognise connection failure
        sendData("x");
    }

    @Override
    public void onPause()
    {
        super.onPause();
        try
        {
            //Don't leave Bluetooth sockets open when leaving activity
            btSocket.close();
        } catch (IOException e2) {
            Toast.makeText(getBaseContext(), getString(R.string.err_noclosebtsocket), Toast.LENGTH_SHORT).show();
        }
    }
    //takes the UUID and creates a comms socket
    private BluetoothSocket createBluetoothSocket(BluetoothDevice device) throws IOException {

        return  device.createRfcommSocketToServiceRecord(BTMODULEUUID);
    }

    //Checks that the Android device Bluetooth is available and prompts to be turned on if off
    private void checkBTState() {

        if(btAdapter==null) {
            Toast.makeText(getBaseContext(), getString(R.string.err_nobtsupport), Toast.LENGTH_LONG).show();
        } else {
            if (btAdapter.isEnabled()) {
            } else {
                Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
                startActivityForResult(enableBtIntent, 1);
            }
        }
    }

    //write method
    public void sendData(String input) {
        byte[] msgBuffer = input.getBytes();           //converts entered String into bytes
        try {
            outStream.write(msgBuffer);                //write bytes over BT connection via outstream
        } catch (IOException e) {
            //if you cannot write, close the application
            Toast.makeText(getBaseContext(), getString(R.string.err_connect), Toast.LENGTH_LONG).show();
            finish();
        }
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
            System.arraycopy(event.values, 0, accelerometerReading,
                    0, accelerometerReading.length);
        } else if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
            System.arraycopy(event.values, 0, magnetometerReading,
                    0, magnetometerReading.length);
        }

        updateOrientationAngles();

        if (inclineEnabled) {
            // stop identified (all angles < 30deg)
            if ((Math.abs(Math.toDegrees(orientationAngles[1])) < 20) && (Math.abs(Math.toDegrees(orientationAngles[2])) < 20)) {
                sendData("r");
                myImageView.setImageResource(R.drawable.ic_bigstop);
                // if forward
            } else if ((Math.toDegrees(orientationAngles[1]) > 30) && (Math.abs(Math.toDegrees(orientationAngles[2])) < 20)) {
                sendData("g");
                myImageView.setImageResource(R.drawable.ic_bigup);
                // if backward
            } else if ((Math.toDegrees(orientationAngles[1]) < -30) && (Math.abs(Math.toDegrees(orientationAngles[2])) < 20)) {
                sendData("b");
                myImageView.setImageResource(R.drawable.ic_bigdown);
                // if spin right
            } else if ((Math.abs(Math.toDegrees(orientationAngles[1])) < 20) && (Math.toDegrees(orientationAngles[2]) > 30)) {
                sendData("a");
                myImageView.setImageResource(R.drawable.ic_bigright);
                // if spin left
            } else if ((Math.abs(Math.toDegrees(orientationAngles[1])) < 20) && (Math.toDegrees(orientationAngles[2]) < -30)) {
                sendData("o");
                myImageView.setImageResource(R.drawable.ic_bigleft);
            }
        }
    }

    // Compute the three orientation angles based on the most recent readings from
    // the device's accelerometer and magnetometer.
    public void updateOrientationAngles() {
        // Update rotation matrix, which is needed to update orientation angles.
        SensorManager.getRotationMatrix(rotationMatrix, null,
                accelerometerReading, magnetometerReading);

        // "rotationMatrix" now has up-to-date information.

        SensorManager.getOrientation(rotationMatrix, orientationAngles);

        // "orientationAngles" now has up-to-date information.
    }

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

    }
}