#include "cdistancemeterdriver_hl.h"
#include <regex>
constexpr int COMM_LEN = 128;
constexpr char CMD_FINISH_CODE = 0x0D;
constexpr int RESPONSE_LEN = 128;
CDistanceMeterDriver_HL::CDistanceMeterDriver_HL(const QString& name, int32_t id)
    : CMeasHeadDriver(name, id)
{
    std::unique_ptr<CMSerialPort> serialport = std::make_unique<CMSerialPort>(QObject::tr("DistanceMeterPort"), id);
    m_pSerialPort = std::move(serialport); 
    m_Variants.add_Variant(Var_Distance_Measure_Thickness,
                           QObject::trUtf8("DistanceMeasureThickness"), double(-1), false,
                           Variant::TONONE);
}

int32_t CDistanceMeterDriver_HL::freshresult(int32_t chid)
{
    std::string sResponse;
    MakeSendCheckComm((const char*)"%EE#RMD3", sResponse);

    double dVal = stod(sResponse);
    
    CMeasHead* pMeas = GET_CHANNEL(chid, m_iID, CMeasHead);
    pMeas->m_Variants.get_VData(Var_MeasHead_Result_ID)->setValue(dVal);

    //测量出来的片厚
    CMotorDriver* pDriver = GET_CARD(MOTOR_DRIVER, CMotorDriver);

    CMWorkTableDriver* pWorkTableDriver = GET_CARD(WORKTABLE_DRIVER, CMWorkTableDriver);
    Q_ASSERT(pWorkTableDriver);
    double dPosZ = pDriver->get_posdata(MOTORZ, true) - dVal;
    //测量出来的片厚
    double dThickMeasure = pWorkTableDriver->ZPosToDefoucsDis(DistanceSensor, dPosZ, WORKTABLE);

    m_Variants.get_VData(Var_Distance_Measure_Thickness)->setValue(dThickMeasure);
    return RTN_SUCCESS1;
}

int32_t CDistanceMeterDriver_HL::init_driver()
{
    int ret = 0;
    try {

        if (!m_gSystem.IsSimulator()) {
            ret = m_pSerialPort->open();
        }
    } catch (QString ex) {
        throw(QString("%1 %2").arg(m_sName).arg(ex));
    }

    return RTN_SUCCESS1;
}

int32_t CDistanceMeterDriver_HL::exit_driver()
{
    m_pSerialPort->close();
    return RTN_SUCCESS1;
}

QDomElement CDistanceMeterDriver_HL::WriteConfig(QDomDocument& doc, QDomElement& root)
{
    QDomElement element = CMeasHeadDriver::WriteConfig(doc, root);

    QDomElement ele1 = m_pSerialPort->WriteConfig(doc, element);

    return element;
}

int CDistanceMeterDriver_HL::ReadConfig(QDomElement& root)
{
    int iIndex = CMeasHeadDriver::ReadConfig(root);

    QDomNodeList List = root.childNodes();

    iIndex = m_pSerialPort->ReadConfig(List.at(iIndex).toElement());

    return iIndex;
}

void CDistanceMeterDriver_HL::SendCommand(const char* pCommand, std::string& sResponse)
{
    QMutexLocker locker(&m_CardMutex);
    int isize = strlen(pCommand);

    try {
        m_pSerialPort->send(pCommand, isize);
        int32_t irtn = m_pSerialPort->wait();
        char pResponse[RESPONSE_LEN] = { 0 };
        m_pSerialPort->receive(pResponse, irtn);
        sResponse = pResponse;
    } catch (const QString& ex) {
        QString info = m_sName + " " + ex;
        MQT_THROW_CODESTR(ALARM_DISTANCMETER_COMMUNICATION, info);
    }
}

void CDistanceMeterDriver_HL::MakeSendCheckComm(const char* pSendData, std::string& sResponse)
{
    std::string sComm = PackageCommand(pSendData);
    SendCommand(sComm.c_str(), sResponse);
    CheckResponse(sResponse);
}

std::string CDistanceMeterDriver_HL::PackageCommand(const char* pSendData)
{
    //"%EE#RMD3" Return "%EE#RMD36EC"
    std::string send = pSendData;
    Q_ASSERT(!send.empty());
    //TODO:按头部至文本最后1个文字的逻辑异或计算
    uint8_t result = send[0];
    for (int32_t i = 1; i < send.length(); i++) {
        result ^= send[i];
    }
    return fmt::format("{}{:X}{}", send, result, CMD_FINISH_CODE);
}

void CDistanceMeterDriver_HL::CheckResponse(std::string& sResponse)
{
    //sResponse = "%EE$RMD-001.4127506D";
    if(sResponse.empty()) {
        MQT_THROW_CODESTR(ALARM_POWERMETER_COMMUNICATION, QObject::trUtf8("DistanceMeter ComPort Response Count:%1 Incorrect")
                          .arg(sResponse.length()));
    }

    if(sResponse.rfind("%EE$") != 0) {
        MQT_THROW_CODESTR(ALARM_POWERMETER_COMMUNICATION, QObject::trUtf8("DistanceMeter;ComPort Command has illage Word(%1)")
                          .arg(sResponse.c_str()));
    }

    //%EE$R +指令信号部 +/- 003.123456 + BCC部 +　Finish_Code
    //012.345678 3位整数 6位小数
    std::regex pattern(R"(^%EE\$.*\r$)");
    std::smatch matches;
    std::string info = sResponse;
    if(m_gSystem.IsSimulator()){
        info = "%EE$-001.4127506D";
    }

    if (false == std::regex_search(info, pattern)) {
        MQT_THROW_CODESTR(ALARM_POWERMETER_COMMUNICATION, QObject::trUtf8("DistanceMeter;ComPort Command has illage Word(%1)")
            .arg(sResponse.c_str()));
    }

    //find
    
    pattern = R"([+-]+[0-9]{3}\.[0-9]{6})";
    if (!std::regex_search(info, matches, pattern)) {
        MQT_THROW_CODESTR(ALARM_POWERMETER_COMMUNICATION, QObject::trUtf8("DistanceMeter;ComPort Command has illage Word(%1)")
            .arg(sResponse.c_str()));
    }
    std::string sMatch = matches[0].str();

    try {
        double dVal = stod(sMatch);
        sResponse = std::to_string(dVal);
    } catch (...) {
        MQT_THROW_CODESTR(ALARM_POWERMETER_COMMUNICATION, QObject::trUtf8("DistanceMeter;ComPort Command has illage Word(%1)")
            .arg(sResponse.c_str()));
    }
}
