package com.example.iot_controlhost.model;

import com.blankj.utilcode.util.StringUtils;
import com.example.iot_controlhost.model.controller.Controller;
import com.example.iot_controlhost.model.sensor.Sensor;
import com.example.iot_controlhost.utils.MMKVUtil;
import com.example.iot_controlhost.utils.global.HardwareSetting;
import com.example.iot_controlhost.utils.global.SpinnerList;
import com.example.iot_controlhost.utils.log.MyLog;

import java.nio.ByteBuffer;

import android_serialport_api.SerialPortUtil;

/**
 * 各种硬件设备
 */
public abstract class Device {

    public static final String MY_CONTROLLER_MODEL = "控制器类型";
    /**
     * 控制器型号
     */
    public static String[] CONTROLLER_MODEL = {"装配式控制器"/*, "集成式控制器"*/};
    /**
     * 设备名称
     */
    protected String name;
    /**
     * 设备型号
     */
    public static final String MODEL = "型号";
    /**
     * 设备地址
     */
    public static final String ADDRESS = "地址";
    /**
     * 设备是否启用
     */
    public static final String ENABLE = "启用";
    /**
     * 操作失败次数
     */
    private int failTimes;

    public Device(String name) {
        this.name = name;
        //设置默认型号
        if (StringUtils.isEmpty(getModel())) {
            setModel(getModels()[0]);
        }
    }

    /**
     * 返回设备基础信息
     */
    @Override
    public String toString() {
        return !isEnable() ? "未启用"
                : (("型号：" + getModel()) + "\t地址：" + (isIntegratedController() ? HardwareSetting.getCommonAddress() : getAddress()));
    }

    /**
     * 是否可用
     * isAvailable()区别于isEnable()，后者为人工设置可用于否，而前者为配置是否得当，可用于否
     */
    public boolean isAvailable() {
        if (!isIntegratedController() && StringUtils.isEmpty(getAddress()) //装配式控制器 判断地址为空
                || isIntegratedController() && StringUtils.isEmpty(HardwareSetting.getCommonAddress())) {//集成式控制器 判断地址为空
            //地址为空也视为不可用
            return false;
        }
        return isEnable();
    }

    /**
     * 获得型号
     */
    public abstract String[] getModels();

    public int addFailTimes() {
        int curTimes = getFailTimes();
        MMKVUtil.put(name + "failTimes", ++curTimes);
        if (this instanceof Controller) {
            MyLog.controllerError("控制器：" + name + "已连续操作失败：" + curTimes + "次");
        } else if (this instanceof Sensor) {
            MyLog.sensorError("传感器：" + name + "已连续读取失败：" + curTimes + "次");
        }
        return curTimes;
    }

    public void clearSetting() {
        MMKVUtil.remove(name + MODEL);
        MMKVUtil.remove(name + ADDRESS);
        MMKVUtil.remove(name + ENABLE);
        MMKVUtil.remove(name + "failTimes");
    }

    /**
     * 设置该设备错误次数
     * 只有在操作成功后或发送警报后才会置零
     */
    public void setFailTimes(int failTimes) {
        MMKVUtil.put(name + "failTimes", failTimes);
    }

    public boolean isEnable() {
        return MMKVUtil.get(name + ENABLE, false);
    }

    public void setEnable(boolean enable) {
        MyLog.test("设置" + name + "设备是否启用：" + enable);
        MMKVUtil.put(name + ENABLE, enable);
    }

    public int getFailTimes() {
        return MMKVUtil.get(name + "failTimes", 0);
    }

    public static String getControllerModel() {
        return MMKVUtil.get(MY_CONTROLLER_MODEL, CONTROLLER_MODEL[0]);
    }

    /**
     * 是否是集成式控制器
     *
     * @return true:集成式控制器 false:装配式控制器 2023年11月14日 10:12:48
     */
    public static boolean isIntegratedController() {
        return !getControllerModel().equals(CONTROLLER_MODEL[0]);
    }

    public static void setControllerModel(String model) {
        MMKVUtil.put(MY_CONTROLLER_MODEL, model);
    }

    public void setAddress(String address) {
        MMKVUtil.put(name + ADDRESS, address);
    }

    public String getAddress() {
        return MMKVUtil.get(name + ADDRESS, SpinnerList.ADDRESS[0]);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getModel() {
        return MMKVUtil.get(name + MODEL, getModels()[0]);
    }

    public void setModel(String model) {
        MMKVUtil.put(name + MODEL, model);
    }

    public static String getCRC(String hex) {
        try {
            byte[] bytes;
            //十六进制字符串转byte[]
            if (hex == null) {
                bytes = new byte[]{};
            } else {
                // 奇数位补0
                if (hex.length() % 2 != 0) {
                    hex = "0" + hex;
                }

                int length = hex.length();
                ByteBuffer buffer = ByteBuffer.allocate(length / 2);
                for (int i = 0; i < length; i++) {
                    String hexStr = hex.charAt(i) + "";
                    i++;
                    hexStr += hex.charAt(i);
                    byte b = (byte) Integer.parseInt(hexStr, 16);
                    buffer.put(b);
                }
                bytes = buffer.array();
            }
            int CRC = 0x0000ffff;
            int POLYNOMIAL = 0x0000a001;
            int i, j;
            for (i = 0; i < bytes.length; i++) {
                CRC ^= ((int) bytes[i] & 0x000000ff);
                for (j = 0; j < 8; j++) {
                    if ((CRC & 0x00000001) != 0) {
                        CRC >>= 1;
                        CRC ^= POLYNOMIAL;
                    } else {
                        CRC >>= 1;
                    }
                }
            }
            String crc = Integer.toHexString(CRC);
            if (crc.length() == 2) {
                crc = "00" + crc;
            } else if (crc.length() == 3) {
                crc = "0" + crc;
            }
            crc = crc.substring(2, 4) + crc.substring(0, 2);
            return crc.toUpperCase();
        } catch (Exception e) {
            return "0000";
        }
    }

    /**
     * 按照指定长度截取字符串成一个数组
     */
    public String[] substring(String str, int length) {
        if(str == null ){
            return new String[0];
        }
        String[] result = new String[str.length() / length];
        int beg = 0;
        for (int i = 0; i < result.length; i++) {
            result[i] = str.substring(beg, beg + length);
            beg = beg + length;
        }
        return result;
    }
}
