package cz.mynarik.accelerometer_0v5;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
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.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.ArrayAdapter;
import android.widget.Toast;
import android.view.View;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import android.widget.ExpandableListView;

public class MainActivity extends Activity implements SensorEventListener {

	//measure
	private long[] times;
	private long time2, time1=0;
    private File file;
    private FileOutputStream fOut;
    private OutputStreamWriter myOutWriter;
    private boolean saving = false;
    private int fileCounter = 0;
    private int dataCounter = 0;
    public boolean sensFusion = true;
    public boolean sensAccel = false;
    public boolean sensGyro = false;
    // Sensors
    private SensorManager mSensorManager;
	private Sensor mAccelerometer;
    private Sensor mGyroscope;
	private double acc_x;
	private double acc_y;
    private double gyr_x=0;
    private double gyr_y=0;
    private double ang_x;
    private double ang_y;
    private double last_x = 0;
    private double last_y = 0;

    private double T;
    private boolean first=true;
    ExpandableListAdapter listAdapter;
    ExpandableListView expListView;
    List<String> listDataHeader;
    HashMap<String, List<String>> listDataChild;

    // Key names received from the BluetoothService Handler
    public static final String DEVICE_NAME = "device_name";
    public static final String TOAST = "toast";

    // Intent request codes
    private static final int REQUEST_CONNECT_DEVICE = 1;
    private static final int REQUEST_ENABLE_BT = 2;
    private static final int REQUEST_ADVANCED_OPTIONS = 3;
    private int sensorPick = 6;


    // Name of the connected device
    private String mConnectedDeviceName = null;
    // Array adapter for the conversation thread
    private ArrayAdapter<String> mConversationArrayAdapter;
    // String buffer for outgoing messages
    private StringBuffer mOutStringBuffer;
    // Local Bluetooth adapter
    private BluetoothAdapter mBluetoothAdapter = null;
    // Member object for the chat services
    private BluetoothService mChatService = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    	super.onCreate(savedInstanceState);

        // Set up the window layout
        //requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
        setContentView(R.layout.activity_main);
        Log.i("message", "createFile");
        // get the listview
        expListView = (ExpandableListView) findViewById(R.id.lvExp);

        // preparing list data
        prepareListData();

        listAdapter = new ExpandableListAdapter(this, listDataHeader, listDataChild);

        // setting list adapter
        expListView.setAdapter(listAdapter);
        //measure


        mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
        mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        mSensorManager.registerListener(this, mAccelerometer , SensorManager.SENSOR_DELAY_GAME);
        mGyroscope = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
        mSensorManager.registerListener(this,mGyroscope,SensorManager.SENSOR_DELAY_GAME);

        // Get local Bluetooth adapter
        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

        // If the adapter is null, then Bluetooth is not supported
        if (mBluetoothAdapter == null) {
            Toast.makeText(this, "Bluetooth is not available", Toast.LENGTH_LONG).show();
            finish();
            return;
        }

        /*new Timer().scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {

            }
        }, 0, 10);//put here time 1000 milliseconds=1 second*/
    }
    @Override
    public void onStart() {
        super.onStart();

        // If BT is not on, request that it be enabled.
        // setupChat() will then be called during onActivityResult
        if (!mBluetoothAdapter.isEnabled()) {
            Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
        // Otherwise, setup the chat session
        } else {
            if (mChatService == null) setupChat();
        }
    }

    @Override
    public synchronized void onResume() {
        super.onResume();
        // Performing this check in onResume() covers the case in which BT was
        // not enabled during onStart(), so we were paused to enable it...
        // onResume() will be called when ACTION_REQUEST_ENABLE activity returns.
        if (mChatService != null) {
            // Only if the state is STATE_NONE, do we know that we haven't started already
            if (mChatService.getState() == BluetoothService.STATE_NONE) {
              // Start the Bluetooth chat services
              mChatService.start();
            }
        }
    }

    private void setupChat() {

        // Initialize the BluetoothService to perform bluetooth connections
        mChatService = new BluetoothService(this);

        // Initialize the buffer for outgoing messages
        mOutStringBuffer = new StringBuffer("");
    }

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

    @Override
    public void onStop() {
        super.onStop();

    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        // Stop the Bluetooth chat services
        if (mChatService != null) mChatService.stop();
    }

    private void ensureDiscoverable() {
        if (mBluetoothAdapter.getScanMode() !=
            BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
            Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
            discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
            startActivity(discoverableIntent);
        }
    }


    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        switch (requestCode) {
        case REQUEST_CONNECT_DEVICE:
            // When DeviceListActivity returns with a device to connect
            if (resultCode == Activity.RESULT_OK) {
                // Get the device MAC address
                String address = data.getExtras()
                                     .getString(DeviceListActivity.EXTRA_DEVICE_ADDRESS);
                // Get the BLuetoothDevice object
                BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
                // Attempt to connect to the device
                mChatService.connect(device);
            }
            break;
        case REQUEST_ENABLE_BT:
            // When the request to enable Bluetooth returns
            if (resultCode == Activity.RESULT_OK) {
                // Bluetooth is now enabled, so set up a chat session
                setupChat();
            } else {
                // User did not enable Bluetooth or an error occured
                finish();
            }
            break;

        case REQUEST_ADVANCED_OPTIONS:
            if (resultCode == Activity.RESULT_OK) {
                int caseInt = data.getIntExtra("out", 6);
                switch (caseInt) {
                    case 4:
                        sensAccel = true;
                        sensGyro = false;
                        sensFusion = false;
                        sensorPick=4;
                        break;
                    case 5:
                        sensAccel = false;
                        sensGyro = true;
                        sensFusion = false;
                        sensorPick=5;
                        break;
                    case 6:
                        sensAccel = false;
                        sensGyro = false;
                        sensFusion = true;
                        sensorPick=6;
                        break;
                }
            }
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.option_menu, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case R.id.scan:
            // Launch the DeviceListActivity to see devices and do scan
            Intent serverIntent = new Intent(this, DeviceListActivity.class);
            startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE);
            return true;
        case R.id.discoverable:
            // Ensure this device is discoverable by others
            ensureDiscoverable();
            return true;

        case R.id.advanced:
        // Launch the DeviceListActivity to see devices and do scan
        Intent advancedIntent = new Intent(this, AdvancedOptionsActivity.class);
        advancedIntent.putExtra("in",sensorPick);
        startActivityForResult(advancedIntent, REQUEST_ADVANCED_OPTIONS);

        return true;
        }
        return false;
    }
    
	@Override
	public void onSensorChanged(SensorEvent event) {
		// TODO Auto-generated method stub
		Sensor mySensor = event.sensor;
        if(mySensor.getType()==Sensor.TYPE_GYROSCOPE){
            time2 = System.nanoTime();
            double x_gyr=event.values[1];
            double y_gyr=event.values[0];
            if(first){
                time1=time2;
                first=false;
            }
            T=(time2-time1)/10000000;
            time1=time2;
            if(sensFusion) {


                ang_x = (0.98) * (ang_x + (x_gyr*T)) + (0.02) * acc_x;
                ang_y = (0.98) * (ang_y - (y_gyr*T)) + (0.02) * acc_y;
                //Log.e("Sensor","Fusion");
            }
            else {
                if(sensGyro){
                    ang_x=ang_x+(x_gyr*T);
                    ang_y=ang_y+(y_gyr*T);
                    //Log.e("Sensor","Gyroscope");
                }
            }
            //TextView xval = (TextView) findViewById(R.id.textXval);
            //TextView yval = (TextView) findViewById(R.id.textYval);
            //TextView zval = (TextView) findViewById(R.id.textZval);
            //xval.setText(String.valueOf(x_gyr));
            //yval.setText(String.valueOf(y_gyr));
            //zval.setText(String.valueOf(event.values[2]));
        }
		if (mySensor.getType()==Sensor.TYPE_ACCELEROMETER) {

            acc_x = 0.0;
            acc_y = 0.0;
            acc_x = Math.atan2(Math.sqrt(event.values[2] * event.values[2] + event.values[1] * event.values[1]), event.values[0]);
            acc_y = Math.atan2(Math.sqrt(event.values[2] * event.values[2] + event.values[0] * event.values[0]), event.values[1]);
            acc_x = acc_x * (180 / Math.PI) - 90;
            acc_y = acc_y * (180 / Math.PI) - 90;
            if(sensAccel){
                ang_x=acc_x;
                ang_y=acc_y;
                //Log.e("Sensor","Accelerometer");
            }
            //TextView xang = (TextView) findViewById(R.id.textXangleval);
            //TextView yang = (TextView) findViewById(R.id.textYangleval);
            //xang.setText(String.valueOf(ang_x));
            //yang.setText(String.valueOf(ang_y));


            try{
                mChatService.write(ang_x,ang_y);
                //mChatService.write(xtest,ytest);
            }
            catch(Exception e){
                Log.e("Sending failed", "Bluetooth");
            }

	    }

        if (saving){
            try {
                myOutWriter.append("x,"+Double.toString(acc_x));
                myOutWriter.append(",y,"+Double.toString(acc_y) + ",t," +String.valueOf(System.nanoTime())+ ",\r\n");

            }
            catch (Exception e) {
                Log.e("Write failed", "Data");
            }/**/
            dataCounter++;
            if(dataCounter>300){
                saving=false;
                dataCounter=0;
                try {
                    myOutWriter.close();
                    fOut.close();

                } catch (IOException e) {
                    Log.e("Writer & Stream", "Close");
                }
                Log.e("Data saved","Data saved");
                Toast.makeText(getApplicationContext(), "Data saved!", Toast.LENGTH_SHORT).show();
            }
        }



	}
    public void saveData (View view){
        if(!saving) {
            saving = true;
            fileCounter++;
            dataCounter = 0;
            file = new File(getExternalFilesDir(null), "data" + String.valueOf(fileCounter) + ".csv");

            try {
                file.createNewFile();
                Log.e("Create file", "File created");
            } catch (IOException e) {
                Toast.makeText(getApplicationContext(), "File can't be created, try again!", Toast.LENGTH_SHORT).show();
                Log.e("Create file", "File can't be created");
                saving = false;
                return;
            }
            try {
                fOut = new FileOutputStream(file);
                myOutWriter = new OutputStreamWriter(fOut);
            } catch (Exception e) {
                Log.e("Writer & Stream", "Create");
            }
            try {
                myOutWriter.append(Build.MANUFACTURER + "," + Build.PRODUCT + "," + Build.MODEL + "," + Build.BRAND + ",\r\n");
            } catch (Exception e) {
                Log.e("File write", "Manufacturer and product");
            }
        }
    }
    public void sendData (View view){
        //TODO Sending data over email
    }
	@Override
	public void onAccuracyChanged(Sensor sensor, int accuracy) {
		// TODO Auto-generated method stub
		
	}

    private void prepareListData() {
        listDataHeader = new ArrayList<String>();
        listDataChild = new HashMap<String, List<String>>();

        // Adding child data
        listDataHeader.add("Nastavení Bluetooth v počítači");
        listDataHeader.add("Spárování telefonu a počítače");
        listDataHeader.add("Propojení telefonu a počítače");

        // Adding child data
        List<String> nastaveni = new ArrayList<String>();
        nastaveni.add("Zkontrolujeme, že máme připojený Bluetooth adaptér. Ověříme, jestli je spuštěný, a pokud není, tak ho spustíme.");
        nastaveni.add("Otevřeme nabídku 'Start' a spustíme 'Ovládací panely'. Do políčka 'Prohledat Ovládací panely' napíšeme Bluetooth.");
        nastaveni.add("Klikneme na odkaz 'Změnit nastavení Bluetooth' a přejdeme na záložku 'COM porty'");
        nastaveni.add("Pokud máme nastavený příchozí COM port, poznamenáme si jeho číslo.");
        nastaveni.add("Pokud nemáme nastavený příchozí COM port, klikneme na tlačítko 'Přidat' a po nainstalování si poznamenáme jeho číslo.");

        List<String> sparovani = new ArrayList<String>();
        sparovani.add("Klikneme na tlačítko menu vpravo nahoře (tři tečky nad sebou), pak klikneme na 'Make discoverable' a potvrdíme 'Yes'.");
        sparovani.add("Na počítači klikneme na nabídku 'Start' a spustíme 'Ovládací panely'. Do políčka 'Prohledat Ovládací panely' napíšeme Bluetooth.");
        sparovani.add("Klikneme na tlačítko 'Přidat Bluetooth zařízení'. Počkáme, dokud se nevyhledají všechna dostupná zařízení. Pokud telefon není v seznamu, zkusíme znovu zopakovat první bod.");
        sparovani.add("Vybereme telefon a klikneme na tlačítko další. Po zobrazení kontrolního kódu potvrdíme na telefonu i v počítači, že chcete zařízení spárovat.");

        List<String> pripojeni = new ArrayList<String>();
        pripojeni.add("Na počítači zapneme program DeskBalance.exe. Klikneme na 'Nastavení'->'Připojit se k jinému zařízení'.");
        pripojeni.add("Označíme 'Připojit přes mobilní telefon' a do čísla portu napišeme, na kterém portu je zařízení připojené - viz 'Nastavení Bluetooth v počítači', a potvrdíme 'Připojit se'.");
        pripojeni.add("Klikneme na tlačítko menu vpravo nahoře (tři tečky nad sebou), klikneme na 'Connect a device'. Objeví se seznam spárovaných zařízení, ve kterém označíme počítač, se kterým budeme komunikovat.");
        pripojeni.add("Spojení by se mělo navázat během 3 vteřin a kulička na obrazovce bude reagovat na natočení telefonu.");


        listDataChild.put(listDataHeader.get(0), nastaveni); // Header, Child data
        listDataChild.put(listDataHeader.get(1),sparovani);
        listDataChild.put(listDataHeader.get(2), pripojeni);
    }
}