#include <QFileDialog>
#include <QGroupBox>
#include <QHBoxLayout>
#include <QThreadPool>
#include <QVBoxLayout>

#include "LogConversionDialog.h"
#include "LogConversionRunnable.h"

LogConversionDialog::LogConversionDialog(QWidget *parent) : QDialog(parent) {
    setWindowTitle("Convert a Binary Log");

    QVBoxLayout *mainLayout = new QVBoxLayout();
    setLayout(mainLayout);

    setMinimumWidth(500); // seems reasonable

    // Input section

    QGroupBox *inputBox = new QGroupBox("Input Binary Log");
    QHBoxLayout *inputLayout = new QHBoxLayout();
    inputBox->setLayout(inputLayout);

    inputEdit = new QLineEdit();
    inputEdit->setPlaceholderText("Path to input binary file");
    inputLayout->addWidget(inputEdit);

    inputBrowseButton = new QPushButton(QIcon(":fileopen.png"), "Browse...");
    connect(inputBrowseButton, &QPushButton::clicked, this, &LogConversionDialog::browseInputFile);
    inputLayout->addWidget(inputBrowseButton);

    // Output section

    QGroupBox *outputBox = new QGroupBox("Output Text Log");
    QHBoxLayout *outputLayout = new QHBoxLayout();
    outputBox->setLayout(outputLayout);

    outputEdit = new QLineEdit();
    outputEdit->setPlaceholderText("Path to output text file");
    outputLayout->addWidget(outputEdit);

    outputBrowseButton = new QPushButton(QIcon(":fileopen.png"), "Browse...");
    connect(outputBrowseButton, &QPushButton::clicked, this, &LogConversionDialog::browseOutputFile);
    outputLayout->addWidget(outputBrowseButton);

    // Progress section

    QGroupBox *progressBox = new QGroupBox("Progress");
    QVBoxLayout *progressLayoutVertical = new QVBoxLayout();
    progressBox->setLayout(progressLayoutVertical);

    QWidget *progressWidget = new QWidget();
    QHBoxLayout *progressLayoutHorizontal = new QHBoxLayout();
    progressWidget->setLayout(progressLayoutHorizontal);
    progressLayoutVertical->addWidget(progressWidget);

    progressBar = new QProgressBar();
    progressLayoutHorizontal->addWidget(progressBar);

    convertButton = new QPushButton("Convert");
    connect(convertButton, &QPushButton::clicked, this, &LogConversionDialog::convert);
    progressLayoutHorizontal->addWidget(convertButton);

    errorLabel = new QLabel();
    errorLabel->setObjectName("log_conversion_error"); // selector for stylesheet
    progressLayoutVertical->addWidget(errorLabel);

    // Put it all together

    mainLayout->addWidget(inputBox);
    mainLayout->addWidget(outputBox);
    mainLayout->addWidget(progressBox);
    mainLayout->addStretch();
}

LogConversionDialog::~LogConversionDialog() {
    // This dialog lives forever
}

void LogConversionDialog::showEvent(QShowEvent *event) {

    inputEdit->clear();
    outputEdit->clear();
    progressBar->reset();
    errorLabel->clear();

    QDialog::showEvent(event);
}

void LogConversionDialog::reject() {

    // Only close if unlocked
    if (convertButton->isEnabled()) {
        QDialog::reject();
    }
}

void LogConversionDialog::browseInputFile() {

    QString path = QFileDialog::getOpenFileName(this, "Open Binary Log", inputEdit->text(), "Binary Logs (*.bin)");

    inputEdit->setText(path);
    progressBar->reset();
}

void LogConversionDialog::browseOutputFile() {

    QString path = QFileDialog::getSaveFileName(this, "Save Text Log", outputEdit->text(), "Text Logs (*.csv)");

    if (path.isEmpty()) {
        return;
    }

    if (!path.endsWith(".csv", Qt::CaseInsensitive)) {
        path += ".csv";
    }

    outputEdit->setText(path);
    progressBar->reset();
}

void LogConversionDialog::convert() {

    setLocked(true);
    errorLabel->clear();

    LogConversionRunnable *r = new LogConversionRunnable(inputEdit->text(), outputEdit->text());
    connect(r, &LogConversionRunnable::progress, this, &LogConversionDialog::onProgress);
    connect(r, &LogConversionRunnable::error, this, &LogConversionDialog::onError);
    QThreadPool::globalInstance()->start(r);
}

void LogConversionDialog::onProgress(unsigned int done, unsigned int total) {

    progressBar->setMaximum(total);
    progressBar->setValue(done);

    if (done == total) {
        setLocked(false);
    }
}

void LogConversionDialog::onError(int code) {

    progressBar->reset();

    switch (code) {

    case LogConversionRunnable::Error::ERROR_OPEN_INPUT:
        errorLabel->setText("ERROR: Cannot read input file");
        break;

    case LogConversionRunnable::Error::ERROR_OPEN_OUTPUT:
        errorLabel->setText("ERROR: Cannot write output file");
        break;

    default:
        errorLabel->clear();
        break;
    }

    setLocked(false);
}

void LogConversionDialog::setLocked(bool locked) {

    inputEdit->setDisabled(locked);
    outputEdit->setDisabled(locked);
    inputBrowseButton->setDisabled(locked);
    outputBrowseButton->setDisabled(locked);
    convertButton->setDisabled(locked);
}
