#include "mainwindow.h"
#include "ui_mainwindow.h"

#define CMD_SCAN            50
#define CMD_INIT            51
#define CMD_SET_SAMPLES     70
#define CMD_SET_SPEED       71

using namespace std;

static double **plot_array;
static char packet_buffer[4096]; //pojme 256 vzorků
char *pch = packet_buffer;

bool scanning_flag = false;

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
//nastavení programu*****************************************************************************
    program_settings.samples = 255;
    program_settings.speed = 250;

    program_settings.max_limit = 550;
    program_settings.min_limit = 450;

    program_settings.port = "/dev/ttyUSB0";
    program_settings.BaudRate = BAUD19200;
    program_settings.FlowControl = FLOW_OFF;
    program_settings.Parity = PAR_NONE;
    program_settings.DataBits = DATA_8;
    program_settings.StopBits = STOP_1;
//vytvoření menu pro výběr portu*****************************************************************
    port_menu = ui->menuSettings->addMenu(tr("Port"));
    QDir dir("/dev");
    QStringList filters;
    filters << "ttyS*" << "ttyUSB*";
    dir.setNameFilters(filters);
    dir.setFilter(QDir::Files | QDir::System);
    QFileInfoList list = dir.entryInfoList();
    port_actions = (QAction**)malloc(list.size()*sizeof(QAction*));
    port_group = new QActionGroup(this);
    for (int i=0; i< list.size(); i++)
    {
        port_actions[i] = new QAction(list.at(i).canonicalFilePath(), this);
        port_actions[i]->setCheckable(true);
        port_group->addAction(port_actions[i]);
        port_menu->addAction(port_actions[i]); 
        if(port_actions[i]->text() == program_settings.port)
            port_actions[i]->setChecked(true);
    }
//vytvoření portu********************************************************************************
    port = new QextSerialPort(program_settings.port);
    port->setBaudRate(program_settings.BaudRate);
    port->setFlowControl(program_settings.FlowControl);
    port->setParity(program_settings.Parity);
    port->setDataBits(program_settings.DataBits);
    port->setStopBits(program_settings.StopBits);
    port->open(QIODevice::ReadWrite);
//inicializace MCU*******************************************************************************
    char dat[2] = {CMD_SET_SAMPLES, program_settings.samples};
    port->write(dat, 2);
    dat[0] = CMD_SET_SPEED;
    dat[1] = program_settings.speed;
    port->write(dat, 2);
    dat[0] = CMD_INIT;
    dat[1] = 0;
    port->write(dat, 2);
//inicializace datových polí*********************************************************************
    plot_array = new double* [2];
    plot_array[0] = new double [program_settings.samples];
    plot_array[1] = new double [program_settings.samples];
    for(int i = 0; i < program_settings.samples; i++)
    {
        plot_array[0][i] = i;
        plot_array[1][i] = 0;
    }

    packet_buffer[0] = '\0';
//vytvoření časovače pro čtení rs232*************************************************************
    read_timer = new QTimer(this);
//spojení signálů a slotů************************************************************************
    connect(ui->actionSave,SIGNAL(triggered(bool)),this,SLOT(slot_MainWindow_save()));
    connect(ui->actionOpen,SIGNAL(triggered(bool)),this,SLOT(slot_MainWindow_open()));
    connect(ui->actionExit,SIGNAL(triggered(bool)),this,SLOT(close()));

    connect(ui->actionScan,SIGNAL(triggered(bool)),this,SLOT(slot_MainWindow_scan()));

    connect(ui->actionScanning,SIGNAL(triggered(bool)),this,SLOT(slot_MainWindow_scan_settings()));
    connect(ui->actionLimits, SIGNAL(triggered()), this, SLOT(slot_MainWindow_limits_settings()));
    connect(port_group,SIGNAL(triggered(QAction*)),this,SLOT(slot_MainWindow_serial_port(QAction*)));

    connect(read_timer, SIGNAL(timeout()), this, SLOT(slot_MainWindow_rs232_read()));
}

MainWindow::~MainWindow()
{
    port->close();
    delete port;

    delete[] plot_array[0];
    delete[] plot_array[1];
    delete[] plot_array;

    delete read_timer;

    delete ui;
}

void MainWindow::changeEvent(QEvent *e)
{
    QMainWindow::changeEvent(e);
    switch (e->type()) {
    case QEvent::LanguageChange:
        ui->retranslateUi(this);
        break;
    default:
        break;
    }
}

void MainWindow::slot_MainWindow_save()
{
    QString s = QFileDialog::getSaveFileName(this,tr("Save LBT data"), "/home", tr("LBT data (*.lbt);;All (*.*)"));
    if(s.isNull()) return;
    FILE *file;
    file = fopen(s.toStdString().c_str(), "w");
    if(!file)
    {
        cerr<<"Nelze otevřít zadaný soubor"<<endl;
    }
    fprintf(file, "%d;%d\n", program_settings.samples, program_settings.speed);
    for(int i = 0; i < program_settings.samples; i++)
        fprintf(file, "%f;%f\n", plot_array[0][i], plot_array[1][i]);
    fclose(file);
}

void MainWindow::slot_MainWindow_open()
{
    QString s = QFileDialog::getOpenFileName(this, tr("Open LBT File"),"/home",tr("LBT data (*.lbt)"));
    QFile file(s);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
        return;

    QTextStream in(&file);
    QString line;
    int i = 0;

    line = in.readLine();
    sscanf(line.toStdString().c_str(), "%d;%d\n", &program_settings.samples, &program_settings.speed);
    resizeArray(program_settings.samples);
    while (i < program_settings.samples)
    {
        line = in.readLine();
        sscanf(line.toStdString().c_str(), "%lf;%lf\n", plot_array[0]+i, plot_array[1]+i);
        i++;
    }

    char dat[2] = {CMD_SET_SAMPLES, program_settings.samples};
    port->write(dat, 2);
    dat[0] = CMD_SET_SPEED;
    dat[1] = program_settings.speed;
    port->write(dat, 2);

    QwtPlotCurve *curve = new QwtPlotCurve("Curve");
    ui->plot_space->clear();
    curve->setData(plot_array[0], plot_array[1], program_settings.samples);
    curve->attach(ui->plot_space);
    ui->plot_space->replot();
}

void MainWindow::slot_MainWindow_scan() //spuštění skenování
{
    if(scanning_flag == false)
    {
        char dat[2] = {CMD_SCAN, 0};
        for(int i = 0; i < program_settings.samples; i++) //nulování vykreslovacího pole
        {
            plot_array[0][i] = i;
            plot_array[1][i] = 0;
        }
        port->write(dat, 2);
        read_timer->start(100);
        scanning_flag = true;
    }
}

void MainWindow::slot_MainWindow_scan_settings() //otevírá okno nabídek a předává mu aktuální nastavení
{
    scan_set_dialog = new ScanSettings(this);
    scan_set_dialog->updateWidgets(program_settings);
    scan_set_dialog->show();
}

void MainWindow::slot_MainWindow_limits_settings()
{
    limits_set_dialog = new LimitsSettings(this);
    limits_set_dialog->updateWidgets(program_settings);
    limits_set_dialog->show();
}

void MainWindow::slot_MainWindow_serial_port(QAction* act) //funguje pouze pokud se ještě program nepokusil o komunikaci
{
    port->close();
    port->setPortName(act->text());
    port->open(QIODevice::ReadWrite);
}

void MainWindow::postprocessing()
{
    double max = 0, min = 1000, max_pos, min_pos;
    double dif_max = 0, tmp;
    int dif_pos = 0;
    double sum1 = 0, sum2 = 0;
    char buffer[30];
    for(int i = 0; i < program_settings.samples; i++)
    {
        if(plot_array[1][i] < min)
        {
            min = plot_array[1][i];
            min_pos = i;
        }
        if(plot_array[1][i] > max)
        {
            max = plot_array[1][i];
            max_pos = i;
        }
        sum1 += plot_array[1][i];
    }
    ui->max_intensity_label->setNum(max);
    ui->min_intensity_label->setNum(min);
    ui->dif_intensity_label->setNum(max-min);
    for(int i = 0; i < program_settings.samples/2; i++)
    {
        if(abs(plot_array[1][i] - plot_array[1][program_settings.samples-1-i]) > dif_max)
        {
            dif_max = abs(plot_array[1][i] - plot_array[1][program_settings.samples-1-i]);
            dif_pos = i;
        }
        sum2 += plot_array[1][i];
    }
    ui->max_asymmetry_label->setNum(dif_max);
    sprintf(buffer, "%1.1f%% %1.1f%%", sum2/sum1*100, (sum1-sum2)/sum1*100);
    ui->global_asymmetry_label->setText(QString(buffer));

    QPen pen;
    QwtPlotCurve *curve1 = new QwtPlotCurve("Curve");
    curve1->setData(&max_pos, &max, 1);
    curve1->setStyle(QwtPlotCurve::NoCurve);
    pen.setColor(Qt::red);
    pen.setWidth(4);
    curve1->setSymbol(QwtSymbol(QwtSymbol::XCross, QBrush(), pen, QSize(9, 9)));
    curve1->attach(ui->plot_space);
    ui->plot_space->replot();
    QwtPlotCurve *curve2 = new QwtPlotCurve("Curve");
    curve2->setData(&min_pos, &min, 1);
    curve2->setStyle(QwtPlotCurve::NoCurve);
    curve2->setSymbol(QwtSymbol(QwtSymbol::XCross, QBrush(), pen, QSize(9, 9)));
    curve2->attach(ui->plot_space);
    ui->plot_space->replot();
    QwtPlotCurve *curve3 = new QwtPlotCurve("Curve");
    tmp = dif_pos;
    curve3->setData(&tmp, &(plot_array[1][dif_pos]), 1);
    curve3->setStyle(QwtPlotCurve::NoCurve);
    pen.setColor(Qt::blue);
    curve3->setSymbol(QwtSymbol(QwtSymbol::Ellipse, QBrush(), pen, QSize(13, 13)));
    curve3->attach(ui->plot_space);
    ui->plot_space->replot();
    QwtPlotCurve *curve4 = new QwtPlotCurve("Curve");
    tmp = program_settings.samples-dif_pos-1;
    curve4->setData(&tmp, &(plot_array[1][program_settings.samples-dif_pos-1]), 1);
    curve4->setStyle(QwtPlotCurve::NoCurve);
    curve4->setSymbol(QwtSymbol(QwtSymbol::Ellipse, QBrush(), pen, QSize(13, 13)));
    curve4->attach(ui->plot_space);
    ui->plot_space->replot();
}

void MainWindow::slot_MainWindow_rs232_read()
{
    char buff[16];
    char *chtmp;
    int tmp1 = -1, tmp2;  

    while(port->atEnd() == true) //vyčtení bufferu sériového zařízení
    {
        port->readLine(buff, 16);
        strcat(packet_buffer, buff);
    }
    while(strrchr(pch, '\n') != NULL) //vybrání a zpracování paketů
    {
        chtmp = strchr(pch, '\n');
        if(chtmp == NULL)
            break;
        strncpy(buff, pch, chtmp-pch);
        buff[chtmp-pch] = '\0';
        pch = chtmp+1;
        sscanf(buff, "%d;%d", &tmp1, &tmp2);
        plot_array[1][tmp1] = 512-tmp2;
        if(tmp1 == program_settings.samples-1)
        {
            packet_buffer[0] = '\0';
            pch = packet_buffer;
            read_timer->stop();
            scanning_flag = false;
        }
    }
    if(tmp1 == -1) return; //pokud se objevila nová data tak se vykreslí
    QwtPlotCurve *curve = new QwtPlotCurve("Curve");
    ui->plot_space->clear();
    curve->setData(plot_array[0], plot_array[1], program_settings.samples);
    curve->attach(ui->plot_space);
    ui->plot_space->replot();
    if(scanning_flag == false)
        postprocessing();
}

void MainWindow::slot_MainWindow_set_scan_ok()
{ 
    program_settings = scan_set_dialog->new_settings; //ukončení okna nastavení a odeslání nastavení do mcu
    scan_set_dialog->close();
    delete scan_set_dialog;
    char dat[2] = {CMD_SET_SAMPLES, program_settings.samples};
    port->write(dat, 2);
    dat[0] = CMD_SET_SPEED;
    dat[1] = program_settings.speed;
    port->write(dat, 2);
    resizeArray(program_settings.samples); //úprava velikosti datového pole podle nové hodnoty "samples"
}

void MainWindow::slot_MainWindow_set_limits_ok()
{
    program_settings = limits_set_dialog->new_settings;
    limits_set_dialog->close();
    delete limits_set_dialog;
}

void resizeArray(int s)
{
    delete[] plot_array[0];
    delete[] plot_array[1];

    plot_array[0] = new double [s];
    plot_array[1] = new double [s];
    for(int i = 0; i < s; i++)
    {
        plot_array[0][i] = i;
        plot_array[1][i] = 0;
    }
}
