#include "serial_qt_transport.h"
#include "serial/serial_types.h"

#include <QSerialPort>
#include <QtGlobal>
#include <qcontainerfwd.h>

namespace {
QSerialPort::DataBits mapDataBits(int bits) {
    switch (bits) {
    case 5:
        return QSerialPort::Data5;
    case 6:
        return QSerialPort::Data6;
    case 7:
        return QSerialPort::Data7;
    case 8:
    default:
        return QSerialPort::Data8;
    }
}

QSerialPort::StopBits mapStopBits(int bits) {
    switch (bits) {
    case 2:
        return QSerialPort::TwoStop;
    case 1:
    default:
        return QSerialPort::OneStop;
    }
}

QSerialPort::Parity mapParity(const QString& parity) {
    const QString key = parity.trimmed().toUpper();
    if (key == QStringLiteral("E") || key == QStringLiteral("EVEN"))
        return QSerialPort::EvenParity;
    if (key == QStringLiteral("O") || key == QStringLiteral("ODD"))
        return QSerialPort::OddParity;
    if (key == QStringLiteral("M") || key == QStringLiteral("MARK"))
        return QSerialPort::MarkParity;
    if (key == QStringLiteral("S") || key == QStringLiteral("SPACE"))
        return QSerialPort::SpaceParity;
    return QSerialPort::NoParity;
}
} // namespace

QtSerialTransport::QtSerialTransport(QObject* parent)
    : ISerialTransport(parent) {}

QtSerialTransport::~QtSerialTransport() {
    close();
}

void QtSerialTransport::ensurePort_() {
    if (m_port)
        return;

    m_port = new QSerialPort(this);
    connect(m_port, &QSerialPort::readyRead, this, [this]() {
        const QByteArray data = m_port->readAll();
        if (!data.isEmpty())
            emit bytesReceived(data);
    });
}

void applyConfigDebug(const SerialConfig& config) {
#if DEBUG_MODE
    QString strd = "";
    strd += "baud:" + QString::number(config.baudRate);
#endif
}

void QtSerialTransport::applyConfig_(const SerialConfig& config) {
    if (!m_port)
        return;
    applyConfigDebug(config);
    m_port->setBaudRate(config.baudRate);
    m_port->setDataBits(mapDataBits(config.dataBits));
    m_port->setStopBits(mapStopBits(config.stopBits));
    m_port->setParity(mapParity(config.parity));
    // TODO:待实现内容(根据SerialConfig扩展软件/硬件流控配置)
    m_port->setFlowControl(QSerialPort::NoFlowControl);
}

bool QtSerialTransport::open(const SerialConfig& config, QString* error) {
    ensurePort_();

    if (config.portName.trimmed().isEmpty()) {
        if (error)
            *error = QStringLiteral("Port name is empty");
        return false;
    }

    if (m_port->isOpen())
        m_port->close();

    m_port->setPortName(config.portName);
    applyConfig_(config);

    const bool ok = m_port->open(QIODevice::ReadWrite);
    if (!ok) {
        if (error)
            *error = m_port->errorString();
        return false;
    }

    if (error)
        error->clear();
    return true;
}

void QtSerialTransport::close() {
    if (m_port && m_port->isOpen())
        m_port->close();
}

bool QtSerialTransport::writeBytes(const QByteArray& data, QString* error) {
    if (!m_port || !m_port->isOpen()) {
        if (error)
            *error = QStringLiteral("Serial port not open");
        return false;
    }

    if (data.isEmpty()) {
        if (error)
            error->clear();
        return true;
    }

    const qint64 written = m_port->write(data);
    if (written < 0) {
        if (error)
            *error = m_port->errorString();
        return false;
    }

    if (error)
        error->clear();
    return true;
}
