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

import android.app.Activity;
import android.app.Dialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
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.view.Window;
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.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.data.dao.AbstractDao;
import jp.agentec.abook.abv.bl.data.dao.SppDeviceDao;
import jp.agentec.abook.abv.bl.dto.BluetoothPairingDeviceInfoDto;
import jp.agentec.abook.abv.bl.dto.SppDeviceDto;
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.SelectSppDeviceAdapter;
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;
import jp.agentec.adf.util.StringUtil;

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

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

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

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

    private BroadcastReceiver mBluetoothSearchReceiver;

    // SPP通信端末の選択リストダイアログ
    private Dialog mSelectSppDeviceListDialog;

    // SPP通信端末のDaoクラス
    private SppDeviceDao mSppDeviceDao = AbstractDao.getDao(SppDeviceDao.class);



    @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.spp_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.d(TAG, String.format("[deleteConnectInfo] title : %s, address : %s", rowData.title, rowData.deviceAddress));
                // ペアリング情報をクリアする。
                mSppDeviceDao.clearPairingDevice(rowData.deviceAddress);

                // 保存済みのアドレスを管理するメンバー変数も削除
                mSavedDeviceAddressList.remove(rowData.deviceAddress);
                reloadListView();
                //スキャン実行中ではない場合はスキャン実行
                if (!mScanning) {
                    startScan();
                }
            }
        });

        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();
                }
            }
        });

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

        // 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.spp_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.spp_machine, R.string.msg_location_device_no_allow);
            return;
        }

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

        //インテントフィルターとBroadcastReceiverの登録
        IntentFilter filter = new IntentFilter();
        filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
        filter.addAction(BluetoothDevice.ACTION_FOUND);
        mBluetoothSearchReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                if (BluetoothDevice.ACTION_FOUND.equals(intent.getAction())) {
                    // 取得したbluetooth情報を取得
                    BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                    // 識別商品名に絞る
                    if (device.getName() != null) {
                        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());
                    }
                } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(intent.getAction())) {
                    Logger.d("-------ACTION_DISCOVERY_FINISHED");
                    // startDiscoveryのスキャン時間が12秒であるため、再度スタートさせる（20秒のタイマーが別であるため無限には実行しない)
                    bleManagerUtil.mBluetoothAdapter.startDiscovery();
                }
            }
        };

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
            registerReceiver(mBluetoothSearchReceiver, filter, RECEIVER_EXPORTED);
        } else {
            registerReceiver(mBluetoothSearchReceiver, filter);
        }

        // bluetoothAdapterから発見開始行う（結果はブロードキャストで取得 mBluetoothSearchReceiver）
        bleManagerUtil.mBluetoothAdapter.startDiscovery();

        // スキャン開始（一定時間後にスキャン停止する）
        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 );
        if (mBluetoothSearchReceiver != null) {
            unregisterReceiver(mBluetoothSearchReceiver);
            mBluetoothSearchReceiver = null;
        }

        mScanning = false;
        mButton_Scan.setText(getString(R.string.pairing_search_scan));
        reloadListView();
        Logger.d(TAG, "stop scan !!");
    }

    /**
     * SPP通信の端末選択ダイアログ表示処理
     * @param rowData bluetooth情報
     */
    private void showSelectSppDeviceListDialog(final BleListRowData rowData) {
        if (mSelectSppDeviceListDialog == null) {
            mSelectSppDeviceListDialog = new Dialog(this);
            mSelectSppDeviceListDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
            mSelectSppDeviceListDialog.setCanceledOnTouchOutside(false);
            mSelectSppDeviceListDialog.setContentView(R.layout.bluetooth_device_select_dialog);

            mSelectSppDeviceListDialog.findViewById(R.id.closeBtn).setOnClickListener(new View.OnClickListener() {

                @Override
                public void onClick(View v) {
                    mSelectSppDeviceListDialog.dismiss();
                }
            });
        }

        ListView listView = (ListView) mSelectSppDeviceListDialog.findViewById(R.id.listView1);
        final List<SppDeviceDto> sppDeviceDtoList = mSppDeviceDao.getAllSppDevice();
        listView.setAdapter(new SelectSppDeviceAdapter(this, sppDeviceDtoList));

        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                mSelectSppDeviceListDialog.dismiss();
                // タップしたポジションの端末情報を取得
                SppDeviceDto selectedSppDeviceDto = sppDeviceDtoList.get(position);
                // 取得したデータのペアリングが既に存在し、ペアリング情報が一致しない場合上書きと見做す。
                if (!StringUtil.isNullOrEmpty(selectedSppDeviceDto.pairingDeviceAddress)) {
                    if (!selectedSppDeviceDto.pairingDeviceAddress.equals(rowData.deviceAddress)) {
                        mSavedDeviceAddressList.remove(selectedSppDeviceDto.pairingDeviceAddress);
                    }
                }

                // ペアリング情報をセットして、更新する
                selectedSppDeviceDto.pairingDeviceName = rowData.title;
                selectedSppDeviceDto.pairingDeviceAddress = rowData.deviceAddress;
                mSppDeviceDao.updateSppDevice(sppDeviceDtoList.get(position));

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

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

        if (mSelectSppDeviceListDialog != null) {
            mSelectSppDeviceListDialog.show();
        }
    }

    private void localSaveDeviceInfo(BleListRowData bleListRowData) {
        // アドレスが保存されてる場合無視
        if (!mSavedDeviceAddressList.contains(bleListRowData.deviceAddress)) {
            // 選択ダイアログ表示
            showSelectSppDeviceListDialog(bleListRowData);
        }
    }

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

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

        // SPP通信端末の情報を取得
        List<SppDeviceDto> sppDeviceDtoList = mSppDeviceDao.getPairingDeviceList();
        if (CollectionUtil.isNotEmpty(sppDeviceDtoList)) {
            for (SppDeviceDto dto : sppDeviceDtoList) {
                sectionList.add(new SectionHeaderData(String.format(getString(R.string.pairing_save_machine), dto.sppDeviceName)));
            }
        }

        // その他のヘッダー情報追加
        sectionList.add(new SectionHeaderData(String.format(getString(mScanning ? R.string.pairing_other_machine_searching : R.string.pairing_other_machine), getString(R.string.spp_machine))));
        return sectionList;
    }

    /**
     * ListViewのRowデータを作成する。
     * @return Rowデータリスト
     */
    private List<List<BleListRowData>> getRowListInfo() {
        List<List<BleListRowData>> rowList = new ArrayList<List<BleListRowData>>();
        // SPP通信機器のペアリングデバイス情報を取得
        List<SppDeviceDto> sppDeviceDtoList = mSppDeviceDao.getPairingDeviceList();
        if (CollectionUtil.isNotEmpty(sppDeviceDtoList)) {

            for (SppDeviceDto dto : sppDeviceDtoList) {
                List<BleListRowData> rowDataList = new ArrayList<BleListRowData>();
                rowDataList.add(new BleListRowData(dto.pairingDeviceName, dto.pairingDeviceAddress, true));
                rowList.add(rowDataList);
                // 保存された情報であれば、メンバー変数で管理するため、listに追加、既に存在する場合は何もしない
                if (!mSavedDeviceAddressList.contains(dto.pairingDeviceAddress)) {
                    mSavedDeviceAddressList.add(dto.pairingDeviceAddress);
                }
            }
        }

        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) {
                BleListRowData scanRowData = new BleListRowData(bleDevice.getName(), 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;
    }
}
