#include "xmltoolsinterface.h"
#include "ui_xmltoolsinterface.h"

XmlToolsInterface::XmlToolsInterface(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::XmlToolsInterface),
    xmlProcessor()
{
    ui->setupUi(this);
    this->setAttribute(Qt::WA_DeleteOnClose, true); //destroy itself once finished.
    this->xmlProcessor = new XmlProcessor(UtilVago::getAppPath(), &this->listToProccess);

    // setup the correct input options for the current selection
    on_rbFilterRelativeElements_clicked();
    on_cbFilterParentElement_toggled(ui->cbFilterParentElement->isChecked());
    on_cbFilterAttributeName_toggled(ui->cbFilterAttributeName->isChecked());
    on_cbXmlToolsOperation_currentIndexChanged(ui->cbXmlToolsOperation->currentText());

    connect(this->xmlProcessor, SIGNAL(resultConversion(QString,int)), this, SLOT(TXmlToolsResult(QString,int)));
}

XmlToolsInterface::~XmlToolsInterface()
{
    delete xmlProcessor;
    delete ui;
}

void XmlToolsInterface::dropEvent(QDropEvent* event)
{
    const QMimeData* mimeData = event->mimeData();

    event->acceptProposedAction();

    // Set the input file. This file type was already validated by the dragEnterEvent at this point
    ui->leInputInputFiles->setText(mimeData->urls().at(0).toLocalFile());
}

void XmlToolsInterface::dragEnterEvent(QDragEnterEvent *event){
    const QMimeData* mimeData = event->mimeData();

    if (mimeData->hasUrls())
    {
        if(mimeData->urls().size() == 1 && QFileInfo(mimeData->urls().at(0).toLocalFile()).suffix().toUpper() == "XML"){
            event->accept();
        }
    }
}

void XmlToolsInterface::on_rbFilterRelativeElements_clicked()
{
    ui->leFilterXPathExpression->setEnabled(false);
    ui->leFilterElement->setEnabled(true);
    ui->leFilterParentElement->setEnabled(true);
    ui->lbFilterElement->setEnabled(true);
    ui->cbFilterParentElement->setEnabled(true);
    ui->leFilterAttributeName->setEnabled(true);
    ui->leFilterAttributeValue->setEnabled(true);
    ui->lbFilterAttributeValue->setEnabled(true);
    ui->cbFilterAttributeName->setEnabled(true);

    on_cbFilterParentElement_toggled(ui->cbFilterParentElement->isChecked());
    on_cbFilterAttributeName_toggled(ui->cbFilterAttributeName->isChecked());

    setCommand();
}

void XmlToolsInterface::on_rbFilterXPathExpression_clicked()
{
    ui->leFilterElement->setEnabled(false);
    ui->leFilterParentElement->setEnabled(false);
    ui->lbFilterElement->setEnabled(false);
    ui->cbFilterParentElement->setEnabled(false);
    ui->leFilterAttributeName->setEnabled(false);
    ui->leFilterAttributeValue->setEnabled(false);
    ui->lbFilterAttributeValue->setEnabled(false);
    ui->cbFilterAttributeName->setEnabled(false);
    ui->leFilterXPathExpression->setEnabled(true);

    setCommand();
}

void XmlToolsInterface::on_cbXmlToolsOperation_currentIndexChanged(const QString &arg1)
{
    ui->leInputCurrentValues->setEnabled(true);
    ui->leInputNewValues->setEnabled(true);
    ui->leInputDiffOldNewValue->setEnabled(true);
    ui->leInputPositions->setEnabled(true);

    if(arg1 == "Add Values"){
        ui->leInputCurrentValues->setEnabled(false);
        ui->leInputDiffOldNewValue->setEnabled(false);
        ui->leInputPositions->setEnabled(false);
    }
    else if(arg1 == "Remove Values"){
        ui->leInputNewValues->setEnabled(false);
        ui->leInputDiffOldNewValue->setEnabled(false);
        ui->leInputPositions->setEnabled(false);
    }
    else if(arg1 == "Replace Single Value"){
        ui->leInputDiffOldNewValue->setEnabled(false);
        ui->leInputPositions->setEnabled(false);
    }
    else if(arg1 == "Replace All Values"){
        ui->leInputCurrentValues->setEnabled(false);
        ui->leInputDiffOldNewValue->setEnabled(false);
    }
    else if(arg1 == "Update Elements"){
        ui->leInputCurrentValues->setEnabled(false);
        ui->leInputNewValues->setEnabled(false);
        ui->leInputPositions->setEnabled(false);
    }
    else if(arg1 == "Invert Elements"){
        ui->leInputCurrentValues->setEnabled(false);
        ui->leInputNewValues->setEnabled(false);
        ui->leInputDiffOldNewValue->setEnabled(false);
        ui->leInputPositions->setEnabled(false);
    }

    setCommand();
}

void XmlToolsInterface::on_cbFilterParentElement_toggled(bool checked)
{
    ui->leFilterParentElement->setEnabled(checked);
}

void XmlToolsInterface::on_cbFilterAttributeName_toggled(bool checked)
{
    ui->leFilterAttributeName->setEnabled(checked);
    ui->leFilterAttributeValue->setEnabled(checked);
}

void XmlToolsInterface::on_pbInputBrowse_clicked()
{
    QString result = QFileDialog::getOpenFileName(this,"Choose the XML file...","./" , "XML Files (*.xml)");

    if(!result.isEmpty()){
        ui->leInputInputFiles->setText(result);
    }
}

void XmlToolsInterface::on_pbPreviewOperation_clicked()
{
    if(!validateInput()){
        return;
    }
    this->listToProccess.clear();

    // Copy the target file to temporary location and aply to it the command

    QString currentFileLocation = ui->leInputInputFiles->text();
    QString previewFileLocation=GlobalVars::VagoTemporaryDir+"/"+QFileInfo(currentFileLocation).fileName();

    QFile oldFile(previewFileLocation);

    // Create temp folder if it doesn't exist
    if(!QDir(GlobalVars::VagoTemporaryDir).exists()){
        QDir().mkdir(GlobalVars::VagoTemporaryDir);
    }

    if(oldFile.exists()){
        if(!oldFile.remove()){
            UtilVago::showAndLogErrorPopUpLogButton("Couldn't remove old temporary file to preview XML patch! Existing file:\n"
                                                    + previewFileLocation
                                                    );
        }
    }

    if(!QFile::copy(currentFileLocation, previewFileLocation)){
        UtilVago::showAndLogErrorPopUpLogButton("Couldn't create temporary file to preview the XML patch!\nFrom: " +
                                                currentFileLocation +
                                                "\nTo: " + previewFileLocation
                                                );
        return;
    }

    this->listToProccess.append(buildCommand(previewFileLocation).remove(0,9)); // 0,9 removes XmlTools from the beginning
    this->previewInProgress = true;

    this->xmlProcessor->start();
    this->xmlProcessor->wait(); // wait for the XML to be processed

    XmlToolsInterfaceCommandPreview *previewWindow = new XmlToolsInterfaceCommandPreview(currentFileLocation, previewFileLocation, this);
    previewWindow->show();
}

void XmlToolsInterface::on_pbApplyOperation_clicked()
{
    if(!validateInput()){
        return;
    }

    this->listToProccess.clear();
    this->listToProccess.append(ui->leOperationCommandGenCommand->text().remove(0,9)); // 0,9 removes XmlTools from the beginning
    this->xmlProcessor->start();
}

// return true if valid, false otherwise
bool XmlToolsInterface::validateInput()
{

    if(ui->leInputInputFiles->text().trimmed().isEmpty()){
        Util::Dialogs::showError("You must provide an Input File!");
        return false;
    }

    if(ui->rbFilterRelativeElements->isChecked() && ui->leFilterElement->text().trimmed().isEmpty()){
        Util::Dialogs::showError("With Relative Elements checked you must provide a Element Name!");
        return false;
    }

    if(ui->cbFilterParentElement->isChecked() && ui->leFilterParentElement->text().trimmed().isEmpty()){
        Util::Dialogs::showError("Parent Element is checked but none was provided!");
        return false;
    }

    if(ui->cbFilterAttributeName->isChecked()){
        if(ui->leFilterAttributeName->text().trimmed().isEmpty())
        {
            Util::Dialogs::showError("Attribute Name is checked but none was provided!");
            return false;
        }

        if(ui->leFilterAttributeValue->text().trimmed().isEmpty())
        {
            Util::Dialogs::showError("With Attribute Name checked you must provide a Attribute Value!");
            return false;
        }
    }

    if(ui->rbFilterXPathExpression->isChecked() && ui->leFilterXPathExpression->text().trimmed().isEmpty())
    {
        Util::Dialogs::showError("X-Path Expression is checked but none was provided!");
        return false;
    }

    if(ui->cbXmlToolsOperation->currentText() == "Add Values" && ui->leInputNewValues->text().isEmpty()){
        Util::Dialogs::showError(R"|(With "Add Values" operation selected you must provide the "New Value(s)" to be added.)|");
        return false;
    }

    if(ui->cbXmlToolsOperation->currentText() == "Remove Values" && ui->leInputCurrentValues->text().isEmpty()){
        Util::Dialogs::showError(R"|(With "Remove Value" operation selected you must provide the "Current Value(s)" to be removed.)|");
        return false;
    }

    return true;
}

void XmlToolsInterface::TXmlToolsResult(QString result, int numErrors){

    if(!this->previewInProgress){
        QApplication::alert(this); //Show a notification if window is not active (only when not previewing)
    }

    if(numErrors!=0){
        QString sNumErrors=QString::number(numErrors);
        if(numErrors>1){
            UtilVago::showErrorPopUpLogButton(result+"\n This is the last of "+sNumErrors+" errors.");
        }
        else{
            UtilVago::showErrorPopUpLogButton(result);
        }
    }
    else if(numErrors == 0){
        // if there's a preview in progress don't display the message below
        if(!this->previewInProgress){
            Util::Dialogs::showInfo("File(s) processed with sucess!");
        }
    }

    this->previewInProgress = false;
}

void XmlToolsInterface::setCommand(){
  ui->leOperationCommandGenCommand->setText(buildCommand());
}

QString XmlToolsInterface::buildCommand(const QString &alternativeFileLocation){
    QString currCommand;

    QString currOperation = ui->cbXmlToolsOperation->currentText();

    if(currOperation == "Add Values"){
        currCommand += "--add-values ";
    }
    else if(currOperation == "Remove Values"){
        currCommand += "--remove-values ";
    }
    else if(currOperation == "Replace Single Value"){
        currCommand += "--replace-value ";
    }
    else if(currOperation == "Replace All Values"){
        currCommand += "--replace-all-values ";
    }
    else if(currOperation == "Update Elements"){
        currCommand += "--update-elements ";
    }
    else if(currOperation == "Invert Elements"){
        currCommand += "--invert-elements ";
    }

    if(ui->leInputNewValues->isEnabled()){
        currCommand += "--new-val " + Util::String::insertQuotes(ui->leInputNewValues->text()) + " ";
    }

    if(ui->leInputCurrentValues->isEnabled()){
        currCommand += "--current-val " + Util::String::insertQuotes(ui->leInputCurrentValues->text()) + " ";
    }

    if(ui->leInputPositions->isEnabled() && !ui->leInputPositions->text().trimmed().isEmpty()){
        currCommand += "--positions " + Util::String::insertQuotes(ui->leInputPositions->text()) + " ";
    }

    if(ui->leInputDiffOldNewValue->isEnabled()){
        currCommand += "--diff-old-new-val " + Util::String::insertQuotes(ui->leInputDiffOldNewValue->text()) + " ";
    }

    if(ui->rbFilterRelativeElements->isChecked()){
        if(ui->leFilterElement->isEnabled()){
            currCommand += "--element-name " + Util::String::insertQuotes(ui->leFilterElement->text()) + " ";
        }
        if(ui->leFilterParentElement->isEnabled()){
            currCommand += "--parent-element-name " + Util::String::insertQuotes(ui->leFilterParentElement->text()) + " ";
        }
        if(ui->leFilterAttributeName->isEnabled()){
            currCommand += "--attribute-name " + Util::String::insertQuotes(ui->leFilterAttributeName->text()) + " ";
            currCommand += "--attribute-value " + Util::String::insertQuotes(ui->leFilterAttributeValue->text()) + " ";
        }
    }
    else{
        if(ui->leFilterXPathExpression->isEnabled()){
            currCommand += "--xpath-expression " + Util::String::insertQuotes(ui->leFilterXPathExpression->text()) + " ";
        }
    }

    if(alternativeFileLocation.isEmpty()){
        currCommand += "--files " + Util::String::insertQuotes(ui->leInputInputFiles->text());
    }
    else{
        currCommand += "--files " + Util::String::insertQuotes(alternativeFileLocation);
    }


    if(ui->cbOptionsNoBackups->isChecked()){
        currCommand += " --no-backups";
    }

    return "XmlTools " + currCommand;
}

void XmlToolsInterface::on_pbOperationCommandCopyToClipboard_clicked()
{
    QApplication::clipboard()->setText(ui->leOperationCommandGenCommand->text());
}

void XmlToolsInterface::on_leInputInputFiles_textChanged(const QString &arg1)
{
    // If it contains a wildcard we are not able to guarantee that it is editing only one file, in this case we can't preview the result
    if(arg1.contains("*") || arg1.contains("?")){
        ui->pbPreviewOperation->setEnabled(false);
    }
    else{
        ui->pbPreviewOperation->setEnabled(true);
    }

    setCommand();
}

void XmlToolsInterface::on_leFilterElement_textChanged(const QString &)
{
    setCommand();
}

void XmlToolsInterface::on_leFilterParentElement_textChanged(const QString &)
{
    setCommand();
}

void XmlToolsInterface::on_leFilterAttributeName_textChanged(const QString &)
{
    setCommand();
}

void XmlToolsInterface::on_leFilterAttributeValue_textChanged(const QString &)
{
    setCommand();
}

void XmlToolsInterface::on_leInputCurrentValues_textChanged(const QString &)
{
    setCommand();
}

void XmlToolsInterface::on_leInputNewValues_textChanged(const QString &)
{
    setCommand();
}

void XmlToolsInterface::on_leInputPositions_textChanged(const QString &)
{
    setCommand();
}

void XmlToolsInterface::on_leInputDiffOldNewValue_textChanged(const QString &)
{
    setCommand();
}

void XmlToolsInterface::on_cbOptionsNoBackups_toggled(bool)
{
    setCommand();
}
