#pragma once
#include <iostream>
#include "deviceBase.h"
#include "Crc.h"

using namespace std;

// 煤气驱鸟炮
#define EXPEL_DATA_HEAD          (0xFE) // 数据头
#define EXPEL_HEART_BEAT         (0x01) // 心跳
#define EXPEL_GENERAL_ACK        (0X02) // 通用应答
#define EXPEL_SYS_STATE          (0x14) // 获取设备信息
#define EXPEL_SYS_STATE_ACK      (0X15) // 获取设备信息应答

#define EXPEL_POWER_OUTPUT_CTRL  (0X16) // 电源输出控制   <-: 通用应答
#define EXPEL_POWER_OUTPUT_ON    (0x01) // 电源开启
#define EXPEL_POWER_OUTPUT_OFF   (0x00) // 电源关闭

#define EXPEL_BOMB_CTRL          (0X17) // 煤气炮控制     <-: 通用应答
#define EXPEL_BOMB_ON            (0X01) // 煤气炮开炮

#define EXPEL_GET_BOMB_STATE     (0X18) // 获取开炮结果   
#define EXPEL_GET_BOMB_STATE_ACK (0X19) // 煤气炮开炮应答 <-：通用应答（因为状态为阶段状态，过时会丢失状态。需确认应答收到，未收到应带会重传3次



class deviceGasV1:public deviceBase
{
private:
    unsigned short voltage;
    short current;
    short pressure;
    uint8_t power_out_state;

private: 
    enum RECV_STEP{
        STEP_HEAD = 0,
        STEP_LEN = 1,
        STEP_SEQ = 2,
        STEP_SAddr = 3,
        STEP_DAddr = 4,
        STEP_MSGId = 5,
        STEP_DATA = 6
    };
    typedef struct {
        uint8_t dataCount;
        uint8_t dataLength;
        uint8_t dataCheckSum;
        uint8_t data[15];
        enum RECV_STEP step = STEP_HEAD;
    }ExpelComm;

    ExpelComm _comm;

public:
    deviceGasV1():deviceBase()
    {
        this->setDeviceToken(serial);
        this->setDeviceInfo("北京大兴机场 民航小板协议");
        this->setBaudRate(115200);
    }
    ~deviceGasV1(){}

    void setVoltage(unsigned short Voltage){
        voltage = Voltage;
    }

    void setCurent(short Current){
        current = Current;
    }

    void setPressure(short Pressure){
        pressure = Pressure;
    }

    void setPowerOutState(uint8_t PowerOutState){
        power_out_state = PowerOutState;
    }

    unsigned short getVoltage(){
        return voltage;
    }

    short getCurent(){
        return current;
    }

    short getPressure(){
        return pressure;
    }

    uint8_t getPowerOutState(){
        return power_out_state;
    }

    void serialization(){}

    bool Consumer(uint8_t *data, int len, int &msg_id)
    {
        bool ReceiveSuccessful = false;
        if(this->Type != 1 && len > 0) return true;
        for (int i = 0; i < len; i++)
        {
            switch(_comm.step){
                case STEP_HEAD:
                    if(data[i] == EXPEL_DATA_HEAD){
                        _comm.data[0] = EXPEL_DATA_HEAD;
                        _comm.step = STEP_LEN;
                    }
                    break;
                case STEP_LEN:
                    _comm.data[1] = data[i];
                    _comm.dataLength = data[i];
                    _comm.step = STEP_SEQ;
                    break;
                case STEP_SEQ:
                    _comm.data[2] = data[i];
                    _comm.step = STEP_SAddr;
                    break; 
                case STEP_SAddr:
                    _comm.data[3] = data[i];
                    _comm.step = STEP_DAddr;
                    break;
                case STEP_DAddr:
                    _comm.data[4] = data[i];
                    _comm.step = STEP_MSGId;
                    break;
                case STEP_MSGId:
                    _comm.data[5] = data[i];
                    _comm.step = STEP_DATA;
                    _comm.dataCount = 6;
                    break;
                case STEP_DATA:
                    _comm.data[_comm.dataCount++] = data[i];
                    if(_comm.dataCount == _comm.dataLength + 2 + 6){
                        ReceiveSuccessful = true;
                        _comm.step = STEP_HEAD;
                    }
                    break;
                default:
                    _comm.step = STEP_HEAD;
                    break;   
            }
        }
        if(!ReceiveSuccessful) return false;
        return deserialization(_comm.data, _comm.dataLength + 2 + 6, msg_id);
    } 

    static void serialization(const GasV1Control gasControl, char* data){
        data[0] = EXPEL_DATA_HEAD;
        data[1] = 0x01;
        data[2] = 0x01;
        data[3] = 0xAC;
        data[4] = (char)gasControl.deviceId;
        data[5] = gasControl.msgId;
        data[6] = gasControl.data;

        int16_t checksum =  Crc::crc_calculate((uint8_t *)(data + 1), data[1] + 4 + 1);
        data[7] = (char)(checksum&0x00ff);
        data[8] = (char)(checksum >> 8);
        data[9] = 0x0D;
        data[10] = 0x0A;
    }

    bool deserialization(){
        return true;
    }

    bool deserialization(const uint8_t *data, int len, int &msg_id){
        if(data[0] != EXPEL_DATA_HEAD) return false;

        int16_t checksum = Crc::crc_calculate((uint8_t *)(data + 1), data[1] + 4 + 1);

        if(data[len - 2] != (uint8_t)(checksum&0x00ff) || data[len - 1] != (uint8_t)(checksum >> 8)){
            return false;
        }
        setDeviceId(std::to_string(data[4]));
        msg_id = data[5];
        if(msg_id == EXPEL_SYS_STATE_ACK){
            // 获取系统状态
            voltage = data[6] + (data[7]*255);
            current = data[8] + (data[9]*255);
            pressure = data[10] + (data[11]*255);
            power_out_state = data[12];
        }
        return true;
    }   

    /**
     * @description: 打开
     * @param {int} deivceId
     * @return {*}
     */    
    int32_t Open(std::string DeviceId, uint8_t* data, int& length){
        GasV1Control gasControl;
        gasControl.deviceId = atoi(DeviceId.c_str());
        gasControl.msgId = EXPEL_POWER_OUTPUT_CTRL;
        gasControl.data = EXPEL_POWER_OUTPUT_ON;
        length = 11;
        serialization(gasControl, (char*)data);
        return 0;   
    }

    /**
     * @description: 关闭
     * @param {int} deivceId
     * @return {*}
     */    
    int32_t Close(std::string DeviceId, uint8_t* data, int& length){
        GasV1Control gasControl;
        gasControl.deviceId = atoi(DeviceId.c_str());
        gasControl.msgId = EXPEL_POWER_OUTPUT_CTRL;
        gasControl.data = EXPEL_POWER_OUTPUT_OFF;
        length = 11;
        serialization(gasControl, (char*)data);
        return 0;
    }

    /**
     * @description: 开炮
     * @param {int} deivceId
     * @return {*}
     */    
    int32_t Fire(std::string DeviceId, uint8_t* data, int& length){
        // GasV1Control gasControl;
        // gasControl.deviceId = atoi(DeviceId.c_str());
        // gasControl.msgId = EXPEL_BOMB_CTRL;
        // gasControl.data = EXPEL_BOMB_ON;
        // length = 11;
        // serialization(gasControl, (char*)data);

        //return Status(DeviceId, data, length);
        return Open(DeviceId, data, length);
    }

    /**
     * @description: 状态
     * @param {int} deivceId
     * @return {*}
     */    
    int32_t Status(std::string DeviceId, uint8_t* data, int& length){
        GasV1Control gasControl;
        gasControl.deviceId = atoi(DeviceId.c_str());
        gasControl.msgId = EXPEL_SYS_STATE;
        gasControl.data = 0x00;
        length = 11;
        serialization(gasControl, (char*)data);
        return 0;
    }

    /**
     * @description: 判定msg是否为status
     * @param {int} &msg_id
     * @return {*}
     */    
    bool getStatusMsg(int &msg_id){
        if(msg_id != EXPEL_SYS_STATE_ACK) return false;
        return true;
    }

    /**
     * @description: 构建设备信息
     * @param {SendDevice&} sendDevice
     * @return {*}
     */    
    void BuildDeviceInfo(SendDevice& sendDevice){
        sendDevice.deviceId = atoi(this->getDeviceId().c_str());
        sendDevice.commandCode = "1";
        sendDevice.status = 1;
        sendDevice.workStatus = 1;
        sendDevice.powerStatus = 1;
        sendDevice.batteryStatus = 1;
        sendDevice.num  = 0;
        sendDevice.oxyPressure  = 0;
        sendDevice.gasPressure  = 0;
        sendDevice.remark = "";
        sendDevice.attr1 = std::to_string(this->getVoltage());     // 电压
        sendDevice.attr2 = std::to_string(this->getCurent());     // 电流
        sendDevice.attr3 = std::to_string(this->getPressure());    // 声压
    }
};
