#include "CounterDevice.h"

#include <iostream>
#include <QDateTime>
#include <QDebug>

CounterDevice::CounterDevice(QObject *parent) : QObject(parent)
{
    connect(&this->serialUtil, &QSerialPortUtil::dataRecieved,
                this, &CounterDevice::dataReceivedHandler);

    connect(this, &CounterDevice::successDataCalculate,
            this, &CounterDevice::afterFramePhase);

    kafkaUtil.setBrokers(SettingConfig::getInstance().KAFKA_BROKERS);
    kafkaUtil.setTopic(SettingConfig::getInstance().KAFKA_DATA_TOPIC);
    kafkaUtil.createProducer();
}

CounterDevice::~CounterDevice()
{
    disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved,
                this, &CounterDevice::dataReceivedHandler);
}

void CounterDevice::setComName(QString comName)
{
    this->comName = comName;
}
void CounterDevice::setBaudRate(int baudRate)
{
    this->baudRate = baudRate;
}
QString CounterDevice::getDevCode()
{
    return this->devCode;
}
void CounterDevice::setDevCode(QString devCode)
{
    this->devCode = devCode;
}
void CounterDevice::setDeviceId(QString deviceId)
{
    this->deviceId = deviceId;
}

bool CounterDevice::isSerialOpen()
{
    return this->serialUtil.isOpen();
}

void CounterDevice::initSerialPort()
{
    this->serialUtil.openSerialPort(this->comName, this->baudRate);
}


void CounterDevice::dataReceivedHandler(QByteArray data)
{
    QList<QByteArray> frameList = CounterProtocolBM::extractFrameList(data);

    if (frameList.size() > 0)
    {
        for (int i = 0; i < frameList.size(); i++)
        {
            QByteArray frameByte = frameList.at(i);
            if (CounterProtocolBM::checkFrame(frameByte) == true)
            {
                CounterDataDto * counterData = new CounterDataDto(this);
                counterData->rawFrame = frameByte;
                // ★解析成数据对象
                bool parse = CounterProtocolBM::parseMessureData(frameByte, counterData);

                // 解析成功
                if (parse == true)
                {
                    // 1. 清空dataBuff，等待下一帧的数据
//                    this->dataBuff.clear();

                    if (counterData->channelActive == 0)
                    {
                        continue;
                    }

                    // 2. 补充其他字段
                    QDateTime now = QDateTime::currentDateTime();
                    counterData->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz");
                    counterData->milisecond = now.toMSecsSinceEpoch();
                    counterData->devCode = devCode;

//                    this->afterFramePhase(counterData);

                    // 3 计算数据ID一样的测量数据的时差值，通道值-参考通道值
                    this->pushChannelRawFrame(counterData);

                    // 在此处释放内存，不影响后续显示
                    // 不在此处释放内存则会导致内存持续增加
                    delete counterData;
                }
            }
        }
    }
}

void CounterDevice::afterFramePhase(CounterDataDto * counterData)
{
    // 0. 输出到日志文件中
    QString date = counterData->timestamp.mid(0, 10);

    // 1. 原始字节数组数据
    QString filename = "raw_" + devCode + ".log";
    QString content = counterData->timestamp + " " + counterData->rawFrame.left(counterData->rawFrame.size() - COUNTER_FRAME_TAIL.size());
    QLogUtil::writeRawDataLogByDate(date, filename, content);

    // 2. 各个通道的clock diff数据
    QString chFilename("%1_CH_%2.log");
    chFilename = chFilename.arg(devCode);
    if (counterData->channelId < 10)
    {
        chFilename = chFilename.arg(QString("0%1").arg(counterData->channelId));
    } else
    {
        chFilename = chFilename.arg(counterData->channelId);
    }
    QString channelDataStr = QString("%1 [%2] %3 %4")
            .arg(counterData->timestamp)
            .arg(counterData->frameId)
            .arg(counterData->channelData)
            .arg(counterData->channelClockValueStr);
    QLogUtil::writeChannelDataLogByDate(date, chFilename, channelDataStr);

    // 3. 输出到中间件，执行后续处理过程
    if (SettingConfig::getInstance().NEED_KAFKA == 1)
    {
        QJsonObject jsonObj = counterData->toJSON();
        jsonObj.insert("clientId", SettingConfig::getInstance().CLIENT_ID);
        jsonObj.insert("deviceId", deviceId);
        kafkaUtil.produceMessage(QString(QJsonDocument(jsonObj).toJson(QJsonDocument::Compact)));
    }

    // 4. 在界面上简单显示相差数据结果
    emit this->sendDataToDraw(counterData);
}

void CounterDevice::pushChannelRawFrame(CounterDataDto * counterData)
{
    QString currentFrameId = counterData->frameId;
    QString currentChannelId = QString("%1").arg(counterData->channelId);

    if (counterData->channelId == counterData->channelRefId)
    {
        // 自身是参考通道
        counterData->clone(&bench);
        counterData->channelClockValue = 0;
        counterData->channelClockValueStr = "0";

        emit successDataCalculate(counterData);

        qlonglong thisBench = counterData->channelData;
        // 遍历temp，处理之前的临时暂存的队列
        if (hisList.isEmpty() == false)
        {
            for (int i = 0; i < hisList.size(); i++)
            {
                CounterDataDto * hisItem = hisList.at(i);
                if (qAbs(hisItem->milisecond - bench.milisecond) < 500)
                {
                    hisItem->channelClockValue = (hisItem->channelData - thisBench) * 1E-11;  // 10ps to s
                    hisItem->channelClockValueStr = QString::number(hisItem->channelClockValue, 'f', 12);

                    emit successDataCalculate(hisItem);
                    delete hisItem;
                }
            }

            hisList.clear();
        }
    } else
    {
        // 自身不是参考通道，减去相同frameId的参考通道值
        if (qAbs(bench.milisecond - counterData->milisecond) < 500)
        {
            // 在参考基准中能找到
            qlonglong currentBench = bench.channelData;
            counterData->channelClockValue = (counterData->channelData - currentBench) * 1E-11; // 10ps to s
            counterData->channelClockValueStr = QString::number(counterData->channelClockValue, 'f', 12);

            emit successDataCalculate(counterData);
        } else
        {
            // 暂存，等收到基准之后再处置
            CounterDataDto * copyPoint = new CounterDataDto();

            // ★clone一份对象，存入缓存队列
            counterData->clone(copyPoint);

            hisList.append(copyPoint);
        }
    }
}
