//  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 <QtGui/QMessageBox>
#include <QtGui/QFileDialog>
#include <QSettings>
#include <QDateTime>
#include <QProcess>
#include <QDirIterator>
#include <QTimer>

#include <libxml/parser.h>
#include <libxml/xpath.h>
#include <libxml/xpathInternals.h>

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

#include "reception.h"
#include "logging.h"
#include "benchmark.h"

#include "xsltprocessor.h"

MainWindow::MainWindow(const QLocale locale, QString arg, QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow){
    this->locale = locale;
    ui->setupUi(this);
    this->arg = arg;
    benchmarkTab = this->findChild<QWidget *>("benchmarkTab");
    benchmark = Benchmark::getInstance(this, dynamic_cast<QWebView*>(benchmarkTab->childAt(0,0)));
    loggingTab = this->findChild<QWidget *>("loggingTab");
    logging = Logging::getInstance(this, dynamic_cast<QWebView*>(loggingTab->childAt(0,0)));
    receptionTab = this->findChild<QWidget *>("receptionTab");
    Reception::getInstance(this, dynamic_cast<QWebView*>(receptionTab->childAt(0,0)));
    editorTab = this->findChild<QWidget *>("editorTab");
    editor = Editor::getInstance(this, dynamic_cast<QWebView*>(editorTab->childAt(0,0)));
    manualTab = this->findChild<QWidget *>("manualTab");
    QWebFrame *webFrame = dynamic_cast<QWebView*>(manualTab->childAt(0,0))->page()->mainFrame();
    webFrame->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAlwaysOff);
    tabWidget = this->findChild<QTabWidget *>("tabWidget");
    QSettings settings;
    QString language = settings.value("Locale").toString().split("_").at(0);
    if (language != "fr")
        beginManualPath ="http://nomoseed.com/" + language + "/";
    else
        beginManualPath = "http://nomoseed.com/";
    endManualPath = "?do=login&u=nomosdk&p=nomoSDK";
    int i;
    const int count = tabWidget->count();
    for(i=0; i<count; i++)
    {
        tabWidget->removeTab(0);
    }
    backgroundWidget = this->findChild<QWidget *>("backgroundWidget");
    buttonsWidget = this->findChild<QWidget *>("buttonsWidget");

    QAction* openAct = new QAction(this);
    openAct->setShortcuts(QKeySequence::Save);
    connect(openAct, SIGNAL(triggered()), this, SLOT(on_saveButton_clicked()));
    buttonsWidget->addAction(openAct);

    QWebSettings *defaultSettings = QWebSettings::globalSettings();
    defaultSettings->setAttribute(QWebSettings::PrivateBrowsingEnabled, true);

    QString interfaces= "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?><interfaces>";
    QStringList qmFilter;
    qmFilter << "*.xsl";
    QDirIterator interfacesDir("transformations", qmFilter,QDir::Files | QDir::NoSymLinks);
    while(interfacesDir.hasNext())
    {
        QStringList item = interfacesDir.next().split("_");
        if (item[0] == "transformations/interface" && item[2].endsWith("xsl"))
            interfaces.append("<interface language=\""+item[1]+"\" extension=\""+item[2].remove(".xsl")+"\" />");
    }
    interfaces.append("</interfaces>");
    QFile interfacesFile("interfaces.xml");
    interfacesFile.open (QFile::WriteOnly);
    interfacesFile.write(interfaces.toUtf8());
    interfacesFile.close();
    showReception();
    if (arg != "")
        QTimer::singleShot(500, this, SLOT(openProject()));
}

MainWindow::~MainWindow(){
    QFile::remove("local.uni");
    QFile::remove("local.prg");
    QFile::remove("local.mod");
    QFile::remove("local.bas");
    QFile::remove("local.eng");
    QFile::remove("local.lnk");
    QFile::remove("formalism.log");
    QFile::remove("macro.log");
    QDir dir;
    dir.setNameFilters(QStringList("*.seed"));
    QStringList list = dir.entryList ();
    for (int i = 0; i < list.size(); ++i)
        dir.remove(list.at(i));
    delete ui;
    benchmark->close();
    Benchmark::kill();
    editor->close();
    Editor::kill();
    Logging::kill();
    Reception::kill();
    xmlCleanupMemory ();
}

QLocale MainWindow::getLocale(){
    return this->locale;
}

QStringList MainWindow::selectFile(QString title, QString list){
    QFileDialog dialog(this, title, "", list);
    dialog.setWindowState(Qt::WindowNoState);
    dialog.setWindowFlags(Qt::Window | Qt::WindowTitleHint | Qt::WindowCloseButtonHint);
    dialog.setFileMode(QFileDialog::ExistingFile);
    dialog.setViewMode(QFileDialog::Detail);
    dialog.setOption(QFileDialog::DontUseNativeDialog, true);

    if (dialog.exec())
        return dialog.selectedFiles();
    else
        return QStringList ("");
}

void MainWindow::selectProject(){
    QStringList fileNames = selectFile(tr("Open a nomo SDK file..."),tr("All nomoSDK files (*.mod *.prg *.bas *.eng *.uni *.map *.pts *.sql);;Model (*.mod);;Program (*.prg);;Knowledge base (*.bas);;Inference engine (*.eng);;Unit (*.uni);;Worldsquare map (*.map);;Scatter of points(*.pts);;Structured Query Language(*.sql);;"));
    if (!fileNames[0].isEmpty())
        this->openProject(fileNames[0]);
}

void MainWindow::openLogging (const QString path){
    const QString result = logging->openDB(path);
    if (result.isEmpty()) {
        if (tabWidget->currentWidget()->objectName() == "receptionTab")
            hiddenReception();
        else
            tabWidget->setMovable(true);
        updateTab(loggingTab);
    }
    else
        QMessageBox::warning(this, tr("Error"),result);
}

void MainWindow::updateTab(QWidget * tab){
    const int i = tabWidget->indexOf(tab);
    if (i == -1)
    {
        tab->resize(this->size());
        tab->childAt(0,0)->resize(this->size());
        tabWidget->addTab(tab, tab->accessibleName());
        tabWidget->setCurrentIndex(tabWidget->indexOf(tab));
    }
    else
        tabWidget->setCurrentIndex(i);
}

void MainWindow::openProject(const QString path){
    const QString projectPath = QDir::cleanPath(path);

    QString result;
    if (tabWidget->currentWidget()->objectName() == "receptionTab")
        hiddenReception();
    else
        tabWidget->setMovable(true);
    const nomoProjectType projectType = toProjectType(projectPath.section('.', -1));
    switch(projectType){
        case mod:
        case prg:
        case bas:
        case eng:
        case uni:{
            result = editor->open(projectPath, projectType);
            if (result == "")
                updateTab(editorTab);
        } break;
        case map:{
            result = benchmark->openMap(projectPath);
            if (result == "")
                updateTab(benchmarkTab);
        } break;
        case pts:{
            result = benchmark->openPoints(projectPath);
            if (result == "")
                updateTab(benchmarkTab);
        } break;
        case sql:{
                logging->openSQL(projectPath);
                updateTab(loggingTab);
        }break;
        default:break;
    }
    if (!result.isEmpty()){
        QMessageBox::warning(this, tr("Error"),tr("Document invalid, the opening of the file has failed : ")+ "\n" + result);
        if (tabWidget->count() == 0)
             showReception();
    }else if ((projectType == pr || projectType == fr) && tabWidget->count() == 0)
        showReception();
}

void MainWindow::createProject(const nomoProjectType projectType, const QString projectPath, const QString projectName, const QString projectFormalism){
    if(projectType == map)
        QFile::copy("transformations/worldsquare.map",projectPath);
    else
        editor->createProject(projectType, projectPath, projectName, projectFormalism);
    openProject(projectPath);
}

void MainWindow::resizeEvent(QResizeEvent *){
    QSize sizeNew = this->size();
    backgroundWidget->resize(sizeNew);
    tabWidget->resize(sizeNew);
    QWidget * tab;
    int i;
    for(i=0; i<tabWidget->count(); i++)
    {
        tab = tabWidget->widget(i);
        tab->resize(sizeNew);
        tab->childAt(0,0)->resize(sizeNew);
    }
}

void MainWindow::on_tabWidget_tabCloseRequested(int index){
    if (tabWidget->widget(index) == editorTab)
        editor->close();
    if (tabWidget->widget(index) == loggingTab)
        logging->close();
    if (tabWidget->widget(index) == benchmarkTab)
        benchmark->close();
    tabWidget->removeTab(index);
    if (tabWidget->count() == 0)
        showReception();
    if (tabWidget->count() == 1)
        if(tabWidget->widget(0) == this->findChild<QWidget *>("receptionTab"))
            tabWidget->setTabsClosable (false);
}

void MainWindow::on_createButton_clicked(){
    showReception();
    tabWidget->setCurrentIndex(tabWidget->indexOf(receptionTab));
}

void MainWindow::on_openButton_clicked(){
    this->selectProject();
}

void MainWindow::on_saveButton_clicked(){
    if (tabWidget->currentWidget() == editorTab)
        editor->saveAll();
    else if (tabWidget->currentWidget() == benchmarkTab)
        benchmark->save();
}

void MainWindow::on_helpButton_clicked(){
    QString answer;
    if (tabWidget->currentWidget() == editorTab)
        answer = "doc/langage_nomo";
    else if (tabWidget->currentWidget() == receptionTab)
        answer = "nomosdk";
    else if (tabWidget->currentWidget() == benchmarkTab)
        answer = "nomosdk/bancs_essais";
    dynamic_cast<QWebView*>(manualTab->childAt(0,0))->load(QUrl::fromEncoded ((beginManualPath + answer + endManualPath).toUtf8()));
    tabWidget->setTabsClosable (true);
    updateTab(manualTab);
    dynamic_cast<QWebView*>(manualTab->childAt(0,0))->setFocus();
   // this->resize(this->maximumSize ());
   // this->showMaximized () ;
    if (this->size().width() < 1220){
        this->move(this->x()+(this->size().width()-1200)/2,this->y());
        this->resize(QSize(1220,this->size().height()));
    }
}

void MainWindow::showReception(){
    receptionTab->resize(this->size());
    receptionTab->childAt(0,0)->resize(this->size());
    tabWidget->addTab(receptionTab, receptionTab->accessibleName());
    if (tabWidget->count() == 1)
    {
        tabWidget->setTabsClosable (false);
        tabWidget->setMovable(false);
        this->findChild<QWidget *>("saveButton")->setVisible(false);
        this->findChild<QWidget *>("createButton")->setVisible(false);
        this->findChild<QWidget *>("openButton")->setVisible(false);
        this->findChild<QWidget *>("helpButton")->setVisible(true);
    }
}

void MainWindow::hiddenReception(){
    tabWidget->removeTab(tabWidget->indexOf(receptionTab));
    tabWidget->setTabsClosable (true);
    this->findChild<QWidget *>("saveButton")->setVisible(true);
    this->findChild<QWidget *>("createButton")->setVisible(true);
    this->findChild<QWidget *>("openButton")->setVisible(true);
    this->findChild<QWidget *>("helpButton")->setVisible(true);
}

void MainWindow::on_tabWidget_destroyed(){

}

void MainWindow::on_tabWidget_currentChanged(int index){
    if (index == tabWidget->indexOf(receptionTab))
    {
        this->findChild<QWidget *>("saveButton")->setVisible(false);
        this->findChild<QWidget *>("createButton")->setVisible(false);
        this->findChild<QWidget *>("openButton")->setVisible(false);
        this->findChild<QWidget *>("helpButton")->setVisible(true);

    }
    else
    {
        this->findChild<QWidget *>("saveButton")->setVisible(true);
        this->findChild<QWidget *>("createButton")->setVisible(true);
        this->findChild<QWidget *>("openButton")->setVisible(true);
        this->findChild<QWidget *>("helpButton")->setVisible(true);
    }
}

void MainWindow::closeTabEditor(){
    tabWidget->removeTab(tabWidget->indexOf(editorTab));
    if (tabWidget->count() == 0)
        showReception();
    if (tabWidget->count() == 1)
        if(tabWidget->widget(0) == this->findChild<QWidget *>("receptionTab"))
            tabWidget->setTabsClosable (false);
}

void MainWindow::openProject(){
    openProject(arg);
    this->show();
}
