#include <Graphics/Dialogs/InputDialog.hpp>

#include <QDomDocument>
#include <QFileDialog>
#include <QImage>
#include <QMessageBox>
#include <QTextStream>

#include <Converter.hpp>
#include <GraphvizIntegrator.hpp>
#include <utility>
#include <Utils.hpp>

// TODO don't move cursor on parse
// TODO don't clear text box on invalid automaton

InputDialog::InputDialog(std::shared_ptr<abstraction::Value> p_automaton)
    : ui(new Ui::InputDialog)
{
    ui->setupUi(this);
    this->setWindowTitle("Input");
    this->setAutomaton(std::move(p_automaton));
}

std::shared_ptr<abstraction::Value> InputDialog::getAutomaton() {
    return this->automaton;
}

void InputDialog::setAutomaton(std::shared_ptr<abstraction::Value> p_automaton, bool updateText) {
    this->automaton = std::move(p_automaton);
    QSignalBlocker blockerXML(ui->plainTextEdit_xml);
    QSignalBlocker blockerText(ui->plainTextEdit_text);

    if (this->automaton) {
        if (auto text = Converter::toXML(this->automaton)) {
            ui->plainTextEdit_xml->setPlainText(*text);
        }
        else {
            ui->plainTextEdit_xml->clear();
        }

        if ( updateText ) {
            if (auto text = Converter::toString(this->automaton)) {
                ui->plainTextEdit_text->setPlainText(*text);
            }
            else {
                ui->plainTextEdit_text->clear();
            }
        }

        if (auto image = Converter::toPNG(this->automaton)) {
            ui->label_image->setPixmap(QPixmap::fromImage(*image));
            ui->scrollArea->setFixedSize(ui->tab_image->size());
            this->setTabShown(ui->tab_image, true);
        }
        else {
            this->setTabShown(ui->tab_image, false);
        }
    }
    else {
        this->setTabShown(ui->tab_image, false);
        ui->plainTextEdit_xml->document()->clear();
        ui->plainTextEdit_text->document()->clear();
        ui->label_image->clear();
    }
}

void InputDialog::on_generateRandomAutomatonButton_clicked() {
    this->setAutomaton(Utils::generateRandomAutomaton());
}

void InputDialog::on_generateRandomGrammarButton_clicked() {
    this->setAutomaton(Utils::generateRandomGrammar());
}

void InputDialog::on_okCancelButtonBox_accepted() {
    this->accept();
}

void InputDialog::on_okCancelButtonBox_rejected() {
    this->reject();
}

void InputDialog::on_plainTextEdit_xml_textChanged() {
    if (auto l_automaton = Converter::tryParse(ui->plainTextEdit_xml->toPlainText())) {
        this->setAutomaton(std::move(l_automaton));
    }
}

void InputDialog::on_plainTextEdit_text_textChanged() {
    if (auto l_automaton = Converter::tryParse(ui->plainTextEdit_text->toPlainText())) {
        this->setAutomaton(std::move(l_automaton), false);
    }
}

void InputDialog::on_openFileButton_clicked() {
    QString filename(QFileDialog::getOpenFileName(this,
                                                  tr("Open file"),
                                                  QDir::homePath(),
                                                  "XML files (*.xml);;Text files (*.txt)"));
    if (filename.isEmpty()) {
        return;
    }

    QFile file(filename);
    if (!file.open(QFile::ReadOnly | QFile::Text)) {
        QMessageBox::warning(this, "Warning", "File does not exist.");
        return;
    }

    QTextStream stream(&file);
    QString l_data = stream.readAll();
    file.close();

    if (auto l_automaton = Converter::tryParse(l_data)) {
        this->setAutomaton(std::move(l_automaton));
    }
    else {
        QMessageBox::critical(this, "Error", "Failed to parse input.");
    }
}

void InputDialog::setTabShown(QWidget* tab, bool value) {
    ui->tabWidget->setTabEnabled(ui->tabWidget->indexOf(tab), value);
}
