#include "pcapwin.h"
#include <QTextEdit>
#include <QPushButton>
#include <QMessageBox>
#include <QLabel>
#include <QDateTime>
#include <QRadioButton>
#include <QDebug>
#include "globalfunc.h"

PcapWin *PcapWin::newIns(QByteArray &name, QWidget *parent) {
    if(name.isEmpty()) return 0;
    char errbuf[PCAP_ERRBUF_SIZE]{'\0'};
    auto pcapRe = pcap_open_live(name.data(), 65536, PCAP_OPENFLAG_PROMISCUOUS, 50, errbuf);
    if(pcapRe == 0) {
        QMessageBox::critical(parent, "Error", QString(tr("打开网卡失败"))+errbuf);
        return 0;
    }
    auto pcapSend = pcap_open_live(name.data(), 65536, 0, 50, errbuf);
    if(pcapSend == 0) {
        QMessageBox::critical(parent, "Error", QString(tr("打开网卡失败"))+errbuf);
        return 0;
    }
    return new PcapWin(pcapRe, pcapSend, parent);
}

PcapWin::PcapWin(pcap_t *pcapRece, pcap_t *pcapSend, QWidget *parent) : BaseWin{parent}, pcap(pcapSend) {
    setWindowModality(Qt::WindowModal);
    setAttribute(Qt::WA_DeleteOnClose);
    setWindowTitle(tr("网口通信"));
    resize(1024, 720);

    auto vBox = new QVBoxLayout(center);
    vBox->setContentsMargins(0,0,0,0);
    vBox->setSpacing(3);
    vBox->addLayout(addBtns(new QHBoxLayout()));

    auto fdReceive = new QTextEdit;
    fdReceive->setFontFamily("Consolas");
    fdReceive->setReadOnly(true);
    fdReceive->document()->setMaximumBlockCount(200);

    auto hBox = new QHBoxLayout;
    {
        auto vBox = new QVBoxLayout;
        auto hBox2 = new QHBoxLayout;

        hBox2->addWidget(new QLabel(tr("接收:")));
        hBox2->addStretch();

        auto fdStart = new QRadioButton(tr("开始"));
        fdStart->setChecked(true);
        connect(fdStart, &QPushButton::toggled, this, [this](bool checked) {
            thd->status = checked ? 0 : 1;
        });
        hBox2->addWidget(fdStart);
        hBox2->addSpacing(20);

        auto fdEnd = new QRadioButton(tr("暂停"));
        hBox2->addWidget(fdEnd);

        hBox2->addStretch();

        auto btnClear = new QPushButton(tr("清除"));
        btnClear->setMinimumWidth(120);
        connect(btnClear, &QPushButton::clicked, fdReceive, &QTextEdit::clear);
        hBox2->addWidget(btnClear);

        hBox2->addStretch();

        vBox->addLayout(hBox2);

        vBox->addWidget(fdReceive);

        hBox->addLayout(vBox);
    }
    {
        auto wgt = new QWidget;
        wgt->setMaximumWidth(400);

        auto vBox = new QVBoxLayout(wgt);
        vBox->setContentsMargins(0,0,0,0);
        vBox->setSpacing(3);

        auto hBox2 = new QHBoxLayout;
        hBox2->addStretch();

        auto btnSend = new QPushButton(tr("发送"));
        btnSend->setMinimumWidth(120);
        hBox2->addWidget(btnSend);

        hBox2->addStretch();

        auto btnClear = new QPushButton(tr("清除"));
        btnClear->setMinimumWidth(120);
        hBox2->addWidget(btnClear);
        hBox2->addStretch();

        vBox->addLayout(hBox2);

        auto fdSend = new QTextEdit;
        fdSend->setFontFamily("Consolas");
        vBox->addWidget(fdSend);

        connect(btnSend, &QPushButton::clicked, this, [this, fdSend] {
            auto text = fdSend->toPlainText();
            auto len = text.size();
            QByteArray bytes;
            for(int i=0; i<len; i++) {
                auto ch = text[i].toLatin1();
                if((ch>='0' && ch<='9') || (ch>='A' && ch<='F') || (ch>='a' && ch<='f')) bytes.append(ch);
            }
            if(bytes.size() % 2) bytes.append('0');
            bytes = QByteArray::fromHex(bytes);
            if(pcap_sendpacket(pcap, (u_char*)bytes.data(), bytes.size())) {
                QMessageBox::critical(this, "Error", QString(tr("发送失败: "))+pcap_geterr(pcap));
                return;
            }
        });
        connect(btnClear, &QPushButton::clicked, fdSend, &QTextEdit::clear);

        hBox->addWidget(wgt);
    }
    vBox->addLayout(hBox);

    thd = new PcapThread(pcapRece);
    connect(thd, &PcapThread::onMsg, fdReceive, &QTextEdit::append);
    thd->start();
}

PcapThread::PcapThread(pcap_t *pcap) : pcap(pcap) {
    connect(this, &QThread::finished, this, &QThread::deleteLater);
}
void PcapThread::run() {
    pcap_pkthdr *header;
    const u_char *data;
    int res;
    while((res = pcap_next_ex(pcap, &header, &data)) >= 0) {
        if(status==2) return;
        if(status==1 || res == 0) continue; //超时
        if(data[0]!=0x55 || data[1]!=0x55) continue;
        QString data_str;
        data_str.append(QDateTime::fromSecsSinceEpoch(header->ts.tv_sec).toString("yy-MM-dd HH:mm:ss.")+QString::number(header->ts.tv_usec));
        data_str.append(" len:").append(QString::number(header->caplen)).append("/").append(QString::number(header->len)).append("\n");
        char line[LINE_LEN + 1];
        int l = 0;
        for(uint i=0; i<header->caplen; i++) {
            data_str.append(QString::asprintf("%.2x ", data[i]));
            if(i > 13) {
                if(isgraph(data[i]) || data[i] == ' ') line[l] = data[i];
                else line[l] = '.';
                if(l==15) {
                    line[16] = 0;
                    data_str.append("    ").append(line).append("\n");
                    l = 0;
                } else l++;
            } else if(i == 13) {
                data_str.append("\n");
            }
        }
        line[l] = 0;
        data_str.append("    ").append(line).append("\n\n");
        emit onMsg(data_str);
    }
    emit onError(pcap_geterr(pcap));
}
