#include "chart_file.h"
#include "src/model_select/model_select.h"
#include "ui_chart_file.h"

#include <QDebug>
#include <QMessageBox>
#include <QFile>

#define MAX_LINE_NUM 1000

chart_file::chart_file(QWidget *parent) : QWidget(parent),
                                          ui(new Ui::chart_file),
                                          chart(new QChart),
                                          timer(new QTimer),
                                          count(0),
                                          line_now_count(0),
                                          line_last_count(0),
                                          read_time(1)

{
    ui->setupUi(this);

    // 初始化变量
    time = nullptr;
    point1 = nullptr;
    point2 = nullptr;

    // 设置点的数量
    pointsSize = 200;

    // 初始化字体颜色
    initFontColor();

    // 初始化读取数据
    initReadData();

    // 设置定时器间隔为100毫秒
    timer->setInterval(10);

    // 启动定时器
    timer->start();
}

chart_file::~chart_file()
{
    // 释放UI对象和动态分配的内存
    delete ui;

    // 释放动态分配的数组内存
    delete[] time;
    delete[] point1;
    delete[] point2;

    // 释放二维数组tempDis的内存
    for (int i = 0; i < pointsNum; i++)
    {
        delete[] tempDis[i];
    }
    delete[] tempDis;
}

// 鼠标滚轮事件处理函数
void chart_file::wheelEvent(QWheelEvent *event)
{
    if (event->angleDelta().y() > 0)
    {
        chart->zoom(1.1);
    }
    else
    {
        chart->zoom(10 / 1.1);
    }

    QWidget::wheelEvent(event);
}

void chart_file::initUI()
{
    initChart();
}
// 初始化曲线图
void chart_file::initChart()
{
    // chart->createDefaultAxes();

    /**修改**/
    axisX = new QValueAxis();
    axisX->setTitleFont(QFont("Microsoft YaHei", 10, QFont::Normal, true));
    axisX->setTitleText("Time(s)");
    axisX->setGridLineVisible(true);
    chart->addAxis(axisX, Qt::AlignBottom);

    axisY = new QValueAxis();
    axisY->setTitleFont(QFont("Microsoft YaHei", 10, QFont::Normal, true));
    axisY->setTitleText("值");
    axisY->setGridLineVisible(true);
    chart->addAxis(axisY, Qt::AlignLeft);

    for (int i = 0; i < pointsNum; i++)
    {
        series[i]->attachAxis(axisX);
        series[i]->attachAxis(axisY);
    }
    /**修改**/
    chart->legend()->hide();
    chartView = new QChartView(chart);
    chartView->setRenderHint(QPainter::Antialiasing); // 抗锯齿渲染
    // 为 scope_1 设置布局
    QVBoxLayout *layout = new QVBoxLayout(ui->scope_1);
    layout->addWidget(chartView);
}
// 初始化信号槽连接
// 初始化槽函数，连接信号和槽
void chart_file::initSlot()
{
    connect(timer, SIGNAL(timeout()), this, SLOT(timerSlot()));
    connect(ui->allRadioButton, SIGNAL(clicked()), this, SLOT(selectAll()));
    connect(ui->invertRadioButton, SIGNAL(clicked()), this, SLOT(invertSelect()));

    for (int i = 0; i < pointsNum; i++)
    {
        connect(checkBoxVector.at(i), SIGNAL(toggled(bool)), this, SLOT(checkboxChanged()));
        connect(series[i], SIGNAL(hovered(QPointF, bool)), this, SLOT(tipSlot(QPointF, bool)));
    }
}

/*
 for (int i=0;i<pointsNum;i++)
    {
        QVector<QPointF> oldData = series[i]->pointsVector();
        QVector<QPointF> data;

        if(oldData.size()<pointsSize){
            data=oldData;
        }
        else {
            oldData.removeFirst();
            data=oldData;
        }
    }
*/
// 添加图表数据
struct ValueRange
{
    float minY = std::numeric_limits<float>::max();    // 初始为正无穷
    float maxY = std::numeric_limits<float>::lowest(); // 初始为负无穷
};

ValueRange valueRanges[8]; // MAX_POINTS_NUM为最大数据系列数量

void chart_file::addChartData(float time, float *pointsDis)
{
    float globalMinX = 0;
    float globalMaxX = time;
    float globalMinY = pointsDis[0];
    float globalMaxY = pointsDis[0];

    for (int i = 0; i < pointsNum; i++)
    {
        // 获取第 i 个数据系列的点向量
        QVector<QPointF> data = series[i]->pointsVector();

        data.append(QPointF(time, pointsDis[i]));

        float minX = data.at(0).x();
        float maxX = data.at(0).x();
        float minY = data.at(0).y();
        float maxY = data.at(0).y();

        for (int j = 0; j < data.size(); j++)
        {
            if (minY > data.at(j).y())
                minY = data.at(j).y();
            if (maxY < data.at(j).y())
                maxY = data.at(j).y();
        }

        if (i == 0)
        {
            for (int j = 0; j < data.size(); j++)
            {
                if (maxX < data.at(j).x())
                    maxX = data.at(j).x();
            }

            globalMaxX = maxX;
        }

        globalMinY = globalMinY < minY ? globalMinY : minY;
        globalMaxY = globalMaxY > maxY ? globalMaxY : maxY;

        series[i]->replace(data);
        valueRanges[i].minY = std::min(valueRanges[i].minY, minY);
        valueRanges[i].maxY = std::max(valueRanges[i].maxY, maxY);

        tempDis[i][0] = pointsDis[i];
        tempDis[i][1] = maxY;
        tempDis[i][2] = minY;
    }

    addTableData(tempDis);

    axisX->setRange(globalMinX, globalMaxX);
    axisY->setRange(globalMinY - (globalMaxY - globalMinY) * 0.1, globalMaxY + (globalMaxY - globalMinY) * 0.1);
}

// 设置点的数量
void chart_file::setPointsNum(int num)
{
    if (num > 9)
    {
        QMessageBox::information(this, "Warnning", "The number of points exceed 9!");
        return;
    }

    tempDis = new float *[num];

    pointsNum = num;
    // model->setRowCount(num);

    // 该函数用于初始化图表中的数据系列，并为每个数据系列设置颜色和临时数据存储空间
    // 参数:
    // - pointsNum: 数据系列的数量
    // - series: 指向数据系列数组的指针
    // - colorTable: 包含每个数据系列颜色的QList
    // - chart: 指向图表对象的指针
    // - tempDis: 指向临时数据存储数组的指针
    for (int i = 0; i < pointsNum; i++)
    {
        series[i] = new QLineSeries();
        series[i]->setColor(colorTable.at(i));
        chart->addSeries(series[i]);
        tempDis[i] = new float[3];
    }

    initUI();
    initTable(num);
    initSlot();
}

// 添加表格数据
void chart_file::addTableData(float **pointsDis)
{
    for (int i = 0; i < pointsNum; i++)
    {
        for (int j = 0; j < 1; j++)
        {
            model->setItem(i, j + 1, new QStandardItem(QString::number(pointsDis[i][j])));
            model->item(i, j + 1)->setForeground(QBrush(colorTable.at(i)));
            model->item(i, j + 1)->setTextAlignment(Qt::AlignCenter);
        }
    }
}

// 初始化表格
void chart_file::initTable(int pointsNumber)
{
    ui->allRadioButton->setChecked(true);

    model = new QStandardItemModel();
    model->setColumnCount(2);
    model->setHorizontalHeaderItem(0, new QStandardItem(QObject::tr("曲线编号")));
    model->setHorizontalHeaderItem(1, new QStandardItem(QObject::tr("当前值")));
    // model->setHorizontalHeaderItem(2, new QStandardItem(QObject::tr("Peak(mm)")));
    // model->setHorizontalHeaderItem(3, new QStandardItem(QObject::tr("Valley(mm)")));

    ui->tableView->setModel(model);

    ui->tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
    ui->tableView->verticalHeader()->hide();
    ui->tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
    ui->tableView->setColumnWidth(1, 100);

    model->setRowCount(pointsNumber);

    // 此函数用于在表格视图中创建多个复选框，并将它们添加到模型中
    // 每个复选框的标签为 "Point" 加上序号，并根据颜色数组设置样式
    // 最后，将复选框添加到表格视图中，并设置其初始状态为选中
    QString str = "";
    for (int i = 0; i < pointsNumber; i++)
    {
        str = "NGS干扰仿真曲线";
        str += QString::number(i + 1);
        QCheckBox *box = new QCheckBox(str, ui->tableView);
        box->setStyleSheet(strColor[i]);

        checkBoxVector.append(box);

        model->setItem(i, 0, new QStandardItem(""));
        ui->tableView->setIndexWidget(model->index(i, 0), checkBoxVector.at(i));
        model->item(i, 0)->setTextAlignment(Qt::AlignCenter);
        checkBoxVector.at(i)->setChecked(true);
    }
}

// 全选所有点
void chart_file::selectAll()
{
    for (int i = 0; i < checkBoxVector.size(); i++)
        checkBoxVector.at(i)->setChecked(true);
}

// 初始化字体颜色
void chart_file::initFontColor()
{
    colorTable.append(QColor(255, 0, 0));    // red
    colorTable.append(QColor(0, 0, 255));    // blue
    colorTable.append(QColor(0, 255, 0));    // green
    colorTable.append(QColor(139, 0, 0));    // dark red
    colorTable.append(QColor(255, 255, 0));  // yellow
    colorTable.append(QColor(0, 0, 0));      // black
    colorTable.append(QColor(128, 42, 42));  // 棕色
    colorTable.append(QColor(160, 32, 240)); // purple
    colorTable.append(QColor(0, 255, 255));  // 青色

    strColor[0] = "QCheckBox{color:rgb(255,0,0)}";
    strColor[1] = "QCheckBox{color:rgb(0,0,255)}";
    strColor[2] = "QCheckBox{color:rgb(0,255,0)}";
    strColor[3] = "QCheckBox{color:rgb(139,0,0)}";
    strColor[4] = "QCheckBox{color:rgb(255,255,0)}";
    strColor[5] = "QCheckBox{color:rgb(128,42,42)}";
    strColor[7] = "QCheckBox{color:rgb(160,32,240)}";
    strColor[8] = "QCheckBox{color:rgb(0,255,255)}";
}

// 反选所有点
void chart_file::invertSelect()
{
    for (int i = 0; i < checkBoxVector.size(); i++)
    {
        if (checkBoxVector.at(i)->checkState())
            checkBoxVector.at(i)->setChecked(false);
        else
            checkBoxVector.at(i)->setChecked(true);
    }
}

// 复选框状态改变处理函数
void chart_file::checkboxChanged()
{
    for (int i = 0; i < pointsNum; i++)
    {
        if (checkBoxVector.at(i)->checkState())
        {
            series[i]->setVisible(true);
        }
        else
        {
            series[i]->setVisible(false);
        }
    }
}

// 初始化读取数据
void chart_file::initReadData()
{
    QString name = "D:/desktop/NGS/model_git/model_zl/tcp/data/data_output_1.txt";

    QFile readFile(name);
    int i = 0;

    if (!readFile.open(QIODevice::ReadOnly | QIODevice::Text))
    {
        QMessageBox::information(nullptr, "Warning", "Fail to read the file");
        return;
    }

    QTextStream readStream(&readFile);
    QString line;

    time = new float[100000];
    point1 = new float[100000];
    point2 = new float[100000];

    while (i < MAX_LINE_NUM)
    {
        line = readStream.readLine();

        if (!line.isEmpty())
        {
            QStringList list = line.split(QRegularExpression(" "), Qt::SkipEmptyParts);
            time[i] = list.at(0).toFloat();
            point1[i] = list.at(1).toFloat();
            point2[i] = list.at(2).toFloat();
            line_now_count++;
        }

        i++;
    }

    readFile.close();
}
// 每当曲线显示完全尝试读取新的数据,若无尝试提示信息
void chart_file::add_read_data()
{

    QString name = QString("D:/desktop/NGS/model_git/model_zl/tcp/data/data_output_%1.txt").arg(read_time);
    line_last_count = line_now_count;
    QFile readFile(name);
    int i = 0;

    if (!readFile.open(QIODevice::ReadOnly | QIODevice::Text))
    {
        QMessageBox::information(nullptr, "Warning", "Fail to read the file");
        return;
    }

    QTextStream readStream(&readFile);
    QString line;

    while (i < MAX_LINE_NUM)
    {
        line = readStream.readLine();

        if (!line.isEmpty())
        {
            QStringList list = line.split(QRegularExpression(" "), Qt::SkipEmptyParts);

            time[i + line_last_count] = list.at(0).toFloat();
            point1[i + line_last_count] = list.at(1).toFloat();
            point2[i + line_last_count] = list.at(2).toFloat();
            line_now_count++;
        }

        i++;
    }

    readFile.close();
}

// 添加数据
void chart_file::addData()
{
    if (count < MAX_LINE_NUM * read_time)
    { // 确保不会越界
        float y[2];
        y[0] = point1[count];
        y[1] = point2[count];

        addChartData(time[count], y);
        count++;
    }
}
//获取指定文件夹下文件数目
int chart_file::getFileNum(QString path)
{
    QDir dir(path);
    int count = 0;
    foreach (QFileInfo fileInfo, dir.entryInfoList(QDir::Files))
    {
        count++;
    }
    return count;
}



// 定时器槽函数
void chart_file::timerSlot()
{

    if (QObject::sender() == timer)
    {
        if (count >= MAX_LINE_NUM * read_time)
        {
            timer->stop(); // 停止定时器v
            send_time = getFileNum("D:/desktop/NGS/model_git/model_zl/tcp/data/");
            MessageDialog md(
                QString("曲线显示完全，请选择是否继续显示"),
                QString("当前曲线显示完成%1/%2个曲线，是否继续显示下一个曲线？").arg(read_time).arg(send_time),
                MESSAGE_LEVEL_WARNING);
            int ret = md.exec();
            if (ret)
            {
                read_time++;
                add_read_data();
                timer->start(); // 重新启动定时器
            }
            
        }
        else
        {
            addData();
        }
    }
}

void chart_file::on_btn_clear_clicked()
{
    timer->stop(); // 停止定时器

    for (int i = 0; i < pointsNum; i++)
    {
        series[i]->clear();
    }
    count = 0; // 重置计数
    chart->update();
    chartView->repaint();

    timer->start(); // 重新启动定时器（如果需要）
}

void chart_file::on_btn_save_clicked()
{
    for (int i = 0; i < pointsNum; i++)
    {
        series[i]->clear();
    }
}
