//  Copyright (2010-2013) Cédric Coussinet (cedric.coussinet@nomoseed.net)
//
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published
//  by the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with this program. If not, see <http://www.gnu.org/licenses/>

#include <QtWebKit/QWebFrame>

#include <QDir>
#include <QWebElement>
#include <QMessageBox>
#include <QFileDialog>

#include "logging.h"
#include "mainwindow.h"
#include "xsltprocessor.h"

#if WIN32
const QString Rterm = "R/bin/R";
#else
const QString Rterm = "R";
#endif

Logging::Logging(QMainWindow * mainWindow, QWebView * webView){
    this->mainWindow = mainWindow;
    this->webView = webView;

    QWebFrame *webFrame = webView->page()->mainFrame();
    webFrame->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAlwaysOff);
    webFrame->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAlwaysOff);

    const QByteArray open(QString("\""+tr("Open")+"\"").toUtf8());
    const QByteArray add(QString("\""+tr("Add")+"\"").toUtf8());
    const QByteArray reset(QString("\""+tr("Reset")+"\"").toUtf8());
    const QByteArray table(QString("\""+tr("Table")+"\"").toUtf8());
    const QByteArray graphic(QString("\""+tr("Graphic")+"\"").toUtf8());
    const QByteArray expor(QString("\""+tr("Export")+"\"").toUtf8());
    const QByteArray database(QString("\""+tr("Database")+"\"").toUtf8());
    const QByteArray view(QString("\""+tr("View")+"\"").toUtf8());
    const QByteArray query(QString("\""+tr("Query")+"\"").toUtf8());

    const char * params[19];
    params[0]="open";
    params[1]= open.constData();
    params[2]="add";
    params[3]= add.constData();
    params[4]="reset";
    params[5]= reset.constData();
    params[6]="table";
    params[7]= table.constData();
    params[8]="graphic";
    params[9]= graphic.constData();
    params[10]="export";
    params[11]= expor.constData();
    params[12]="database";
    params[13]= database.constData();
    params[14]="view";
    params[15]= view.constData();
    params[16]="query";
    params[17]= query.constData();
    params[18]=NULL;

    QString logging= "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?><logging xmlns=\"http://www.nomoseed.org/nomosdk\"/>";

    const QByteArray out = XSLTProcessor::transform(QByteArray("web/logging/logging.xsl"), logging, params);

    QByteArray url(QDir::currentPath().toUtf8());
    url.append("/web/logging/logging.xhtml");

    QObject::connect(webView->page()->mainFrame(), SIGNAL(javaScriptWindowObjectCleared()),this, SLOT(populateJavaScriptWindowObject()));

    webView->setContent( out, "application/xhtml+xml", QUrl::fromLocalFile(url));
    connect (&rProcess, SIGNAL (readyReadStandardOutput()), this, SLOT(outputR()));
    connect (&rProcess, SIGNAL (readyReadStandardError ()), this, SLOT(errorR()));
    QStringList arguments;
    arguments << "--save";
    rProcess.start(Rterm, arguments);
 //   rProcess.write("setwd('"+QDir::currentPath ().toUtf8()+"')\n");
    rProcess.write("source('web/logging/logging.r')\n");
}

Logging::~Logging(){
    rProcess.write("q('no')\n");
    rProcess.kill();
}

void Logging::close (){
    pathDB.clear();
    webView->page()->mainFrame()->evaluateJavaScript("document.getElementById('add').disabled = 'disabled'");
    webView->page()->mainFrame()->evaluateJavaScript("document.getElementById('reset').disabled = 'disabled'");
    webView->page()->mainFrame()->evaluateJavaScript("document.getElementById('table').disabled = 'disabled'");
    webView->page()->mainFrame()->evaluateJavaScript("document.getElementById('graphic').disabled = 'disabled'");
    webView->page()->mainFrame()->evaluateJavaScript("document.getElementById('export').disabled = 'disabled'");
}

QString Logging::openDB (const QString path){
    QString result = "";
    result = validateDB(path);
    if (result.isEmpty()){
        if (pathDB.isEmpty()){
            webView->page()->mainFrame()->evaluateJavaScript("document.getElementById('add').disabled = ''");
            webView->page()->mainFrame()->evaluateJavaScript("document.getElementById('reset').disabled = ''");
            webView->page()->mainFrame()->evaluateJavaScript("document.getElementById('table').disabled = ''");
            webView->page()->mainFrame()->evaluateJavaScript("document.getElementById('graphic').disabled = ''");
        }
        pathDB = path;
        rProcess.write("rm(rule, type, item, component)\n");
        rProcess.write("rm(log, input, output, premise, conclusion)\n");
        rProcess.write(QString("rule = read.csv('"+pathDB+"/rule.csv', strip.white=TRUE)\n").toUtf8().data());
        rProcess.write(QString("type = read.csv('"+pathDB+"/type.csv', strip.white=TRUE)\n").toUtf8().data());
        rProcess.write(QString("item = read.csv('"+pathDB+"/item.csv', strip.white=TRUE)\n").toUtf8().data());
        rProcess.write(QString("component = read.csv('"+pathDB+"/component.csv', strip.white=TRUE)\n").toUtf8().data());
        QDir directory(pathDB);
        if (QFile::exists(directory.absoluteFilePath("log.csv")))
            rProcess.write(QString("log = read.csv('"+pathDB+"/log.csv', strip.white=TRUE)\n").toUtf8().data());
        if (QFile::exists(directory.absoluteFilePath("input.csv")))
            rProcess.write(QString("input = read.csv('"+pathDB+"/input.csv', strip.white=TRUE)\n").toUtf8().data());
        if (QFile::exists(directory.absoluteFilePath("output.csv")))
            rProcess.write(QString("output = read.csv('"+pathDB+"/output.csv', strip.white=TRUE)\n").toUtf8().data());
        if (QFile::exists(directory.absoluteFilePath("premise.csv")))
            rProcess.write(QString("premise = read.csv('"+pathDB+"/premise.csv', strip.white=TRUE)\n").toUtf8().data());
        if (QFile::exists(directory.absoluteFilePath("conclusion.csv")))
            rProcess.write(QString("conclusion = read.csv('"+pathDB+"/conclusion.csv', strip.white=TRUE)\n").toUtf8().data());
    }
    if (result.isEmpty())
        webView->page()->mainFrame()->evaluateJavaScript("nomoSDK.tableView (document.getElementsByTagName('textarea')[0].value);");
    return result;
}

void Logging::openDatabase (){
    QFileDialog dialog(mainWindow, tr("Choose a directory..."), "", "");
    dialog.setWindowState(Qt::WindowNoState);
    dialog.setWindowFlags(Qt::Window | Qt::WindowTitleHint | Qt::WindowCloseButtonHint);
    dialog.setFileMode(QFileDialog::Directory);
    dialog.setViewMode(QFileDialog::Detail);
    dialog.setOptions(QFileDialog::DontUseNativeDialog);
    if (dialog.exec()){
        QString result = openDB (dialog.directory().absolutePath());
        if (!result.isEmpty())
            QMessageBox::warning(dynamic_cast<MainWindow*>(mainWindow), QObject::tr("Error"), result);
    }
}

void Logging::addDatabase (){
    QStringList fileNames = dynamic_cast<MainWindow*>(mainWindow)->selectFile (QObject::tr("Open a log file..."), QObject::tr("All log files (*.pr *.fr);;Partial log of rules(*.pr);;Full log of rules(*.fr)"));
    if (!fileNames[0].isEmpty()) {
        QStringList arguments;
        arguments << "-udb";
        arguments << pathDB + QDir::separator();
        arguments << fileNames[0];
        QProcess nomotools;
        nomotools.start(toolsName, arguments);
        nomotools.waitForFinished();
    }
    rProcess.write(QString("rule = read.csv('"+pathDB+"/rule.csv', strip.white=TRUE)\n").toUtf8().data());
    rProcess.write(QString("log = read.csv('"+pathDB+"/log.csv')\n").toUtf8().data());
    QDir directory(pathDB);
    if (QFile::exists(directory.absoluteFilePath("input.csv")))
        rProcess.write(QString("input = read.csv('"+pathDB+"/input.csv', strip.white=TRUE)\n").toUtf8().data());
    if (QFile::exists(directory.absoluteFilePath("output.csv")))
        rProcess.write(QString("output = read.csv('"+pathDB+"/output.csv', strip.white=TRUE)\n").toUtf8().data());
    if (QFile::exists(directory.absoluteFilePath("premise.csv")))
        rProcess.write(QString("premise = read.csv('"+pathDB+"/premise.csv', strip.white=TRUE)\n").toUtf8().data());
    if (QFile::exists(directory.absoluteFilePath("conclusion.csv")))
        rProcess.write(QString("conclusion = read.csv('"+pathDB+"/conclusion.csv', strip.white=TRUE)\n").toUtf8().data());

}

void Logging::resetDatabase (){
    QFile Rule (pathDB+"/rule.csv");
    QByteArray Line;
    QByteArray Buffer;
    Rule.open(QFile::ReadOnly);
    Line = Rule.readLine();
    while (Line.size()>2) {
        Buffer = Buffer + Line;
        Line = Rule.readLine();
    };
    Rule.close();
    Rule.open(QFile::WriteOnly);
    Rule.write(Buffer);
    Rule.close();
  //  qWarning(Buffer.data());
    rProcess.write(QString("rule = read.csv('"+pathDB+"/rule.csv', strip.white=TRUE)\n").toUtf8().data());
    rProcess.write(QString("type = read.csv('"+pathDB+"/type.csv', strip.white=TRUE)\n").toUtf8().data());
    rProcess.write(QString("item = read.csv('"+pathDB+"/item.csv', strip.white=TRUE)\n").toUtf8().data());
    rProcess.write(QString("component = read.csv('"+pathDB+"/component.csv', strip.white=TRUE)\n").toUtf8().data());
    QFile::remove(pathDB+QDir::separator()+"log.csv");
    QFile::remove(pathDB+QDir::separator()+"input.csv");
    QFile::remove(pathDB+QDir::separator()+"output.csv");
    QFile::remove(pathDB+QDir::separator()+"premise.csv");
    QFile::remove(pathDB+QDir::separator()+"conclusion.csv");
    rProcess.write("rm(log, input, output, premise, conclusion)\n");
}

void Logging::openSQL (const QString path){
    QFile sqlf(path);
    sqlf.open(QFile::ReadOnly);
    QWebElement e = webView->page()->mainFrame()->documentElement().findFirst("textarea");
    e.setPlainText(QString(sqlf.readAll()));
    sqlf.close();
}

QString Logging::validateDB(const QString path){
    QDir directory(path);
    QString result = "";
    if (!QFile::exists(directory.absoluteFilePath("rule.csv")) ||
        !QFile::exists(directory.absoluteFilePath("item.csv")) ||
        !QFile::exists(directory.absoluteFilePath("type.csv")) ||
        !QFile::exists(directory.absoluteFilePath("component.csv")))
        result = QObject::tr("A repertory of log database must have the following four files: rule.csv, item.csv, type.csv and component.csv");
    return result;
}

void Logging::populateJavaScriptWindowObject(){
    webView->page()->mainFrame()->addToJavaScriptWindowObject("nomoSDK", this);
}

void Logging::outputR(){
  //  qWarning("outputR");
    QString output = rProcess.readAllStandardOutput();
  //  qWarning(output.toUtf8().data());
    if (output.contains("OkTableView"))
            showTableView();
    else if (output.contains("OkGraphicView"))
            showGraphicView();
}

void Logging::errorR(){
  //  qWarning("errorR");
    QString output = rProcess.readAllStandardError();
  //  qWarning(output.toUtf8().data());
    if (output.contains("RS-DBI driver")){
        QWebElement e = webView->page()->mainFrame()->documentElement().findFirst("#screen");
        e.setPlainText(output);
    }
}

void Logging::graphicView(const QString sql){
    webView->page()->mainFrame()->evaluateJavaScript("document.getElementById('export').disabled = 'disabled'");
    QFile::remove("web/logging/color.csv");
    QFile::remove("web/logging/view.csv");
    QRect e = webView->page()->mainFrame()->documentElement().findFirst("#screen").geometry();
    rProcess.write(QString("graphicView(\""+sql+"\""+","+QString::number(e.height()-10)+","+QString::number(e.width()-10)+")\n").toUtf8().data());
}

void Logging::showGraphicView(){
    QFile svg("web/logging/view.svg");
    svg.open(QFile::ReadOnly);
    QWebElement e = webView->page()->mainFrame()->documentElement().findFirst("#screen");
    e.setInnerXml(svg.readAll());
    svg.close();
    webView->page()->mainFrame()->evaluateJavaScript("document.getElementById('export').disabled = ''");
}

void Logging::tableView(const QString sql){
    webView->page()->mainFrame()->evaluateJavaScript("document.getElementById('export').disabled = 'disabled'");
    QFile::remove("web/logging/color.csv");
    QFile::remove("web/logging/view.svg");
    rProcess.write(QString("tableView(\""+sql+"\")\n").toUtf8().data());
}

void Logging::showTableView(){
    QString table;
    QFile csv("web/logging/view.csv");
    csv.open(QFile::ReadOnly);
    if (QFile::exists("web/logging/color.csv")){
        QFile colors("web/logging/color.csv");
        QString color;
        QString line;
        colors.open(QFile::ReadOnly);
        color = colors.readLine();
        line = csv.readLine();
        table = "<table style=\"text-align:center\"><tr><td>";
        line.replace(',', "</td><td>");
        table = table + line + "</td></tr>";
        while (!colors.atEnd()) {
            color = colors.readLine().trimmed();
            line = csv.readLine().trimmed();
            line.replace(',', "</td><td>");
            table = table + "<tr style=\"background-color:"+color+"\"><td>" + line + "</td></tr>";
        }
        table.append("</table>");
        colors.close();
    }
    else{
        table = csv.readAll();
        table.replace(',', "</td><td>");
        table.replace('\n', "</td></tr><tr><td>");
        table = "<table style=\"text-align:center\"><tr><td>" + table + "</td></tr></table>";
    }
    QWebElement e = webView->page()->mainFrame()->documentElement().findFirst("#screen");
    e.setInnerXml(table);
    csv.close();
    webView->page()->mainFrame()->evaluateJavaScript("document.getElementById('export').disabled = ''");
}

void Logging::exportView(){
    QString filename;
    if (QFile::exists("web/logging/view.csv")){
        filename = QFileDialog::getSaveFileName(mainWindow, QObject::tr("Save View"), QDir::currentPath(), QObject::tr("View CSV (*.csv)"));
        if (!filename.isNull()){
            QFile::remove(filename);
            QFile::copy("web/logging/view.csv",filename);
        }
    }
    else if (QFile::exists("web/logging/view.svg")){
        filename = QFileDialog::getSaveFileName(mainWindow, QObject::tr("Save View"), QDir::currentPath(), QObject::tr("View SVG (*.svg)"));
        if (!filename.isNull()){
            QFile::remove(filename);
            QFile::copy("web/logging/view.svg",filename);
        }
    }
}
