package com.asuscomm.mahaljsp.bluetoothtest;

import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.method.ScrollingMovementMethod;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.TextView;
import android.widget.Toast;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;

public class MainActivity extends AppCompatActivity {
    TextView txtMsg;
    EditText editMsg;
    ListView listViewPaired, listViewUnPaire;
    BluetoothAdapter btAdapter;
    Set<BluetoothDevice> deviceSet=new HashSet<>();
    List<BluetoothDevice>bondDeviceList=new ArrayList<>();
    List<BluetoothDevice>unBondDeviceList=new ArrayList<>();
    List<HashMap<String, String>> pairedList=new ArrayList<>(), unPaireList=new ArrayList<>();
    SimpleAdapter pairedAdapter, unPaireAdapter;
    private OutputStream outputStream;
    private InputStream inputStream;
    //final String SPP_UUID = "00001101-0000-1000-8000-00805F9B34FB";
    final String SPP_UUID = "abcd0000-1234-1234-1234-abcd12345678";
    UUID uuid = UUID.fromString(SPP_UUID);
    BluetoothSocket clientSocket;
    private BluetoothServerSocket serverSocket;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        listViewPaired=(ListView)findViewById(R.id.listViewPaired);
        listViewUnPaire=(ListView)findViewById(R.id.listViewUnPaire);
        txtMsg=(TextView)findViewById(R.id.txtMsg);
        txtMsg.setMovementMethod(new ScrollingMovementMethod());
        editMsg=(EditText)findViewById(R.id.editMsg);
        btAdapter=BluetoothAdapter.getDefaultAdapter();
        if(btAdapter==null){
            new AlertDialog.Builder(this)
                    .setTitle("Bluetooth Test")
                    .setMessage(("裝置沒有藍芽設備, 即將結束"))
                    .setPositiveButton("確定", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            finish();
                        }
                    })
                    .show();
        }
        if(!btAdapter.isEnabled()){
            //Intent intent=new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            //startActivityForResult(intent, 100);
            btAdapter.enable();
            processPermission();
        }
        else{
            processPermission();
        }
    }
    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if(requestCode==100){
            if(resultCode==Activity.RESULT_CANCELED){
                new AlertDialog.Builder(this)
                        .setMessage("藍芽未開啟, 即將結束")
                        .setPositiveButton("確定", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                finish();
                            }
                        })
                        .show();
            }
            else if(resultCode==Activity.RESULT_OK){
                processPermission();
            }
        }
    }
    private void init(){
        //設定已配對 ListView 的 Adapter及Click事件
        pairedAdapter=new SimpleAdapter(
                this,
                pairedList,
                R.layout.listview_layout,
                new String[]{"Name","Mac"},
                new int[]{R.id.txtName, R.id.txtMac}
        );
        listViewPaired.setAdapter(pairedAdapter);
        listViewPaired.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Toast.makeText(MainActivity.this, "connecting......", Toast.LENGTH_LONG).show();
                String mac=pairedList.get(position).get("Mac");
                BluetoothDevice device=btAdapter.getRemoteDevice(mac);
                try {
                    clientSocket = device.createRfcommSocketToServiceRecord(uuid);
                    clientSocket.connect();
                    outputStream=clientSocket.getOutputStream();
                    inputStream=clientSocket.getInputStream();
                    serverSocket.close();//當裝置為client時, 要中斷下面執行緒裏的 serverSocket.accept() blocking call
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
        //設定搜尋 ListView 的 Adapter及Click事件
        unPaireAdapter=new SimpleAdapter(
                this,
                unPaireList,
                R.layout.listview_layout,
                new String[]{"Name","Mac"},
                new int[]{R.id.txtName, R.id.txtMac}
        );
        listViewUnPaire.setAdapter(unPaireAdapter);
        listViewUnPaire.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                String s=unPaireList.get(position).get("Mac");
                Log.d("Thomas", s);
                bondDevice(unPaireList.get(position).get("Mac"));
            }
        });

        deviceSet=btAdapter.getBondedDevices();
        if(deviceSet.size()>0){
            for(BluetoothDevice device: deviceSet){
                HashMap<String, String>hashMap=new HashMap<>();
                hashMap.put("Name", device.getName());
                hashMap.put("Mac", device.getAddress());
                pairedList.add(hashMap);
                pairedAdapter.notifyDataSetChanged();
                bondDeviceList.add(device);
            }
        }
        IntentFilter filter=new IntentFilter();
        filter.addAction(BluetoothDevice.ACTION_FOUND);
        filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
        registerReceiver(btReceiver, filter);
        btAdapter.startDiscovery();
        new ReceivedThread().start();
    }
    BroadcastReceiver btReceiver=new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if(intent.getAction().equals(BluetoothDevice.ACTION_FOUND)){
                BluetoothDevice device=intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                unBondDeviceList.add(device);
                HashMap<String, String>hashMap=new HashMap<>();
                hashMap.put("Name", device.getName());
                hashMap.put("Mac", device.getAddress());
                unPaireList.add(hashMap);
                unPaireAdapter.notifyDataSetChanged();
            }
            else if(intent.getAction().equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED)) {
                int cur_bond_state = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.BOND_NONE);
                int previous_bond_state = intent.getIntExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, BluetoothDevice.BOND_NONE);
                Log.d("Thomas", "### cur_bond_state ##" + cur_bond_state + " ~~ previous_bond_state" + previous_bond_state);
                if(cur_bond_state==BluetoothDevice.BOND_BONDED){
                    BluetoothDevice device=intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                    HashMap<String, String>hashMap=new HashMap<>();
                    hashMap.put("Name", device.getName());
                    hashMap.put("Mac", device.getAddress());
                    pairedList.add(hashMap);
                    pairedAdapter.notifyDataSetChanged();
                    bondDeviceList.add(device);
                    unBondDeviceList.remove(device);
                    for (HashMap<String, String >h : unPaireList){
                        if(h.get("Mac").equals(device.getAddress())){
                            unPaireList.remove(h);
                            unPaireAdapter.notifyDataSetChanged();
                            break;
                        }
                    }
                }
            }
        }
    };
    @Override
    protected void onDestroy() {
        btAdapter.cancelDiscovery();
        unregisterReceiver(btReceiver);
        super.onDestroy();
    }
    private void processPermission(){
        if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.M){
            int hasPermission=checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION);
            if(hasPermission!= PackageManager.PERMISSION_GRANTED){
                requestPermissions(
                        new String[]{Manifest.permission.ACCESS_FINE_LOCATION},200);
            }
            else{
                init();
            }
        }
        else init();
    }
    @Override
    public void onRequestPermissionsResult(
            int requestCode,
            @NonNull String[] permissions,
            @NonNull int[] grantResults) {
        if(requestCode==200){
            if (grantResults[0]==PackageManager.PERMISSION_GRANTED)init();
            else Toast.makeText(this, "No permission", Toast.LENGTH_LONG).show();
        }
        else super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }
    public void bondDevice(String mac){
        Method createBondMethod = null;
        try {
            createBondMethod = BluetoothDevice.class.getMethod("createBond");
            for(BluetoothDevice d:unBondDeviceList) {
                if(d.getAddress()!=null && d.getAddress().equals(mac)) {
                    Log.d("Thomas","開始配對");
                    createBondMethod.invoke(d);
                    break;
                }
            }
        }
        catch (NoSuchMethodException e) {Log.d("Thomas", e.getMessage());}
        catch (IllegalAccessException e){Log.d("Thomas", e.getMessage());}
        catch (InvocationTargetException e) {Log.d("Thomas", e.getMessage());}
    }
    public void btnSendClick(View view){
        if(outputStream!=null){
            try {
                outputStream.write(editMsg.getText().toString().getBytes("utf-8"));
                editMsg.setText("");

            } catch (IOException e) {
                Log.d("Thomas", "Send error : "+e.getMessage());
            }
        }
        else{
            Log.d("Thomas","os is null");
        }
    }
    Handler handler=new Handler(){
        @Override
        public void handleMessage(Message msg) {
            String s=txtMsg.getText().toString();
            switch(msg.what){
                case 100:
                    txtMsg.setText(s+"\n"+(String)(msg.obj));
                    break;
                case 200:
                    Toast.makeText(MainActivity.this, "Connected", Toast.LENGTH_SHORT).show();
                    break;
            }

        }
    };
    private class ReceivedThread extends Thread {
        public ReceivedThread() {
            try {
                serverSocket = btAdapter.listenUsingRfcommWithServiceRecord("Bluetooth_Socket", uuid);
            } catch (Exception e) {}
        }
        public void run() {
            try {
                Log.d("Thomas", "blocked");
                BluetoothSocket socket = serverSocket.accept();//blocking call
                inputStream = socket.getInputStream();
                outputStream = socket.getOutputStream();
            }
            catch(Exception e){
                Log.d("Thomas", "server socket close");
                Message msg=new Message();
                msg.what=200;
                handler.sendMessage(msg);
            }
            try {
                while (true) {
                    byte[] buffer = new byte[1024];
                    int count = inputStream.read(buffer);
                    Message msg = new Message();
                    msg.what=100;
                    msg.obj = new String(buffer, 0, count, "utf-8");
                    handler.sendMessage(msg);
                    Log.d("Thomas", "received");
                }
            }
            catch(IOException e){}
        }
    }
}

