package cn.joyway.joywaybeacon;

import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.os.Bundle;
import android.text.Editable;
import android.text.InputType;
import android.text.TextWatcher;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.RelativeLayout;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.Nullable;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;

import cn.joyway.lib.CommunicateCode.CC;
import cn.joyway.lib.ConvertEx;
import cn.joyway.lib.JoywayLib;
import cn.joyway.lib.bluetooth.BT;
import cn.joyway.lib.bluetooth.BeaconConnectStatus;
import cn.joyway.lib.bluetooth.BeaconScanEvent;
import cn.joyway.lib.bluetooth.OnBeaconEventHandler;
import cn.joyway.lib.bluetooth.UUIDHelper;
import cn.joyway.lib.view.ToastHelper;

public class Activity_iBeacon extends Activity_JWBase implements OnBeaconEventHandler {

    EditText _etName;
    EditText _etUUID;
    EditText _etMajor;
    EditText _etMinor;
    EditText _etRssiAtOneMeter;
    Spinner _spinnerTxPower;
    EditText _etAdv1_interval;
    TextView _tvAdv1_timeLen;
    EditText _etAdv1_timeLen;
    CheckBox _cbAdv1_neverStop;
    RelativeLayout _rlAdv2_params;
    CheckBox _cbAdv2_neverStop;
    EditText _etAdv2_interval;
    TextView _tvAdv2_timeLen;
    EditText _etAdv2_timeLen;
    RelativeLayout _rlButtonFun;
    EditText _etButtonDelayForTurningOn;
    CheckBox _cbAdvertiseButtonEvent;
    TextView _tvButtonEventValue;

    static int PARAM_INDEX_DEVICE_PASSWORD = 0;
    static int PARAM_LEN_DEVICE_PASSWORD = 12;

    static int PARAM_INDEX_DEVICE_NAME = 12;
    static int PARAM_LEN_DEVICE_NAME = 12;

    static int PARAM_INDEX_UUID = 24;
    static int PARAM_LEN_UUID = 16;

    static int PARAM_INDEX_MAJOR = 40;
    static int PARAM_LEN_MAJOR = 2;

    static int PARAM_INDEX_MINOR = 42;
    static int PARAM_LEN_MINOR = 2;

    static int PARAM_INDEX_RSSI_AT_ONE_METER = 44;
    // static int PARAM_LEN_RSSI_AT_ONE_METER = 1;

    static int PARAM_INDEX_TX_POWER = 45;
    // static int PARAM_LEN_TX_POWER = 1;

    static int PARAM_INDEX_ADV1_INTERVAL_byMS = 46;
    static int PARAM_LEN_ADV1_INTERVAL_byMS = 2;

    static int PARAM_INDEX_ADV1_TIME_LEN_by100MS = 48;
    static int PARAM_LEN_ADV1_TIME_LEN_by100MS = 2;

    static int PARAM_INDEX_ADV2_INTERVAL_byMS = 50;
    static int PARAM_LEN_ADV2_INTERVAL_byMS = 2;

    static int PARAM_INDEX_ADV2_TIME_LEN_by100MS = 52;
    static int PARAM_LEN_ADV2_TIME_LEN_by100MS = 2;

    static int PARAM_INDEX_BUTTON_DELAY_FOR_TURNING_ON_by100MS = 54;
    // static int PARAM_LEN_BUTTON_DELAY_FOR_TURNING_ON_by100MS = 1;

    static int PARAM_INDEX_EIGHT_BOOL = 55;
    // static int PARAM_LEN_EIGHT_BOOL = 1;

    @Override
    void bindUI() {

        // region 绑定控件到变量
        setContentView(R.layout.activity_ibeacon);
        ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
            Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
            v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
            return insets;
        });
        _tvNoticeForWaiting = findViewById(R.id.tv_jwbeacon_notice_for_waiting);
        _tvTitle = findViewById(R.id.tv_jwbeacon_title);
        _tvMac = findViewById(R.id.tv_jwbeacon_mac);
        _tvFWPID = findViewById(R.id.tv_jwbeacon_fwpid_value);
        _tvConnectStatus = findViewById(R.id.tv_jwbeacon_connect_status);
        _bnSave = findViewById(R.id.bn_jwbeacon_save);
        _etDevicePassword = findViewById(R.id.et_jwbeacon_device_password);
        _cbShowDevicePassword = findViewById(R.id.cb_jwbeacon_show_device_password);
        _cbShowDevicePassword.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                // int currentType = _etDevicePassword.getInputType();
                int textPassword = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD;
                int textVisiblePassword = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD;

                if (isChecked) {
                    _etDevicePassword.setInputType(textVisiblePassword);
                } else {
                    _etDevicePassword.setInputType(textPassword);
                }

                _etDevicePassword.setSelection(_etDevicePassword.getText().length());
            }
        });
        _etName = findViewById(R.id.et_jwbeacon_name);
        _etUUID = findViewById(R.id.et_jwbeacon_uuid);
        _etMajor = findViewById(R.id.et_jwbeacon_major);
        _etMinor = findViewById(R.id.et_jwbeacon_minor);
        _etRssiAtOneMeter = findViewById(R.id.et_jwbeacon_rssi_at_one_meter);
        _spinnerTxPower = findViewById(R.id.spinner_jwbeacon_tx_power);
        _etAdv1_interval = findViewById(R.id.et_jwbeacon_adv1_interval);
        _tvAdv1_timeLen = findViewById(R.id.tv_jwbeacon_adv1_time_len);
        _etAdv1_timeLen = findViewById(R.id.et_jwbeacon_adv1_time_len);
        _cbAdv1_neverStop = findViewById(R.id.cb_jwbeacon_adv1_never_stop);
        _rlAdv2_params = findViewById(R.id.rl_jwbeacon_adv2);
        _etAdv2_interval = findViewById(R.id.et_jwbeacon_adv2_interval);
        _tvAdv2_timeLen = findViewById(R.id.tv_jwbeacon_adv2_time_len);
        _etAdv2_timeLen = findViewById(R.id.et_jwbeacon_adv2_time_len);
        _cbAdv2_neverStop = findViewById(R.id.cb_jwbeacon_adv2_never_stop);
        _rlButtonFun = findViewById(R.id.rl_button_fun);
        _etButtonDelayForTurningOn = findViewById(R.id.et_jwbeacon_button_delay_for_turning_on_by100ms);
        _cbAdvertiseButtonEvent = findViewById(R.id.cb_jwbeacon_advertise_button_event);
        _tvButtonEventValue = findViewById(R.id.tv_jwbeacon_button_event_value);
        // endregion

        // region 监听输入框的内容，如果出现不合法的值，就要提醒
        _etMajor.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {

            }

            @Override
            public void afterTextChanged(Editable s) {
                if (s.toString().length() > 1) {
                    int major = ConvertEx.String_to_int(s.toString(), -1);
                    if (major < 0 || major > 65535) {
                        Toast.makeText(Activity_iBeacon.this, "Major ID range is 0-65535.", Toast.LENGTH_LONG).show();
                    }
                }
            }
        });
        _etMinor.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {

            }

            @Override
            public void afterTextChanged(Editable s) {
                if (s.toString().length() > 1) {
                    int minor = ConvertEx.String_to_int(s.toString(), -1);
                    if (minor < 0 || minor > 65535) {
                        Toast.makeText(Activity_iBeacon.this, "Minor ID range is 0-65535.", Toast.LENGTH_LONG).show();
                    }
                }
            }
        });
        _etRssiAtOneMeter.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {

            }

            @Override
            public void afterTextChanged(Editable s) {
                if (s.toString().length() > 1) {
                    int rssiAtOneMeter = ConvertEx.String_to_int(s.toString(), 255);
                    if (rssiAtOneMeter > 10 || rssiAtOneMeter < -120) {
                        Toast.makeText(Activity_iBeacon.this, "Rssi at one meter range is -120 ~ +10.",
                                Toast.LENGTH_LONG).show();
                    }
                }
            }
        });

        // region 发射功率
        String[] txPowerEntries = new String[] { "-30", "-20", "-16", "-12", "-8", "-4", "0", "4" };
        int[] txPowerValues = new int[] { -30, -20, -16, -12, -8, -4, 0, 4 };
        ArrayAdapter<String> txPowerAdapter = new ArrayAdapter<>(this,
                android.R.layout.simple_spinner_item, txPowerEntries);
        txPowerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        _spinnerTxPower.setAdapter(txPowerAdapter);
        // endregion 发射功率

        _etAdv1_interval.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {

            }

            @Override
            public void afterTextChanged(Editable s) {
                if (s.toString().length() > 1) {
                    int adv_interval = ConvertEx.String_to_int(s.toString(), 999999999);
                    if (adv_interval < 100 || adv_interval > 10000) {
                        Toast.makeText(Activity_iBeacon.this, "Adv interval rang is 100~10000ms.", Toast.LENGTH_LONG)
                                .show();
                    }
                }
            }
        });
        _etAdv1_timeLen.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {

            }

            @Override
            public void afterTextChanged(Editable s) {
                if (!_cbAdv1_neverStop.isChecked() && s.toString().length() > 1) {
                    int adv_timeLen = ConvertEx.String_to_int(s.toString(), 6553500 + 1);
                    if (adv_timeLen >= 6553500) {
                        ToastHelper.show("Adv time length should be less than 6553500 ms.");
                    }
                }
            }
        });
        _etAdv2_interval.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {

            }

            @Override
            public void afterTextChanged(Editable s) {
                if (s.toString().length() > 1) {
                    int adv_interval = ConvertEx.String_to_int(s.toString(), 99999999);
                    if (adv_interval < 100 || adv_interval > 10000) {
                        Toast.makeText(Activity_iBeacon.this, "Adv interval rang is 100~10000ms.", Toast.LENGTH_LONG)
                                .show();
                    }
                }
            }
        });
        _etAdv2_timeLen.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {

            }

            @Override
            public void afterTextChanged(Editable s) {
                if (!_cbAdv2_neverStop.isChecked() && s.toString().length() > 1) {
                    int adv_timeLen = ConvertEx.String_to_int(s.toString(), 6553500 + 1);
                    if (adv_timeLen > 6553500) {
                        ToastHelper.show("Adv time length should be less than 6553500 ms.");
                    }
                }
            }
        });
        _etButtonDelayForTurningOn.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {

            }

            @Override
            public void afterTextChanged(Editable s) {
                if (s.toString().length() > 1) {
                    int delayMS = ConvertEx.String_to_int(s.toString(), 5000 + 1);
                    if (delayMS < 0 || delayMS > 5000) {
                        Toast.makeText(Activity_iBeacon.this, "Button delay should be range 0~5000ms.",
                                Toast.LENGTH_LONG).show();
                    }
                }
            }
        });
        // endregion

        // region 广播永不停止“勾选框” --- 点击事件
        _cbAdv1_neverStop.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                if (isChecked) {
                    // 如果adv1永不停止，那么adv2就没有意义了，必须隐藏，adv2里的参数永远不会用到，因此其数据值不用复位。
                    _rlAdv2_params.setVisibility(View.GONE);
                    // adv1永不停止，那么adv1的广播时长就强制改为“6553500”，不允许用户编辑和看见
                    _etAdv1_timeLen.setText("6553500");
                    _tvAdv1_timeLen.setVisibility(View.GONE);
                    _etAdv1_timeLen.setVisibility(View.GONE);
                } else {
                    // adv1广播一段时间后停止，那么就能广播ADV2
                    _rlAdv2_params.setVisibility(View.VISIBLE);
                    // 允许用户编辑adv1的参数
                    _tvAdv1_timeLen.setVisibility(View.VISIBLE);
                    _etAdv1_timeLen.setVisibility(View.VISIBLE);
                    _etAdv1_timeLen.setText(null);
                    _etAdv1_timeLen.requestFocus();

                }
            }
        });
        _cbAdv2_neverStop.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                if (isChecked) {
                    // adv2永不停止，那么adv2的广播时长就强制改为“6553500”，不允许用户编辑和看见
                    _etAdv2_timeLen.setText("6553500");
                    _tvAdv2_timeLen.setVisibility(View.GONE);
                    _etAdv2_timeLen.setVisibility(View.GONE);
                } else {
                    // 允许用户编辑adv2的参数
                    _tvAdv2_timeLen.setVisibility(View.VISIBLE);
                    _etAdv2_timeLen.setVisibility(View.VISIBLE);
                    _etAdv2_timeLen.setText(null);
                    _etAdv2_timeLen.requestFocus();
                }
            }
        });
        // endregion

    }

    @Override
    int WORKING_PARAM_LEN() {
        return 72;
    }

    @Override
    void showWorkingParamsToUI() {
        byte[] workingParams = ConvertEx.bytes_to_byteArray(_workingParamsFromDevice);
        String passwordConnect = ConvertEx.bytes_to_charString_1byte1char(workingParams,
                PARAM_INDEX_DEVICE_PASSWORD, PARAM_LEN_DEVICE_PASSWORD, true);
        String name = ConvertEx.bytes_to_charString_1byte1char(workingParams,
                PARAM_INDEX_DEVICE_NAME, PARAM_LEN_DEVICE_NAME, true);
        String uuid = ConvertEx.bytes_to_hexString(workingParams,
                PARAM_INDEX_UUID, PARAM_LEN_UUID, false, null);
        String uuidWithShortLine = UUIDHelper.formatNormal(uuid);
        int major = ConvertEx.bytes_to_int(workingParams, PARAM_INDEX_MAJOR, PARAM_LEN_MAJOR);
        int minor = ConvertEx.bytes_to_int(workingParams, PARAM_INDEX_MINOR, PARAM_LEN_MINOR);
        int rssiAtOneMeter = ConvertEx.byte_to_int_neg128_pos127(workingParams[PARAM_INDEX_RSSI_AT_ONE_METER]);
        int txPower = ConvertEx.byte_to_int_neg128_pos127(workingParams[PARAM_INDEX_TX_POWER]);// ???
        int adv1_intervalMS = ConvertEx.bytes_to_int(workingParams,
                PARAM_INDEX_ADV1_INTERVAL_byMS, PARAM_LEN_ADV1_INTERVAL_byMS);
        int adv1_timeLenMS = ConvertEx.bytes_to_int(workingParams,
                PARAM_INDEX_ADV1_TIME_LEN_by100MS, PARAM_LEN_ADV1_TIME_LEN_by100MS) * 100;
        int adv2_intervalMS = ConvertEx.bytes_to_int(workingParams,
                PARAM_INDEX_ADV2_INTERVAL_byMS, PARAM_LEN_ADV2_INTERVAL_byMS);
        int adv2_timeLenMS = ConvertEx.bytes_to_int(workingParams,
                PARAM_INDEX_ADV2_TIME_LEN_by100MS, PARAM_LEN_ADV2_TIME_LEN_by100MS) * 100;
        int buttonDelayForTurningOnMS = ConvertEx.byte_to_int_0_255(
                workingParams[PARAM_INDEX_BUTTON_DELAY_FOR_TURNING_ON_by100MS]) * 100;
        byte eightBool = workingParams[PARAM_INDEX_EIGHT_BOOL];
        boolean advertiseButtonEvent = (eightBool & 0x01) > 0;
        _etDevicePassword.setText(passwordConnect);
        _etName.setText(name);
        _etUUID.setText(uuidWithShortLine);
        _etMajor.setText(ConvertEx.int_to_String(major));
        _etMinor.setText(ConvertEx.int_to_String(minor));
        _etRssiAtOneMeter.setText(ConvertEx.int_to_String(rssiAtOneMeter));
        int[] txPowerValues = new int[] { -30, -20, -16, -12, -8, -4, 0, 4 };
        for (int i = 0; i < txPowerValues.length; i++) {
            if (txPowerValues[i] == txPower) {
                _spinnerTxPower.setSelection(i);
                break;
            }
        }
        _etAdv1_interval.setText(ConvertEx.int_to_String(adv1_intervalMS));
        _etAdv1_timeLen.setText(ConvertEx.int_to_String(adv1_timeLenMS));
        _cbAdv1_neverStop.setChecked(adv1_timeLenMS == 6553500);
        _etAdv2_interval.setText(ConvertEx.int_to_String(adv2_intervalMS));
        _etAdv2_timeLen.setText(ConvertEx.int_to_String(adv2_timeLenMS));
        _cbAdv2_neverStop.setChecked(adv2_timeLenMS == 6553500);
        _etButtonDelayForTurningOn.setText(ConvertEx.int_to_String(buttonDelayForTurningOnMS));
        _cbAdvertiseButtonEvent.setChecked(advertiseButtonEvent);

        // region 根据设备名称判断是否有按钮，如果没有按钮，就隐藏下面的按钮功能区
        if (name.contains("1404B") || name.contains("1405B") || name.contains("1400B")) {
            _rlButtonFun.setVisibility(View.VISIBLE);
        } else {
            _rlButtonFun.setVisibility(View.GONE);
        }
        // endregion
    }

    @Override
    byte[] getWorkingParamsFromUI() {

        // region 检查各个参数是否合法，如果不行就弹出提示，不执行保存动作
        // 密码长度不能超过12个字符
        if (_etDevicePassword.getText().toString().length() > 12) {
            new AlertDialog.Builder(Activity_iBeacon.this)
                    .setTitle("Password can not be more than 12 characters.")
                    .setPositiveButton(R.string.ok, null)
                    .show();
            return null;// 参数不合法，直接返回，不要保存
        }
        // 广播名称不能超过12字符
        if (_etName.getText().toString().length() > 12) {
            new AlertDialog.Builder(Activity_iBeacon.this)
                    .setTitle("Name can not be more than 12 characters.")
                    .setPositiveButton(R.string.ok, null)
                    .show();
            return null;// 参数不合法，直接返回，不要保存
        }
        // UUID不合法
        String uuidInput = _etUUID.getText().toString();
        if (!UUIDHelper.isValidUUID(uuidInput)) {
            new AlertDialog.Builder(Activity_iBeacon.this)
                    .setTitle("UUID not correct.")
                    .setPositiveButton(R.string.ok, null)
                    .show();
            return null;// 参数不合法，直接返回，不要保存
        }
        // major和minor都必须在0~65535范围。
        int major = ConvertEx.String_to_int(_etMajor.getText().toString(), -1);
        int minor = ConvertEx.String_to_int(_etMinor.getText().toString(), -1);
        if (major < 0 || major > 65535 || minor < 0 || minor > 65535) {
            new AlertDialog.Builder(Activity_iBeacon.this)
                    .setTitle("Major ID, Minor ID must be in range 0~65535.")
                    .setPositiveButton(R.string.ok, null)
                    .show();
            return null;// 参数不合法，直接返回，不要保存
        }
        // rssi@1米，范围 -100 ~ 0 dbm。
        int rssiAtOneMeter = ConvertEx.String_to_int(_etRssiAtOneMeter.getText().toString(), 999999);
        if (rssiAtOneMeter > 0 || rssiAtOneMeter < -100) {
            new AlertDialog.Builder(Activity_iBeacon.this)
                    .setTitle("Rssi at one meter must be in range -100~0.")
                    .setPositiveButton(R.string.ok, null)
                    .show();
            return null;// 参数不合法，直接返回，不要保存
        }
        // 发射功率 -30 和 -20 到 +4.
        int[] txPowerValuesForCheck = new int[] { -30, -20, -16, -12, -8, -4, 0, 4 };
        int tx_power = txPowerValuesForCheck[_spinnerTxPower.getSelectedItemPosition()];
        // 广播间隔范围 100ms 到 10s。
        int adv1_interval = ConvertEx.String_to_int(_etAdv1_interval.getText().toString(), -1);
        int adv1_time_len = ConvertEx.String_to_int(_etAdv1_timeLen.getText().toString(), -1);
        boolean adv1_never_stop = _cbAdv1_neverStop.isChecked();
        int adv2_interval = ConvertEx.String_to_int(_etAdv2_interval.getText().toString(), -1);
        int adv2_time_len = ConvertEx.String_to_int(_etAdv2_timeLen.getText().toString(), -1);
        boolean adv2_never_stop = _cbAdv2_neverStop.isChecked();
        String error_msg = null;
        // 广播1的间隔必须在100-10000范围
        if (adv1_never_stop || adv1_time_len > 0) {
            if (adv1_interval < 100 || adv1_interval > 10000) {
                error_msg = "Adv 1 Interval can only be in range 100~10000 milliseconds.";
            }
        }
        // 如果广播1不是“永不停止”，那么就必须设定一个"非负数"作为广播时长
        if (!adv1_never_stop && adv1_time_len < 0) {
            error_msg = Activity_iBeacon.this.getString(R.string.adv_1_time_length_is_not_correct);
        }
        // 广播2的间隔必须在100-10000范围
        if (adv2_never_stop || adv2_time_len > 0) {
            if (adv2_interval < 100 || adv2_interval > 10000) {
                error_msg = "Adv 2 Interval can only be in range 100~10000 milliseconds.";
            }
        }
        // 如果广播2不是“永不停止”，那么就必须设定一个"非负数"作为广播时长
        if (!adv2_never_stop && adv2_time_len < 0) {
            error_msg = Activity_iBeacon.this.getString(R.string.adv_2_time_length_is_not_correct);
        }
        // 如果广播1和2都非“永不停止”，但是adv1和adv2的时长都是0，那么提示用户广播时长至少需要指定一个有效值。
        if (!adv1_never_stop && !adv2_never_stop && adv1_time_len == 0 && adv2_time_len == 0) {
            error_msg = Activity_iBeacon.this.getString(R.string.adv_time_len_can_not_all_be_zero);
        }
        // 如果出现了上述错误，就提示用户，范湖null
        if (error_msg != null) {
            new AlertDialog.Builder(Activity_iBeacon.this).setTitle(error_msg).setPositiveButton(R.string.ok, null)
                    .show();
            return null;// 参数不合法，直接返回，不要保存
        }

        int button_delay_for_turning_on_ms = ConvertEx.String_to_int(_etButtonDelayForTurningOn.getText().toString(),
                -1);

        // endregion

        // region 能走到这里，说明参数验证通过了，执行保存。把需要发送的参数，都放入 workingParamsToSave 字节数组里。

        byte[] workingParamsToSave = new byte[WORKING_PARAM_LEN()];
        int nextWriteIndex = 0;

        // gateway password (max 12 bytes)
        byte[] bs = ConvertEx.String_to_byteArray_1Char1byte(_etDevicePassword.getText().toString().trim());
        System.arraycopy(bs, 0, workingParamsToSave, nextWriteIndex, bs.length);
        nextWriteIndex += 12;

        // name (max 12 bytes)
        bs = ConvertEx.String_to_byteArray_1Char1byte(_etName.getText().toString().trim());
        System.arraycopy(bs, 0, workingParamsToSave, nextWriteIndex, bs.length);
        nextWriteIndex += 12;

        // uuid (16 bytes)
        bs = ConvertEx.String_to_byteArray_2Char1byte(UUIDHelper.formatShort(uuidInput));
        System.arraycopy(bs, 0, workingParamsToSave, nextWriteIndex, bs.length);
        nextWriteIndex += 16;

        // major (2 byte)
        bs = ConvertEx.int_to_2bytes(major);
        System.arraycopy(bs, 0, workingParamsToSave, nextWriteIndex, bs.length);
        nextWriteIndex += 2;

        // minor (2 byte)
        bs = ConvertEx.int_to_2bytes(minor);
        System.arraycopy(bs, 0, workingParamsToSave, nextWriteIndex, bs.length);
        nextWriteIndex += 2;

        // rssi at one meter (1 byte)
        workingParamsToSave[nextWriteIndex] = ConvertEx.int_to_1byte(rssiAtOneMeter);
        nextWriteIndex += 1;

        // tx power (1 byte)
        workingParamsToSave[nextWriteIndex] = ConvertEx.int_to_1byte(tx_power);
        nextWriteIndex += 1;

        // 广播（1）间隔 (2 byte)
        bs = ConvertEx.int_to_2bytes(adv1_interval);
        System.arraycopy(bs, 0, workingParamsToSave, nextWriteIndex, bs.length);
        nextWriteIndex += 2;

        // 广播（1）时长 (2 byte)
        bs = ConvertEx.int_to_2bytes(adv1_time_len / 100); // 因为单位是100ms，所以需要除以100
        System.arraycopy(bs, 0, workingParamsToSave, nextWriteIndex, bs.length);
        nextWriteIndex += 2;

        // 广播（2）间隔 (2 byte)
        bs = ConvertEx.int_to_2bytes(adv2_interval);
        System.arraycopy(bs, 0, workingParamsToSave, nextWriteIndex, bs.length);
        nextWriteIndex += 2;

        // 广播（2）时长 (2 byte)
        bs = ConvertEx.int_to_2bytes(adv2_time_len / 100); // 因为单位是100ms，所以需要除以100
        System.arraycopy(bs, 0, workingParamsToSave, nextWriteIndex, bs.length);
        nextWriteIndex += 2;

        // 开机按钮延时。button delay for turning ON
        int bn_delay = (button_delay_for_turning_on_ms / 100);
        workingParamsToSave[nextWriteIndex] = ConvertEx.int_to_1byte(bn_delay); // 因为单位是100ms，所以需要除以100
        nextWriteIndex++;

        // 用一个字节表示8个bool
        byte eightBool = 0x00;
        if (_cbAdvertiseButtonEvent.isChecked()) {
            eightBool |= (0x01);
        }
        workingParamsToSave[nextWriteIndex] = eightBool;
        nextWriteIndex++;

        // endregion

        return workingParamsToSave;
    }

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        BT.listenBeaconEvent(this, true);
    }

    @Override
    protected void onDestroy() {
        BT.listenBeaconEvent(this, false);
        super.onDestroy();
    }

    @Override
    public void onBeaconScanEvent(BeaconScanEvent beaconScanEvent) {

    }

    @Override
    public void onBeaconConnectStatusChanged(String mac,
                                             BeaconConnectStatus oldStatus,
                                             BeaconConnectStatus newStatus) {

    }

    @Override
    public void onBeaconRssiChanged(String mac, int oldRssi, int newRssi) {

    }

    @Override
    public void onDataSentToBeacon(String mac, byte[] bytes, String str) {

    }

    @Override
    public void onBeaconData(String mac, byte[] bytes, String str) {

        if (!mac.equals(_mac))
            return;

        int cc = bytes[0] * 256 + bytes[1];
        int param_len = bytes[2];

        // region 收到信标的按钮事件
        if (cc == CC.D2A_ButtonEvent && param_len == 1) {
            int clickCount = bytes[3];
            if (clickCount == 0) {
                _tvButtonEventValue.setText(R.string.ibeacon_activity_button_long_pressed);
            } else {
                String fmt = Activity_iBeacon.this.getString(R.string.ibeacon_activity_button_click_counts);
                _tvButtonEventValue.setText(String.format(fmt, clickCount));
            }
        }
        // endregion

    }

}