package jp.agentec.abook.abv.ui.home.activity;

import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanResult;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.location.LocationManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.provider.Settings;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import jp.agentec.abook.abv.bl.common.Constant;
import jp.agentec.abook.abv.bl.common.Constant.DeviceType;
import jp.agentec.abook.abv.bl.common.log.Logger;
import jp.agentec.abook.abv.bl.dto.BluetoothPairingDeviceInfoDto;
import jp.agentec.abook.abv.cl.util.BleManagerUtil;
import jp.agentec.abook.abv.cl.util.LocationManagerUtil;
import jp.agentec.abook.abv.launcher.android.R;
import jp.agentec.abook.abv.ui.common.activity.ABVUIActivity;
import jp.agentec.abook.abv.ui.common.util.ABVToastUtil;
import jp.agentec.abook.abv.ui.home.adapter.BleListAdapter;
import jp.agentec.abook.abv.ui.home.adapter.BleListRowData;
import jp.agentec.abook.abv.ui.home.adapter.common.SectionHeaderData;
import jp.agentec.abook.abv.ui.home.helper.ABookPermissionHelper;
import jp.agentec.adf.util.CollectionUtil;

public class BlePairingSettingActivity extends ABVUIActivity {
    private static final String TAG = "BlePairingSettingActivity";

    // 定数
    private static final int    REQUEST_ENABLEBLUETOOTH = 1; // Bluetooth機能の有効化要求時の識別コード
    private static final long   SCAN_PERIOD             = 20000;    // スキャン時間。単位はミリ秒。

    private static final String CENTER_THERMOMETE_DEVICE_NAME = "MF500";    // 中心温度計のデバイス名
    private static final String RADIATION_THERMOMETE_DEVICE_NAME = "IR-TB"; // 放射温度計のデバイス名

    // メンバー変数
    private Handler             mHandler;  // UIスレッド操作ハンドラ : 「一定時間後にスキャンをやめる処理」で必要
    private boolean            mScanning = false;  // スキャン中かどうかのフラグ
    private Button              mButton_Scan;
    private BleManagerUtil      bleManagerUtil;
    private BleListAdapter      mBleListAdapter;  // Adapter
    private List<BluetoothDevice> mScanDeviceInfoList = new ArrayList<BluetoothDevice>();

    private List<String> mSavedDeviceAddressList = new ArrayList<String>(); //登録した端末アドレス

    // デバイススキャンコールバック
    private ScanCallback mLeScanCallback = new ScanCallback() {
        // スキャンに成功（アドバタイジングは一定間隔で常に発行されているため、本関数は一定間隔で呼ばれ続ける）
        @Override
        public void onScanResult( int callbackType, final ScanResult result ) {
            super.onScanResult( callbackType, result );
            runOnUiThread( new Runnable() {
                @Override
                public void run() {
                    BluetoothDevice device = result.getDevice();
                    if (device.getName() != null) {
                        Logger.d("mScanCallback device.getName() = " + device.getName());
                    }
                    // 識別商品名に絞る
                    if(device.getName() != null && (device.getName().startsWith(CENTER_THERMOMETE_DEVICE_NAME) || device.getName().startsWith(RADIATION_THERMOMETE_DEVICE_NAME))) {
                        if (!mSavedDeviceAddressList.contains(device.getAddress())) { //登録されたデバイスの場合、スキャン情報から除外する。
                            boolean isAdd = true;
                            for (BluetoothDevice savedDevice : mScanDeviceInfoList) {
                                if (savedDevice.getAddress().equals(device.getAddress())) {
                                    // スキャンされたデバイス情報リストから一つでも一致する場合、既にスキャンされたと見做し追加しない。
                                    isAdd = false;
                                }
                            }

                            if (isAdd) {
                                mScanDeviceInfoList.add(device);
                            }
                            reloadListView();
                        }
                        Logger.d("device.getName() = " + device.getName() + "device.getAddress() = " + device.getAddress() );
                    }
                }
            } );
        }

        // スキャンに失敗
        @Override
        public void onScanFailed( int errorCode ) {
            super.onScanFailed( errorCode );
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        Logger.i(TAG, "onCreate");
        super.onCreate(savedInstanceState);
        setContentView(R.layout.pairing_setting);

        TextView deviceTitle = (TextView) findViewById(R.id.device_toolbar_title);
        deviceTitle.setText(getString(R.string.chino_machine));

        // 戻り値の初期化
        setResult( Activity.RESULT_CANCELED );

        List<SectionHeaderData> sectionList = getSectionListInfo();
        List<List<BleListRowData>> rowList = getRowListInfo();
        mBleListAdapter = new BleListAdapter( this, sectionList, rowList, new BleListAdapter.BleListAdapterListener() {  // ビューアダプターの初期化
            @Override
            public void onDeleteConnectInfo(BleListRowData rowData) { // 登録されたデバイス情報削除
                Logger.i(rowData.deviceAddress);
                Integer deviceType = null;
                if (rowData.title.startsWith(CENTER_THERMOMETE_DEVICE_NAME)) {
                    deviceType = DeviceType.centerThermomete;
                } else if (rowData.title.startsWith(RADIATION_THERMOMETE_DEVICE_NAME)) {
                    deviceType = DeviceType.radiationThermomete;
                }

                if (deviceType != null) {
                    // 機器連携の情報をローカルに削除する。
                    getABVUIDataCache().removePairingBluetoothDeviceInfo(deviceType);
                }
                // 保存済みのアドレスを管理するメンバー変数も削除
                mSavedDeviceAddressList.remove(rowData.deviceAddress);
                reloadListView();
                //スキャン実行中ではない場合はスキャン実行
                if (!mScanning) {
                    startScan();
                }
            }
        });


        // Bluetoothと接続処理する
        bleManagerUtil = new BleManagerUtil(this, null);
        bleManagerUtil.startDeviceInfo();

//        bleManagerUtil.mBluetoothAdapter.startDiscovery();

        ListView listView = (ListView) findViewById(R.id.devicelist);  // リストビューの取得
        listView.setAdapter(mBleListAdapter);  // リストビューにビューアダプターをセット
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position,
                                    long id) {
                Logger.d(TAG, "position = " + position);
                BleListRowData bleListRowData = (BleListRowData)parent.getItemAtPosition(position);
                // 既に保存されてる場合は何もしない
                if (!bleListRowData.isSaved) {
                    localSaveDeviceInfo(bleListRowData);
                }
            }
        });

        // Reload Button
        mButton_Scan = (Button)findViewById( R.id.btn_reload );
        mButton_Scan.setAllCaps(false);
        mButton_Scan.setText(getString(R.string.pairing_search_scan));
        mButton_Scan.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mScanning) {
                    stopScan();
                } else {
                    startScan();
                }
            }
        });

        // UIスレッド操作ハンドラの作成（「一定時間後にスキャンをやめる処理」で使用する）
        mHandler = new Handler();
    }

    // 初回表示時、および、ポーズからの復帰時
    @Override
    protected void onResume() {
        super.onResume();
        //画面表示時にスキャン実行
        startScan();
    }

    // 別のアクティビティ（か別のアプリ）に移行したことで、バックグラウンドに追いやられた時
    @Override
    protected void onPause() {
        super.onPause();

        // スキャンの停止
        stopScan();
    }

    // 機能の有効化ダイアログの操作結果
    // 機能の有効化ダイアログの操作結果
    @Override
    protected void onActivityResult( int requestCode, int resultCode, Intent data ) {
        switch (requestCode) {
            case REQUEST_ENABLEBLUETOOTH: // Bluetooth有効化要求
                if( Activity.RESULT_CANCELED == resultCode ) {    // 有効にされなかった
                    ABVToastUtil.showMakeText(getApplicationContext(),  String.format(getString(R.string.msg_scan_bluetooth_no_allow), getString(R.string.chino_machine)), Toast.LENGTH_SHORT);
                    return;
                }
                break;
        }
        super.onActivityResult( requestCode, resultCode, data );
    }

    // スキャンの開始
    private void startScan() {
        //BlueTooth許可チェック
        if (!requestBluetoothFeature()) return;

        //端末側の位置情報許可チェッ
        if (!LocationManagerUtil.isLocationGpsEnabled(this)) {
            showSimpleAlertDialog(R.string.chino_machine, R.string.msg_location_device_no_allow);
            return;
        }

        ABookPermissionHelper helper = new ABookPermissionHelper(this, Constant.ABookPermissionType.AccessFineLocation, null);
        //アプリ側の位置情報許可チェック（置くだけセンサーとLinkingアプリの通信できないため）
        if (!helper.checkMultiPermissions(true)) return;

        // BluetoothLeScannerの取得
        // ※Runnableオブジェクト内でも使用できるようfinalオブジェクトとする。
        BluetoothLeScanner scanner = null;
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
            scanner = bleManagerUtil.mBluetoothAdapter.getBluetoothLeScanner();
        }
        if (scanner == null) {
            return;
        }

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            scanner.startScan(mLeScanCallback);
        }



        // スキャン開始（一定時間後にスキャン停止する）
        mHandler.postDelayed( new Runnable() {
            @Override
            public void run() {
                stopScan();
                Logger.d(TAG, "scan in 20 sec");
            }
        }, SCAN_PERIOD );

        mScanning = true;

        mButton_Scan.setText(getString(R.string.pairing_search_stop));
        reloadListView();
        Logger.d(TAG, "start scan !!");
    }

    // スキャンの停止
    private void stopScan() {
        // 一定期間後にスキャン停止するためのHandlerのRunnableの削除
        mHandler.removeCallbacksAndMessages( null );

        // BluetoothLeScannerの取得
        BluetoothLeScanner scanner = null;
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
            scanner = bleManagerUtil.mBluetoothAdapter.getBluetoothLeScanner();
        }
        if(scanner == null) {
            return;
        }

        mScanning = false;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            scanner.stopScan( mLeScanCallback );
        }
        mButton_Scan.setText(getString(R.string.pairing_search_scan));
        reloadListView();
        Logger.d(TAG, "stop scan !!");
    }

    private void localSaveDeviceInfo(BleListRowData bleListRowData) {
        // アドレスが保存されてる場合無視
        if (!mSavedDeviceAddressList.contains(bleListRowData.deviceAddress)) {
            mSavedDeviceAddressList.add(bleListRowData.deviceAddress);

            BluetoothPairingDeviceInfoDto pairingDeviceInfo = new BluetoothPairingDeviceInfoDto();
            if (bleListRowData.title.startsWith(CENTER_THERMOMETE_DEVICE_NAME)) {
                // デバイス名がMF500から始まると中心温度計と見做す。
                pairingDeviceInfo.deviceType = DeviceType.centerThermomete;
            } else if (bleListRowData.title.startsWith(RADIATION_THERMOMETE_DEVICE_NAME)) {
                // デバイス名がIR-TBから始まると放射温度計と見做す。
                pairingDeviceInfo.deviceType = DeviceType.radiationThermomete;
            }

            // 上記のdeviceTypeがセットされた場合のみ、ローカルのxmlに保存する
            if (pairingDeviceInfo.deviceType != null) {
                pairingDeviceInfo.deviceName = bleListRowData.title;
                pairingDeviceInfo.deviceAddress = bleListRowData.deviceAddress;
                // 機器連携の情報をローカルに保存する。
                getABVUIDataCache().setPairingBluetoothDeviceInfo(pairingDeviceInfo);
            }

            // スキャンされた情報から保存されたのでdeviceは削除
            for (BluetoothDevice savedScanDevice : mScanDeviceInfoList) {
                if (savedScanDevice.getAddress().equals(bleListRowData.deviceAddress)) {
                    mScanDeviceInfoList.remove(savedScanDevice);
                    break;
                }
            }

            //画面リロード
            reloadListView();
        }
    }

    // 閉じるボタンの処理
    public void onClickCloseView(View v) {
        finish();
    }

    /**
     * ListViewのSectionデータを作成する。
     * @return Rowデータリスト
     */
    private List<SectionHeaderData> getSectionListInfo() {
        List<SectionHeaderData> sectionList = new ArrayList<>();

        List<BluetoothPairingDeviceInfoDto> bluetoothPairingInfoDtoList = getABVUIDataCache().getPairingBluetoothDeviceInfoList(Arrays.asList(DeviceType.centerThermomete, DeviceType.radiationThermomete));
        if (CollectionUtil.isNotEmpty(bluetoothPairingInfoDtoList)) {
            for (BluetoothPairingDeviceInfoDto bluetoothPairingDeviceInfoDto : bluetoothPairingInfoDtoList) {
                // ペアリング情報が既に保存されてる場合はヘッダー情報を各機器毎に追加する
                if (bluetoothPairingDeviceInfoDto.deviceType.equals(DeviceType.centerThermomete)) {
                    sectionList.add(new SectionHeaderData(String.format(getString(R.string.pairing_save_machine), getString(R.string.center_thermometer))));
                } else if (bluetoothPairingDeviceInfoDto.deviceType.equals(DeviceType.radiationThermomete)) {
                    sectionList.add(new SectionHeaderData(String.format(getString(R.string.pairing_save_machine), getString(R.string.radiation_thermometer))));
                }
            }
        }
        // その他のヘッダー情報追加
        sectionList.add(new SectionHeaderData(String.format(getString(mScanning ? R.string.pairing_other_machine_searching : R.string.pairing_other_machine), getString(R.string.chino_machine))));

        return sectionList;
    }

    /**
     * ListViewのRowデータを作成する。
     * @return Rowデータリスト
     */
    private List<List<BleListRowData>> getRowListInfo() {
        List<List<BleListRowData>> rowList = new ArrayList<List<BleListRowData>>();
        // 引数で指定したタイプリストのペアリング情報を取得
        List<BluetoothPairingDeviceInfoDto> bluetoothPairingInfoDtoList = getABVUIDataCache().getPairingBluetoothDeviceInfoList(Arrays.asList(DeviceType.centerThermomete, DeviceType.radiationThermomete));

        if (CollectionUtil.isNotEmpty(bluetoothPairingInfoDtoList)) {
            for (BluetoothPairingDeviceInfoDto bluetoothPairingDeviceInfoDto : bluetoothPairingInfoDtoList) {
                List<BleListRowData> rowDataList = new ArrayList<BleListRowData>();
                BleListRowData rowData = new BleListRowData(bluetoothPairingDeviceInfoDto.deviceName, bluetoothPairingDeviceInfoDto.deviceAddress, true);
                rowDataList.add(rowData);

                rowList.add(rowDataList);
                // 保存された情報であれば、メンバー変数で管理するため、listに追加、既に存在する場合は何もしない
                if (!mSavedDeviceAddressList.contains(bluetoothPairingDeviceInfoDto.deviceAddress)) {
                    mSavedDeviceAddressList.add(bluetoothPairingDeviceInfoDto.deviceAddress);
                }
            }
        }

        if (mScanDeviceInfoList.size() == 0) {
            List<BleListRowData> scanRowDataList = new ArrayList<BleListRowData>();
            BleListRowData scanRowData = new BleListRowData(""  , "" );
            scanRowDataList.add(scanRowData);
            rowList.add(scanRowDataList);
        } else {
            List<BleListRowData> scanRowDataList = new ArrayList<BleListRowData>();
            for (BluetoothDevice bleDevice : mScanDeviceInfoList) {
                String labelDeviceName = "";
                if (bleDevice.getName().startsWith(CENTER_THERMOMETE_DEVICE_NAME)) {
                    labelDeviceName = getString(R.string.center_thermometer);
                } else if (bleDevice.getName().startsWith(RADIATION_THERMOMETE_DEVICE_NAME)) {
                    labelDeviceName = getString(R.string.radiation_thermometer);
                }
                BleListRowData scanRowData = new BleListRowData(bleDevice.getName(), labelDeviceName, bleDevice.getAddress(), false);
                scanRowDataList.add(scanRowData);
            }
            rowList.add(scanRowDataList);
        }

        return rowList;
    }

    /**
     * ListViewをリロードする。
     */
    private void reloadListView() {
        List<SectionHeaderData> sectionList = getSectionListInfo();
        List<List<BleListRowData>> rowList = getRowListInfo();
        mBleListAdapter.setItem(sectionList, rowList);
    }


    // デバイスのBluetooth機能の有効化要求
    private boolean requestBluetoothFeature() {
        if(bleManagerUtil.mBluetoothAdapter.isEnabled()) {
            return true;
        }
        // デバイスのBluetooth機能が有効になっていないときは、有効化要求（ダイアログ表示）
        Intent enableBtIntent = new Intent( BluetoothAdapter.ACTION_REQUEST_ENABLE );
        startActivityForResult( enableBtIntent, REQUEST_ENABLEBLUETOOTH );
        return false;
    }

}
