#include "TedsWriterDevice.h"
#include "TedsWriterDeviceErrors.h"
#include "LQError.h"
#include "teds_writer_proto.h"
#include <QDebug>

TedsWriterDevice::TedsWriterDevice() {

}

void TedsWriterDevice::detect(LQError &err) {
    m_dev.detect(err, {{TEDSWRTR_USB_VID, TEDSWRTR_USB_PID}});

    if (err.isSuccess()) {
        readInfo(err);
    }
}

void TedsWriterDevice::close() {
    m_dev.close();
}

bool TedsWriterDevice::checkTedsPresent(LQError &err) {
    QByteArray val;
    ctlReqRx(TEDSWRTR_USBCMD_GET_STATUS,  TEDSWRTR_STATUS_PARAM_TEDSMEM, 0, 4, val, err);
    return err.isSuccess() && (val.size() > 0) && (val.at(0) != 0);
}

void TedsWriterDevice::writeTedsData(quint16 addr, const QByteArray &data, LQError &err) {
    ctlReqTx(TEDSWRTR_USBCMD_TEDSMEM_WRITE, addr, 0, data, err);
}

void TedsWriterDevice::readTedsData(quint16 addr, quint16 len, QByteArray &data, LQError &err) {
    ctlReqRx(TEDSWRTR_USBCMD_TEDSMEM_READ, addr, 0, len, data, err);
}

void TedsWriterDevice::ctlReqTx(quint8 req, quint16 wValue, quint16 wIndex, const QByteArray &data, LQError &err) {
    m_dev.ctlVendorReqTx(req, wValue, wIndex, data, err);
    if (!err.isSuccess()) {
        getDevError(err);
    }
}

void TedsWriterDevice::ctlReqRx(quint8 req, quint16 wValue, quint16 wIndex, quint16 reqLen, QByteArray &data, LQError &err) {
    m_dev.ctlVendorReqRx(req, wValue, wIndex, reqLen, data, err);
    if (!err.isSuccess()) {
        getDevError(err);
    }
}

void TedsWriterDevice::getDevError(LQError &err) {
    LQError reqErr;
    QByteArray  rxArr;
    m_dev.ctlVendorReqRx(TEDSWRTR_USBCMD_GET_LAST_ERR, 0, 0, 4, rxArr, reqErr);
    if (reqErr.isSuccess() && (rxArr.size() == 4)) {
        quint32 devErrCode =
                (static_cast<quint32>(static_cast<quint8>(rxArr.at(0))) << 0) |
                (static_cast<quint32>(static_cast<quint8>(rxArr.at(1))) << 8) |
                (static_cast<quint32>(static_cast<quint8>(rxArr.at(2))) << 16) |
                (static_cast<quint32>(static_cast<quint8>(rxArr.at(3))) << 24);
        err = TedsWriterDeviceErrors::devError(devErrCode);
    } else {
        err += reqErr;
    }
}

void TedsWriterDevice::readInfo(LQError &err) {

    QByteArray fwNameArr, fwVerArr, organArr, authorArr, hashArr;
    quint64 burnDataS {0};
    ctlReqRx(TEDSWRTR_USBCMD_GET_INFO,  TEDSWRTR_INFO_PARAM_FWNAME, 0, max_dev_string_len, fwNameArr, err);
    if (err.isSuccess()) {
        ctlReqRx(TEDSWRTR_USBCMD_GET_INFO,  TEDSWRTR_INFO_PARAM_FWVER, 0, max_dev_string_len, fwVerArr, err);
    }
    if (err.isSuccess()) {
        ctlReqRx(TEDSWRTR_USBCMD_GET_INFO,  TEDSWRTR_INFO_PARAM_ORGNAME, 0, max_dev_string_len, organArr, err);
    }
    if (err.isSuccess()) {
        ctlReqRx(TEDSWRTR_USBCMD_GET_INFO,  TEDSWRTR_INFO_PARAM_FWAUTHOR, 0, max_dev_string_len, authorArr, err);
    }
    if (err.isSuccess()) {
        QByteArray dataArr;
        ctlReqRx(TEDSWRTR_USBCMD_GET_INFO,  TEDSWRTR_INFO_PARAM_BURNDATE, 0, max_dev_string_len, dataArr, err);
        if (err.isSuccess() && (dataArr.size() >= 8)) {
            burnDataS = ((quint64)(quint8)dataArr.at(0) << 0)
                    | ((quint64)(quint8)dataArr.at(1) << 8)
                    | ((quint64)(quint8)dataArr.at(2) << 16)
                    | ((quint64)(quint8)dataArr.at(3) << 24)
                    | ((quint64)(quint8)dataArr.at(4) << 32)
                    | ((quint64)(quint8)dataArr.at(5) << 40)
                    | ((quint64)(quint8)dataArr.at(6) << 48)
                    | ((quint64)(quint8)dataArr.at(7) << 56);
        }
    }
    if (err.isSuccess()) {
        ctlReqRx(TEDSWRTR_USBCMD_GET_INFO,  TEDSWRTR_INFO_PARAM_FWHASH, 0, max_dev_string_len, hashArr, err);
    }

    if (err.isSuccess()) {
        m_info = TedsWriterDeviceInfo{
                QString::fromUtf8(fwNameArr),
                QString::fromUtf8(fwVerArr),
                QString::fromUtf8(authorArr),
                QString::fromUtf8(organArr),
                QDateTime::fromSecsSinceEpoch(burnDataS),
                hashArr};
    }
}
