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

import android.app.Activity;
import android.app.PendingIntent;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.AssetFileDescriptor;
import android.location.LocationManager;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.nfc.NdefMessage;
import android.nfc.NfcAdapter;
import android.os.Build;
import android.os.Bundle;
import android.os.Parcelable;
import android.provider.Settings;

import com.nttdocomo.android.sdaiflib.BeaconData;
import com.nttdocomo.android.sdaiflib.BeaconReceiverBase;
import com.nttdocomo.android.sdaiflib.BeaconScanner;
import com.nttdocomo.android.sdaiflib.Define;

import org.json.adf.JSONObject;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import jp.agentec.abook.abv.bl.common.CommonExecutor;
import jp.agentec.abook.abv.bl.common.Constant.ABookPermissionType;
import jp.agentec.abook.abv.bl.common.constant.ABookKeys;
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.SppDeviceDto;
import jp.agentec.abook.abv.cl.util.BleManagerUtil;
import jp.agentec.abook.abv.cl.util.LocationManagerUtil;
import jp.agentec.abook.abv.cl.util.SppBluetoothConnectThread;
import jp.agentec.abook.abv.cl.util.YamatoBluetoothReceiveTask;
import jp.agentec.abook.abv.launcher.android.R;
import jp.agentec.abook.abv.ui.common.dialog.ABookAlertDialog;
import jp.agentec.abook.abv.ui.common.util.AlertDialogUtil;
import jp.agentec.abook.abv.ui.home.activity.BarCodeReaderActivity;
import jp.agentec.abook.abv.ui.home.helper.ABookPermissionHelper;
import jp.agentec.adf.util.NumericUtil;
import jp.agentec.adf.util.StringUtil;

public class ABVCheckContentViewActivity extends ABVContentViewActivity {
    private static final String TAG ="ABVCheckContentViewActivity";
    //置くだけセンサースキャナー
    private BeaconScanner mScanner;

    //置くだけセンサーBeacon受信
    private BeaconReceiver mReceiver;

    //置くだけセンサースキャン状態
    protected boolean isBeaconScaning = false;

    //デフォルトのスキャンモード（0:高精度モード , 1:通常モード, 2:省電力モード, 3:通常モード）
    //通常モードが一番早くBeacon受信できるのでデフォルト値を3も設定
    private static final int DEFAULT_SCAN_MODE = 3;
    private static final String LOG_SEPARATOR = "\n========================\n";
    private static final SimpleDateFormat SDF = new SimpleDateFormat("HH:mm:ss.SSS", Locale.JAPANESE);

    //置くだけセンサーのサービスID
    private static final int OKUDAKE_SERVICE_ID_TEMPERATURE = 1;
    private static final int OKUDAKE_SERVICE_ID_HUMIDITY = 2;

    // 定数
    private static final int REQUEST_CODE_ENABLEBLUETOOTH_CENTER_TEMPERATURE = 2001;  // Bluetooth機能の有効化要求時の識別コード(中心温度計)
    private static final int REQUEST_CODE_ENABLEBLUETOOTH_OKUDAKE = 2002;  // Bluetooth機能の有効化要求時の識別コード
    private static final int REQUEST_CODE_BARCODE_READER  = 2003;  // バーコードリーダの職別コード
    private static final int REQUEST_CODE_ENABLEBLUETOOTH_RADIATION_TEMPERATURE  = 2004;  // Bluetooth機能の有効化要求時の識別コード(放射温度計)
    private static final int REQUEST_CODE_ENABLEBLUETOOTH_SPP_MACHINE = 2005;  // Bluetooth機能の有効化要求時の識別コード(SPP通信機器)

    // メンバー変数
    private BleManagerUtil bleManagerUtil;  // Bluetoothの接続

    // 機器連携のコマンドの設問ID
    public String mQid = "";

    //待ち状態の時画面に表示するダイアログ
    protected ABookAlertDialog mWaitingDialog;

    //置くだけセンサースキャンするデバイスID
    private int mScaningDeviceId;

    //置くだけセンサースキャンするデバイス情報タイプ（１：温度、２：湿度）
    private int mScaningServiceId;

    // デバイスタイプ
    private int mDeviceType;
    // メディアプレイヤー
    private MediaPlayer mMediaPlayer;

    // bluetoothアダプタ
    private BluetoothAdapter mBluetoothAdapter;

    // 接続を切った時、エラーが発生するので、ダイアログ表示しないようにフラグに保持
    private boolean mDisConnectSppBluetoothFlg;

    // 大和機器専用、bluetoothで値取得タスク
    private YamatoBluetoothReceiveTask mYamatoReceiveTask;

    // SPPbluetooth接続スレッド
    private SppBluetoothConnectThread mSppBluetoothConnectThread;

    // NFCアダプタを扱うための変数
    private NfcAdapter mNfcAdapter;

    // SPP通信端末のデータベース管理クラス
    private SppDeviceDao mSppDeviceDao = AbstractDao.getDao(SppDeviceDao.class);

    // SPP通信機器のデバイスID（t_spp_device)
    private Integer mSppDeviceId;

    /**
     *  Beaconスキャン結果受信Receiver.
     */
    private class BeaconReceiver extends BeaconReceiverBase {
        @Override
        protected void onReceiveScanResult(BeaconData data) {
            //選択されたデバイスIDから端末検索
            if (data.getExtraId() == mScaningDeviceId) {
                String value = "-1";
                switch (mScaningServiceId) {
                    case OKUDAKE_SERVICE_ID_TEMPERATURE:
                        value = String.valueOf(data.getTemperature());
                        break;
                    case OKUDAKE_SERVICE_ID_HUMIDITY:
                        value = String.valueOf(data.getHumidity());
                        break;
                    default:
                        value = String.valueOf(data.getTemperature());
                        break;
                }
                //HTML側に値送信
                successAfterAbookCheckAip(value);
                //置くだけセンサーのスキャン中止
                stopOkudakeBeaconScan();

                //待機中のダイヤログ非表示
                dismissWaitngDialog();
            }
            //デバイス情報ログ出力
            StringBuilder sb = new StringBuilder();
            sb.append(LOG_SEPARATOR);
            sb.append("\nビーコンスキャン結果");
            sb.append("\n通知時刻: " + SDF.format(new Date()));
            sb.append("\n検出時刻: " + SDF.format(new Date(data.getTimestamp())));
            sb.append("\nベンダ識別子: " + data.getVendorId());
            sb.append("\n個別番号: " + data.getExtraId());
            sb.append("\nRSSI値: " + data.getRssi());
            sb.append("\nバージョン: " + data.getVersion());
            sb.append("\n距離種別: " + data.getDistance());
            sb.append("\nTxパワー: " + data.getTxPower());
            sb.append("\n温度(℃): " + data.getTemperature());
            sb.append("\n湿度(％): " + data.getHumidity());
            sb.append("\n気圧(hPa): " + data.getAtmosphericPressure());
            sb.append("\n電池残量低下(要充電)フラグ: " + data.getLowBattery());
            sb.append("\n電池残量(％): " + data.getBatteryPower());
            sb.append("\nボタン識別子: " + data.getButtonId());
            sb.append("\n開閉フラグ: " + data.getOpenCloseSensor());
            sb.append("\n人感反応有無フラグ: " + data.getHumanSensor());
            sb.append("\nRawデータ(ビーコンサービスID 8): " + data.getRawData8());
            sb.append("\nRawデータ(ビーコンサービスID 9): " + data.getRawData9());
            sb.append("\nRawデータ(ビーコンサービスID 10): " + data.getRawData10());
            sb.append("\nRawデータ(ビーコンサービスID 11): " + data.getRawData11());
            sb.append("\nRawデータ(ビーコンサービスID 12): " + data.getRawData12());
            sb.append("\nRawデータ(ビーコンサービスID 13): " + data.getRawData13());
            sb.append("\nRawデータ " + data.getRawData());
            sb.append('\n');
            Logger.d(sb.toString());
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        /** 置くだけセンサーデバイス関連 開始 **/
        //ビーコンスキャナー
        mScanner = new BeaconScanner(this);

        //ビーコンレシーバー
        mReceiver = new BeaconReceiver();

        //Filter
        IntentFilter filter = new IntentFilter();
        filter.addAction(Define.filterBeaconScanResult);
        filter.addAction(Define.filterBeaconScanState);

        //Beacon受信開始
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
            registerReceiver(mReceiver, filter, RECEIVER_NOT_EXPORTED);
        } else {
            registerReceiver(mReceiver, filter);
        }
        /** 置くだけセンサーデバイス関連 終了 **/

        /** 中心温度計デバイス関連 開始 **/
        bleManagerUtil = new BleManagerUtil(this, new BleManagerUtil.BleManagerUtilListener() {
            @Override
            public void onConnectionError(int status) { //bluetooth接続エラー
                Logger.e(TAG, "onConnectionError");
                // bluetoothのデバイスタイプ（中心温度計・放射温度計）
                int bluetoothDeviceType = bleManagerUtil.getBluetoothDeviceType();
                // タイプによってメッセージ内容をセット
                if (status == 8) {
                    // タイムアウトのステータス
                    if (bluetoothDeviceType == DeviceType.centerThermomete) {
                        errorAfterAbookCheckAip(String.format(getString(R.string.msg_bluetooth_connect_timeout_error), getString(R.string.center_thermometer), String.valueOf(status)));
                    } else if (bluetoothDeviceType == DeviceType.radiationThermomete) {
                        errorAfterAbookCheckAip(String.format(getString(R.string.msg_bluetooth_connect_timeout_error), getString(R.string.radiation_thermometer), String.valueOf(status)));
                    }
                } else {
                    if (bluetoothDeviceType == DeviceType.centerThermomete) {
                        errorAfterAbookCheckAip(String.format(getString(R.string.msg_bluetooth_connect_error), getString(R.string.center_thermometer)));
                    } else if (bluetoothDeviceType == DeviceType.radiationThermomete) {
                        errorAfterAbookCheckAip(String.format(getString(R.string.msg_bluetooth_connect_error), getString(R.string.radiation_thermometer)));
                    }
                }
                bleManagerDisconnect();
            }

            @Override
            public void onConnectionState() {  // bluetooth接続成功
                Logger.d(TAG, "onConnectionState");
                //ダイアログが非表示になっても、何回呼ばれることがあるので、ダイアログのnullチェックする。
                if (mWaitingDialog != null) {
                    String message = null;
                    // bluetoothのデバイスタイプ（中心温度計・放射温度計）
                    int bluetoothDeviceType = bleManagerUtil.getBluetoothDeviceType();
                    // タイプによってメッセージ内容をセット
                    if (bluetoothDeviceType == DeviceType.centerThermomete) {
                        message = String.format(getString(R.string.msg_ble_connect_success), getString(R.string.center_thermometer));
                    } else if (bluetoothDeviceType == DeviceType.radiationThermomete) {
                        message = String.format(getString(R.string.msg_ble_connect_success), getString(R.string.radiation_thermometer));
                    }

                    if (StringUtil.isNullOrEmpty(message)) {
                        // 接続するデバイスが存在しないと見做し、接続を切る
                        bleManagerDisconnect();
                    } else {
                        mWaitingDialog.setMessage(message);
                    }
                }
            }

            @Override
            public void onDisConnectionState() {  // bluetooth接続切断
                Logger.d(TAG, "onDisConnectionState");
//                setThermometerData("");
                dismissWaitngDialog();
            }

            @Override
            public void onGetDeviceInfo(String strTemp) {  // bluetooth機器からデータ取得成功
                Logger.d(TAG, "onGetDeviceInfo temperature [%s]", strTemp);
                setThermometerData(strTemp);
                bleManagerDisconnect();
            }

            @Override
            public void onGetDeviceInfoFailed(int status) {  // bluetooth機器からデータ取得エラー
                Logger.e(TAG, "onGetDeviceInfoFailed");
                // bluetoothのデバイスタイプ（中心温度計・放射温度計）
                int bluetoothDeviceType = bleManagerUtil.getBluetoothDeviceType();
                String errorMessage = null;
                // タイプによってメッセージ内容をセット
                if (bluetoothDeviceType == DeviceType.centerThermomete) {
                    errorMessage = String.format(getString(R.string.msg_bluetooth_connect_error), getString(R.string.center_thermometer));
                } else if (bluetoothDeviceType == DeviceType.radiationThermomete) {
                    errorMessage = String.format(getString(R.string.msg_bluetooth_connect_error), getString(R.string.radiation_thermometer));
                }

                if (StringUtil.isNullOrEmpty(errorMessage)) {
                    errorAfterAbookCheckAip(errorMessage);
                }
                // bluetooth通信を切断
                bleManagerDisconnect();
                // ダイアログを閉じる
                dismissWaitngDialog();
            }
        });

        bleManagerUtil.startDeviceInfo();
        /** 中心温度計デバイス関連 終了 **/


        // アダプタのインスタンスを取得
        mNfcAdapter = NfcAdapter.getDefaultAdapter(this);

        // bluetoothAdapterがない場合、デバイスがbluetooth機能がない？？
        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        if (mBluetoothAdapter == null) {
            // エラー: Bluetooth なし.
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
    }

    @Override
    protected void onDestroy() {
        //Beacon受信停止
        unregisterReceiver(mReceiver);

        // 接続されている機器と切断する。
        bleManagerDisconnect();

        super.onDestroy();
    }

    @Override
    public void onPause() {
        super.onPause();
        if (mNfcAdapter != null) {
            // Activityがバックグラウンドになったときは、受け取らない
            mNfcAdapter.disableForegroundDispatch(this);
        }
    }

    /**
     * onNewIntentよりonPauseメソッドが先に呼ばれて、
     * onPause処理でnfc検知を受け取らない処理が入っているため、
     * nfc検知処理を受け取らない処理を入れなくてもいい
     *
     * @param intent
     */
    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        String action = intent.getAction();
        // nfcのみ対応、それ以外は無視
        if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(action)
                || NfcAdapter.ACTION_TECH_DISCOVERED.equals(action)
                || NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action))  {
            String data = readFromIntent(intent);
            if (data != null) {
                String[] dataLineSplit = data.split("\r\n");
                String[] lastLineData = dataLineSplit[dataLineSplit.length - 1].split(",");
                // "date, concentration, temperature"
                String result = lastLineData[1].replaceAll(" ", "");

                if (StringUtil.isNumber(result)) {
                    // 数値の場合、正常と見做し設問に値セット
                    setNfcData(result);
                } else {
                    // 数値以外の場合、エラーと見做す
                    Logger.e(TAG, "nfc data is error : " + result);
                    errorAfterAbookCheckAip(String.format(getString(R.string.msg_nfc_value_error), result));
                }
            } else {
                // 取得したデータがない場合、エラー表示
                errorAfterAbookCheckAip(String.format(getString(R.string.msg_bluetooth_receive_data_error), getString(R.string.nfc_communication)));
            }
            dismissWaitngDialog();
        }
    }

    /**
     * インテントからデータを読み込み、データを取得
     * @param intent
     * @return 変換したデータ
     */
    private String readFromIntent(Intent intent) {
        String action = intent.getAction();
        if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(action)
                || NfcAdapter.ACTION_TECH_DISCOVERED.equals(action)
                || NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)) {
            Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
            NdefMessage[] msgs = null;
            if (rawMsgs != null) {
                msgs = new NdefMessage[rawMsgs.length];
                for (int i = 0; i < rawMsgs.length; i++) {
                    msgs[i] = (NdefMessage) rawMsgs[i];
                }
                return parseNdfMessageString(msgs);
            }
        }
        return null;
    }

    /**
     * Ndfメッセージを文字列に変換
     * @param msgs
     * @return 変換したデータ
     */
    private String parseNdfMessageString(NdefMessage[] msgs) {
        if (msgs == null || msgs.length == 0) return null;

        String text = "";
        byte[] payload = msgs[0].getRecords()[0].getPayload();
        String textEncoding = ((payload[0] & 128) == 0) ? "UTF-8" : "UTF-16"; // Get the Text Encoding
        int languageCodeLength = payload[0] & 0063; // Get the Language Code, e.g. "en"
        // String languageCode = new String(payload, 1, languageCodeLength, "US-ASCII");

        try {
            // Get the Text
            text = new String(payload, languageCodeLength + 1, payload.length - languageCodeLength - 1, textEncoding);
        } catch (UnsupportedEncodingException e) {
            Logger.e("UnsupportedEncoding", e.toString());
        }
        return text;
    }

    @Override
    protected void onActivityResult( int requestCode, int resultCode, Intent data ) {
        switch(requestCode) {
            case REQUEST_CODE_ENABLEBLUETOOTH_CENTER_TEMPERATURE: // 中心温度計Bluetooth有効化要求
                if( Activity.RESULT_CANCELED == resultCode ) {    // 有効にされなかった
                    errorAfterAbookCheckAip(String.format(getString(R.string.msg_connect_bluetooth_no_allow), getString(R.string.center_thermometer)));
                    return;
                } else {
                    setCenterThermometerDeviceInfo();
                }
                break;
            case REQUEST_CODE_ENABLEBLUETOOTH_OKUDAKE: // 置くだけセンサーBluetooth有効化要求
                if( Activity.RESULT_CANCELED == resultCode ) {    // 有効にされなかった
                    errorAfterAbookCheckAip(String.format(getString(R.string.msg_connect_bluetooth_no_allow), getString(R.string.title_okudake_sensor)));
                    return;
                } else {
                    startOkudakeBeaconScan();
                }
                break;
            case REQUEST_CODE_BARCODE_READER:  // バーコードの要求
                if (data != null) { //バーコード画面から閉じるときにはdataがないので、値がある時のみセット
                    String value = data.getStringExtra(BarCodeReaderActivity.BARCODE_READING_DATA);
                    successAfterAbookCheckAip(value);
                }
                break;
            case REQUEST_CODE_ENABLEBLUETOOTH_RADIATION_TEMPERATURE: // 放射温度計
                if( Activity.RESULT_CANCELED == resultCode ) {    // 有効にされなかった
                    errorAfterAbookCheckAip(String.format(getString(R.string.msg_connect_bluetooth_no_allow), getString(R.string.radiation_thermometer)));
                    return;
                } else {
                    setRadiationThermometerDeviceInfo();
                }
                break;
            case REQUEST_CODE_ENABLEBLUETOOTH_SPP_MACHINE: // SPP通信機器
                if( Activity.RESULT_CANCELED == resultCode ) {    // 有効にされなかった
                    errorAfterAbookCheckAip(String.format(getString(R.string.msg_connect_bluetooth_no_allow), getString(R.string.spp_machine)));
                    return;
                } else {
                    setSppBluetoothDeviceInfo();
                }
                break;
        }
        super.onActivityResult( requestCode, resultCode, data );
    }

    /**
     * ABVContentViewActivityからの呼ばれるメッソドで各種デバイスとの連携
     * @param abookCheckParam HTML側からのパラメーター情報
     */
    @Override
    protected void getDeviceInfo(Map<String, String> abookCheckParam) {
        if (abookCheckParam.containsKey(ABookKeys.TASK_DEVICE_TYPE)) {

            mDeviceType = Integer.valueOf(abookCheckParam.get(ABookKeys.TASK_DEVICE_TYPE));  // ディバイスのタイプ取得
            mQid = abookCheckParam.get(ABookKeys.TASK_QUESTION_ID);  // 設問ID取得

            // 1:中心温度計  2:置くだけセンサー　3:バーコード 4:放射温度計 5: SPP通信機器 6: NFC通信
            if (mDeviceType == DeviceType.centerThermomete) {  // 中心温度計
                setCenterThermometerDeviceInfo();

            } else if (mDeviceType == DeviceType.sensor) {  // 置くだけセンサー
                String param1 = abookCheckParam.get(ABookKeys.TASK_DEVICE_TYPE_PARAM1);
                String param2 = abookCheckParam.get(ABookKeys.TASK_DEVICE_TYPE_PARAM2);
                if (StringUtil.isNullOrEmpty(param1) || StringUtil.isNullOrEmpty(param2)) {
                    // パラメータが存在しない場合
                    errorAfterAbookCheckAip(getString(R.string.msg_not_found_parameter));
                    return;
                }
                try {
                    mScaningDeviceId = Integer.valueOf(param1);  // デバイスID取得
                    mScaningServiceId = Integer.valueOf(param2);  // ServiceId ID取得
                } catch (NumberFormatException e) {
                    Logger.e("param is not Int", e);
                    errorAfterAbookCheckAip(getString(R.string.msg_fraud_parameter));
                    return;
                }
                startOkudakeBeaconScan();

            } else if (mDeviceType == DeviceType.barcode) {  // バーコード
                setBarcodeDeviceInfo();
            } else if (mDeviceType == DeviceType.radiationThermomete) {  // 放射温度計
                setRadiationThermometerDeviceInfo();
            } else if (mDeviceType == DeviceType.sppBluetoothMachine) {  // SPP通信機器
                String param1 = abookCheckParam.get(ABookKeys.TASK_DEVICE_TYPE_PARAM1);
                // スキームから取得したパラメータをメンバー変数のmSppDeviceIdにセット(setSppBluetoothDeviceInfoで使用)
                mSppDeviceId = Integer.valueOf(param1);

                setSppBluetoothDeviceInfo();

            } else if (mDeviceType == DeviceType.nfc) {
               setNfcDeviceInfo();
            } else {
                Logger.e("外部デバイスタイプ不正　deviceType = " + mDeviceType);
            }
        } else {
            Logger.e("外部デバイスタイプ不正　deviceType is null");
        }
    }

    /**
     * HTML側にNFC機器からのデータを転送する
     * @param strTemp
     */
    public void setNfcData(final String strTemp) {
        Logger.i("setNfcData");
        JSONObject nfcDataJson = new JSONObject();
        nfcDataJson.put(ABookKeys.TASK_QUESTION_ID, mQid);
        nfcDataJson.put("value", strTemp);
        afterABookCheckApi(mCmd, "", 0, "", nfcDataJson.toString());
    }

    /**
     * 置くだけセンサースキャン開始
     */
    private void startOkudakeBeaconScan() {
        //Linkingアプリと置くだけセンサーがBluetoothで通信するのでチェック必要
        if (requestBluetoothFeature(REQUEST_CODE_ENABLEBLUETOOTH_OKUDAKE)) {
            //端末側の位置情報許可チェック
            if (LocationManagerUtil.isLocationGpsEnabled(this)) {
                ABookPermissionHelper helper = new ABookPermissionHelper(this, ABookPermissionType.AccessFineLocation, null);

                //アプリ側の位置情報許可チェック（置くだけセンサーとLinkingアプリの通信できないため）
                if (helper.checkMultiPermissions(true)) {

                    if (!isBeaconScaning) { //スキャン中状態ではない時だけスキャン開始
                        Logger.d("startOkudakeBeaconScan mScaningServiceId = " + mScaningServiceId);
                        showWaitingDialog(getString(R.string.title_okudake_sensor), getString(R.string.pairing_search_scaning));
                        isBeaconScaning = true;
                        int[] serviceIds = new int[] { mScaningServiceId };
                        mScanner.startScan(serviceIds, DEFAULT_SCAN_MODE);
                    }
                }
            } else {
                errorAfterAbookCheckAip(getString(R.string.msg_location_device_no_allow));
            }
        }
    }

    /**
     * 置くだけセンサースキャン中止
     */
    private void stopOkudakeBeaconScan() {
        if (mScanner != null) {
            Logger.d("stopOkudakeBeaconScan");
            mScanner.stopScan();
            isBeaconScaning = false;
        }
    }

    /**
     * 中心温度計、置くだけセンサー接続の待機ダイヤログ表示
     * @param title タイトル
     * @param message 内容
     */
    private void showWaitingDialog(String title, String message) {
        //待機状態のダイヤログ表示
        mWaitingDialog = AlertDialogUtil.createAlertDialog(this, title);
        mWaitingDialog.setMessage(message);
        mWaitingDialog.setButton(DialogInterface.BUTTON_POSITIVE, getResources().getString(R.string.pairing_search_stop), new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                Logger.d(TAG, "waiting Dialog stop click : " + mDeviceType);
                switch (mDeviceType) {
                    case DeviceType.centerThermomete:
                    case DeviceType.radiationThermomete:
                        bleManagerDisconnect();  // 中心温度計接続切断
                        break;
                    case DeviceType.sensor:
                        stopOkudakeBeaconScan();  // 置くだけセンサースキャン中止
                        break;
                    case DeviceType.sppBluetoothMachine:
                        disConnectSppBluetooth();
                        // 接続を切るのに5秒ぐらい必要なので、プログレスバーを表示して5秒後に閉じる
                        showProgressPopup(getString(R.string.msg_common_processing));
                        handler.postDelayed( new Runnable() {
                            @Override
                            public void run() {
                                closeProgressPopup();
                            }
                        }, 5000 );
                        break;
                    case DeviceType.nfc:    // nfc
                        // Activityがバックグラウンドになったときは、受け取らない
                        mNfcAdapter.disableForegroundDispatch(ABVCheckContentViewActivity.this);
                        break;
                }
                successAfterAbookCheckAip("");
                mWaitingDialog = null;
            }
        });
        mWaitingDialog.show();
    }

    /**
     * 中心温度計、置くだけセンサー接続の待機ダイヤログ非表示
     */
    private void dismissWaitngDialog() {
        if (mWaitingDialog != null) {
            mWaitingDialog.dismiss();
            mWaitingDialog = null;
        }
    }
    /**
     * BLEディバイスの中心温度計の情報取得
     */
    private void setCenterThermometerDeviceInfo() {
        if (requestBluetoothFeature(REQUEST_CODE_ENABLEBLUETOOTH_CENTER_TEMPERATURE)) { //端末のBluetooth設定を確認

            String deviceAddress = getABVUIDataCache().getPairingBluetoothDeviceAddress(DeviceType.centerThermomete);
            if (StringUtil.isNullOrEmpty(deviceAddress)) {
                // 登録されている中心温度計がない場合
                errorAfterAbookCheckAip(String.format(getString(R.string.msg_pairing_device_no_info), getString(R.string.center_thermometer)));

                return;  // 以下の処理にかからないようにreturnする
            }
            // 登録されている中心温度計がある
            showWaitingDialog(getString(R.string.center_thermometer), getString(R.string.ble_connecting));
            // 接続
            bleManagerUtil.connect(DeviceType.centerThermomete, deviceAddress);
        }
    }

    /**
     * BLEディバイスの放射温度計の情報取得
     */
    private void setRadiationThermometerDeviceInfo() {
        if (requestBluetoothFeature(REQUEST_CODE_ENABLEBLUETOOTH_RADIATION_TEMPERATURE)) { //端末のBluetooth設定を確認
            String deviceAddress = getABVUIDataCache().getPairingBluetoothDeviceAddress(DeviceType.radiationThermomete);
            if (StringUtil.isNullOrEmpty(deviceAddress)) {
                // 登録されている放射温度計がない場合
                errorAfterAbookCheckAip(String.format(getString(R.string.msg_pairing_device_no_info), getString(R.string.radiation_thermometer)));

                return; // 以下の処理にかからないようにreturnする
            }

            // 登録されている放射温度計がある
            showWaitingDialog(getString(R.string.radiation_thermometer), getString(R.string.ble_connecting));
            // 接続
            bleManagerUtil.connect(DeviceType.radiationThermomete, deviceAddress);
        }
    }

    /**
     * SPP機器の通信情報をセット
     */
    private void setSppBluetoothDeviceInfo() {
        if (requestBluetoothFeature(REQUEST_CODE_ENABLEBLUETOOTH_SPP_MACHINE)) { //端末のBluetooth設定を確認
            final SppDeviceDto sppDeviceDto = mSppDeviceDao.getSppDeviceById(mSppDeviceId);
            if (sppDeviceDto == null || StringUtil.isNullOrEmpty(sppDeviceDto.pairingDeviceAddress)) {
                // 登録されているSPP通信機器がない場合
                errorAfterAbookCheckAip(String.format(getString(R.string.msg_pairing_device_no_info), getString(R.string.spp_machine)));
                return;  // 以下の処理にかからないようにreturnする
            }

            // 登録されているSPP通信機器がある時、接続する
            showWaitingDialog(getString(R.string.spp_machine), getString(R.string.ble_connecting));

            final BluetoothDevice bluetoothDevice = mBluetoothAdapter.getRemoteDevice(sppDeviceDto.pairingDeviceAddress);
            if (bluetoothDevice != null) {
                Logger.d(TAG, "----bluetoothDevice is not null");
                // 既に接続している場合、端末アドレスが一致すれば、接続済みと見做す。
                if (mSppBluetoothConnectThread != null && mSppBluetoothConnectThread.getConnectedAddress().equals(bluetoothDevice.getAddress())) {
                    Logger.d(TAG, "----device address Same");
                    // 接続完了後、処理
                    if (mWaitingDialog != null) {
                        handler.post(new Runnable() {
                            @Override
                            public void run() {
                                mWaitingDialog.setMessage(String.format(getString(R.string.msg_ble_connect_success), sppDeviceDto.sppDeviceName));
                            }
                        });
                    }
                } else {    // 初回のbluetooth接続・bluetooth対象アドレスが異なる場合、新規で接続するようにする。
                    // 初回ではない場合はbluetoothを一度接続を切る。
                    if (mSppBluetoothConnectThread != null) {
                        Logger.d(TAG, "address diff change bluetoothThread");
                        disConnectSppBluetooth();
                        handler.postDelayed(new Runnable() {
                            @Override
                            public void run() {
                                setSppBluetoothThread(bluetoothDevice, sppDeviceDto);
                            }
                        }, 5000);
                    } else {
                        Logger.d(TAG, "new connect spp bluetooth");
                        setSppBluetoothThread(bluetoothDevice, sppDeviceDto);
                    }
                }
            }
        }
    }

    private void setSppBluetoothThread(final BluetoothDevice bluetoothDevice, final SppDeviceDto sppDeviceDto) {
        // 接続が切れた時、tureにセットするため、接続起動時falseに初期化する。
        mDisConnectSppBluetoothFlg = false;

        // 接続
        CommonExecutor.execute(new Runnable() {
            @Override
            public void run() {
                mSppBluetoothConnectThread = new SppBluetoothConnectThread(bluetoothDevice, new SppBluetoothConnectThread.bluetoothConnectThreadListener() {
                    @Override
                    public void onConnect(BluetoothSocket socket) {
                        // 接続完了後、処理
                        if (mWaitingDialog != null) {
                            handler.post(new Runnable() {
                                @Override
                                public void run() {
                                    mWaitingDialog.setMessage(String.format(getString(R.string.msg_ble_connect_success), sppDeviceDto.sppDeviceName));
                                }
                            });
                        }

                        mYamatoReceiveTask = new YamatoBluetoothReceiveTask(socket, sppDeviceDto, new YamatoBluetoothReceiveTask.BluetoothReceiveTaskListener() {
                            @Override
                            public void onGetData(String result) {
                                Logger.i(TAG, "result : " + result);
                                // ダイアログが表示されてる場合だけ、設問に値をセットする
                                if (mWaitingDialog != null && mWaitingDialog.isShowing()) {
                                    setSppBluetoothMachineData(result);
                                }
                            }

                            @Override
                            public void onFail(boolean dataFormatErrorFlg) {
                                Logger.e(TAG, "receiveTaskThread fail");
                                connectErrorSppDevice(sppDeviceDto.sppDeviceName, dataFormatErrorFlg);
                            }
                        });
                        mYamatoReceiveTask.start();
                    }

                    @Override
                    public void onFail() {
                        Logger.e(TAG, "ConnectThread fail");
                        connectErrorSppDevice(sppDeviceDto.sppDeviceName, false);
                    }
                });
                // bluetooth接続スレッド処理開始
                mSppBluetoothConnectThread.start();
            }
        });
    }

    /**
     * NFCデータ受信できるようにセット
     */
    private void setNfcDeviceInfo() {
        if (mNfcAdapter == null) {
            // デバイスがNFCをサポートしてないと見做す。
            errorAfterAbookCheckAip(String.format(getString(R.string.msg_no_support_nfc)));
            return;  // 以下の処理にかからないようにreturnする
        }

        // 端末のNFC設定が無効の場合
        if (!mNfcAdapter.isEnabled()) {
            // NFC設定画面へ遷移確認ダイアログ表示
            showNfcSettingDialog();
            return;
        }

        // NFCがかざされたときの設定
        Intent intent = new Intent(this, this.getClass());
        intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
        // ほかのアプリを開かないようにする
        PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), 0, intent, 0);
        // nfcアダプタのフォアグラウンドディスパッチを有効（onNewIntentメソッドからnfc検知を行う)
        mNfcAdapter.enableForegroundDispatch(this, pendingIntent, null, null);

        showWaitingDialog(getString(R.string.nfc_communication), getString(R.string.msg_hold_nfc_device));
    }

    /**
     * 端末のNFC設定確認
     */
    private void showNfcSettingDialog() {
        ABookAlertDialog alertDialog = AlertDialogUtil.createAlertDialog(this, "NFC");
        alertDialog.setMessage(getString(R.string.msg_no_nfc_setting));
        alertDialog.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int whichButton) {
                startActivity(new Intent(Settings.ACTION_NFC_SETTINGS));
            }
        });
        alertDialog.setNegativeButton(R.string.cancel, null);
        alertDialog.show();
    }

    /**
     * SPP通信エラー処理
     * @param deviceName
     */
    private void connectErrorSppDevice(String deviceName, boolean dataFormatErrorFlg) {
        if (!mDisConnectSppBluetoothFlg) {
            if (dataFormatErrorFlg) {
                // データ取得時のエラーはbluetoothを切断しない
                errorAfterAbookCheckAip(String.format(getString(R.string.msg_bluetooth_receive_data_error), deviceName));
            } else {
                disConnectSppBluetooth();
                errorAfterAbookCheckAip(String.format(getString(R.string.msg_bluetooth_connect_error), deviceName));
            }
            if (mWaitingDialog != null && mWaitingDialog.isShowing()) {
                mWaitingDialog.dismiss();
            }
        }
    }

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

    /**
     * HTML側に温度計からのデータを転送する
     * @param strTemp デバイスから受信された値
     */
    private void setThermometerData(String strTemp) {
        Logger.v(TAG, "thermometer [%s]", strTemp);
        JSONObject thermometerDataJson = new JSONObject();
        thermometerDataJson.put(ABookKeys.TASK_QUESTION_ID, mQid);
        thermometerDataJson.put("value", strTemp);
        afterABookCheckApi(mCmd, "", 0, "", thermometerDataJson.toString());
        // 値が空ではない場合、成功音を出す。
        if (strTemp != null && strTemp.length() > 0) {
            audioPlay();
        }
        Logger.v(TAG, "thermometer JSON [%s]", thermometerDataJson.toString());
    }


    /**
     * HTML側にSPP機器からのデータを転送する
     * @param strData デバイスから受信された値
     */
    public void setSppBluetoothMachineData(final String strData) {
        Logger.v(TAG, "SppBluetoothMachine [%s]", strData);
        JSONObject sppBluetoothMachineDataJson = new JSONObject();
        sppBluetoothMachineDataJson.put(ABookKeys.TASK_QUESTION_ID, mQid);
        sppBluetoothMachineDataJson.put("value", strData);
        // 値が空ではない場合、成功音を出す。
        if (strData != null && strData.length() > 0) {
            audioPlay();
        }
        // 閉じる
        dismissWaitngDialog();
        afterABookCheckApi(mCmd, "", 0, "", sppBluetoothMachineDataJson.toString());
    }

    /**
     * 中心温度計の接続を切る
     */
    protected void bleManagerDisconnect() {
        bleManagerUtil.disconnect(true);
    }

    /**
     * デバイスのバーコードの情報取得
     */
    private void setBarcodeDeviceInfo() {
        //カメラパーミッションチェック
        ABookPermissionHelper helper = new ABookPermissionHelper(ABVCheckContentViewActivity.this, ABookPermissionType.Camera, null);
        if (!helper.checkMultiPermissions(true)) {
            Logger.w(TAG,"startCameraIntent Camera Permission false");
            return;
        }
        Intent barcodeactivityIntent = new Intent( this, BarCodeReaderActivity.class );
        startActivityForResult( barcodeactivityIntent,REQUEST_CODE_BARCODE_READER);
    }

    /**
     * 各デバイスから値を正常に取得された場合、HTML側にコールする
     * @param value 各種デバイスから取得した値
     */
    private void successAfterAbookCheckAip(String value) {
        JSONObject responseJson = new JSONObject();
        responseJson.put(ABookKeys.TASK_QUESTION_ID, mQid);
        responseJson.put("value", value);
        afterABookCheckApi(mCmd, "", 0, "", responseJson.toString());
        Logger.d(TAG, "successAfterAbookCheckAip  JSON [%s]", responseJson.toString());
    }

    /**
     * 各デバイスからエラー（接続不能など）発生した場合、HTML側にコールする
     * @param errorMessage  各種デバイスから取得した値
     */
    private void errorAfterAbookCheckAip(String errorMessage) {
        afterABookCheckApi(mCmd, "", 1, errorMessage, null);
    }

    /**
     * mediaPlayerにmp3ファイルをセット
     * @return
     */
    private boolean audioSetup() {
        boolean fileCheck = false;

        // インタンスを生成
        mMediaPlayer = new MediaPlayer();

        //音楽ファイル名, あるいはパス
        String filePath = "temperatureAudio.mp3";

        // assetsから mp3 ファイルを読み込み
        try(AssetFileDescriptor afdescripter = getAssets().openFd(filePath))
        {
            // MediaPlayerに読み込んだ音楽ファイルを指定
            mMediaPlayer.setDataSource(afdescripter.getFileDescriptor(),
                    afdescripter.getStartOffset(),
                    afdescripter.getLength());
            // 音量調整を端末のボタンに任せる
            setVolumeControlStream(AudioManager.STREAM_MUSIC);
            mMediaPlayer.prepare();
            fileCheck = true;
        } catch (IOException e1) {
            e1.printStackTrace();
        }

        return fileCheck;
    }

    /**
     * mediaplayerをセットして、mp3を再生するメソッド
     */
    private void audioPlay() {
        Logger.d("start audio");
        // mMediaPlayerがnullではない場合は、再生終了されてないと見做し、audioStopメソッドを実行
        if (mMediaPlayer != null) {
            Logger.v("error not stop audio");
            audioStop();
        }
         // audio ファイルを読出し
        if (!audioSetup()) {
            Logger.e("mediaplayer audio set up error");
            return;
        }

        // 再生する
        mMediaPlayer.start();

        // 終了を検知するリスナー
        mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
            @Override
            public void onCompletion(MediaPlayer mp) {
                Logger.d(TAG,"end of audio");
                audioStop();
            }
        });
        Logger.d("start audio2");
    }

    // mediaPlayerを再生終了する
    private void audioStop() {
        // 再生終了
        mMediaPlayer.stop();
        // リセット
        mMediaPlayer.reset();
        // リソースの解放
        mMediaPlayer.release();
        // mediaPlayerを初期化
        mMediaPlayer = null;
    }

    // SPP通信のタスクが存在すれば接続を切るにする
    private void disConnectSppBluetooth() {
        mDisConnectSppBluetoothFlg = true;
        if (mYamatoReceiveTask != null) {
            mYamatoReceiveTask.finish();
            mYamatoReceiveTask = null;
        }

        if (mSppBluetoothConnectThread != null) {
            mSppBluetoothConnectThread.finish();
            mSppBluetoothConnectThread = null;
        }
    }

    @Override
    protected void onStop() {
        super.onStop();
        Logger.d(TAG, "--onStop");
        // SPP通信の接続を切る
        disConnectSppBluetooth();

        // ダイアログを閉じる
        if (mWaitingDialog != null && mWaitingDialog.isShowing()) {
            mWaitingDialog.dismiss();
        }
    }
}