/*****************************************************************************
 * $CAMITK_LICENCE_BEGIN$
 *
 * CamiTK - Computer Assisted Medical Intervention ToolKit
 * (c) 2001-2016 Univ. Grenoble Alpes, CNRS, TIMC-IMAG UMR 5525 (GMCAO)
 *
 * Visit http://camitk.imag.fr for more information
 *
 * This file is part of CamiTK.
 *
 * CamiTK is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * CamiTK 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 Lesser General Public License version 3 for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with CamiTK.  If not, see <http://www.gnu.org/licenses/>.
 *
 * $CAMITK_LICENCE_END$
 ****************************************************************************/
#include "ActionExtensionGenerator.h"

// includes from cepcoreschema
#include <ActionExtension.hxx>
#include <Action.hxx>
#include <Dependency.hxx>

// includes from STL
#include <iostream>
#include <memory>

// includes from Qt
#include <QFileInfo>
#include <QFile>
#include <QDir>
#include <QTextStream>

// local includes
#include "ClassNameHandler.h"
#include "ActionGenerator.h"
#include "DependencyGenerator.h"


using namespace cepcoreschema;

ActionExtensionGenerator::ActionExtensionGenerator(QString xmlFileName, QString actionExtensionsDirectory, QString licence) throw (QString)
    : ExtensionGenerator(actionExtensionsDirectory, licence, "Action") {
    QFileInfo xmlFile(xmlFileName);
    if ((! xmlFile.exists()) || (! xmlFile.isFile())) {
        QString msg = "Exception from ActionExtension generation: \n     The file " + xmlFileName +  " does not exist or is not a file...\n";
        throw (msg);
    }
    try {
        std::string xmlFileStr = xmlFileName.toStdString();
        std::auto_ptr<ActionExtension>domActionExtension = actionExtension(xmlFileStr, xml_schema::flags::dont_validate);
        createFromDom(*domActionExtension);
    } catch (...) {
        QString msg = "Action extension XML file not valid.";
        throw msg;
    }
}

ActionExtensionGenerator::ActionExtensionGenerator( ActionExtension & domActionExtension, QString actionExtensionsDirectory, QString licence)
    : ExtensionGenerator(actionExtensionsDirectory, licence, "Action") {
    createFromDom(domActionExtension);
}

void ActionExtensionGenerator::createFromDom(ActionExtension & dom) {
    this->name = QString(dom.name().c_str());
    this->description = QString(dom.description().c_str()).simplified();

    if (dom.dependencies().present()) {
        Dependencies deps = dom.dependencies().get();
        for(Dependencies::dependency_iterator it = deps.dependency().begin(); it != deps.dependency().end(); it++) {
            Dependency & dep = (*it);
            DependencyGenerator * depGen = new DependencyGenerator(dep);
            dependencyGenerators.append(depGen);
        }
    }

    // Create the action generators...
    for (Actions::action_iterator act = dom.actions().action().begin(); act != dom.actions().action().end(); act++) {
        Action & theAction = (*act);
        ActionGenerator * actionGenerator = new ActionGenerator(theAction, licence);
        actions.append(actionGenerator);
    }
}

ActionExtensionGenerator::~ActionExtensionGenerator() {
//    for (QVector<DependencyGenerator *>::iterator dep = dependencyGenerators.begin(); dep != dependencyGenerators.end(); dep++)
//        delete dep;

}


void ActionExtensionGenerator::generateActionOrComponent(QString directory) {
    // C generate actions
    for (QVector<ActionGenerator *>::iterator it = actions.begin(); it != actions.end(); it++) {
        (*it)->generateFiles(directory);
    }
}

void ActionExtensionGenerator::writeHFile(QString directory) {
    QString className = ClassNameHandler::getClassName(this->name);
    QFile initHFile(":/resources/ActionExtension.h.in");
    initHFile.open(QIODevice::ReadOnly | QIODevice::Text);
    QTextStream inh(&initHFile);

    QFileInfo extFileHPath;
    extFileHPath.setFile(directory, className+ ".h");
    QFile extFileH(extFileHPath.absoluteFilePath());
    if (! extFileH.open(QIODevice::WriteOnly | QIODevice::Text)) {
        QString msg = "Exception from extension generation: \n    Cannot write on file " + extFileHPath.fileName() + "\n";
        throw (msg);
    }
    QTextStream outh(&extFileH);

    QString headdef = className.toUpper();
    QString text;
    do {
        text = inh.readLine();
        text.replace(QRegExp("@LICENCE@"), licence);
        text.replace(QRegExp("@HEADDEF@"), headdef);
        text.replace(QRegExp("@EXTENSIONCLASSNAME@"), className);
        text.replace(QRegExp("@EXTENSIONNAME@"), this->name);
        text.replace(QRegExp("@EXTENSIONDESCRIPTION@"), this->description);
        outh << text << endl;
    } while (! text.isNull());
    extFileH.close();
    initHFile.close();
}

void ActionExtensionGenerator::writeCFile(QString directory) {
    QString className = ClassNameHandler::getClassName(this->name);
    QFile initCFile(":/resources/ActionExtension.cpp.in");
    initCFile.open(QIODevice::ReadOnly | QIODevice::Text);
    QTextStream inc(&initCFile);

    QFileInfo extFileCPath;
    extFileCPath.setFile(directory, className + ".cpp");
    QFile extFileC(extFileCPath.absoluteFilePath());
    if (! extFileC.open(QIODevice::WriteOnly | QIODevice::Text)) {
        QString msg = "Exception from extension generation: \n    Cannot write on file " + extFileCPath.fileName() + "\n";
        throw (msg);
    }
    QTextStream outc(&extFileC);

    QString text;
    QVector<ActionGenerator *>::const_iterator it;
    do {
        text = inc.readLine();
        text.replace(QRegExp("@LICENCE@"), licence);
        text.replace(QRegExp("@EXTENSIONCLASSNAME@"), className);
        text.replace(QRegExp("@EXTENSIONCLASSNAMELOW@"), className.toLower());
        if (text.contains(QRegExp("@INCLUDEACTIONHEADERS@"))) {
            for (it = actions.begin(); it < actions.end(); it++) {
                outc << "#include \"" << (*it)->getClassName() << ".h\"" << endl;
            }
        } else if (text.contains(QRegExp("@BEGIN_REGISTERACTIONS@"))) {
            text = inc.readLine();
            if (actions.size() > 0) {
                QStringList registerTheAction;
                while (! text.contains(QRegExp("@END_REGISTERACTIONS@"))) {
                    for (it = actions.begin(); it < actions.end(); it++) {
                        QString  textTmp = text;
                        textTmp.replace(QRegExp("@ACTIONNAME@"), (*it)->getClassName());
                        registerTheAction << textTmp;
                    }
                    text = inc.readLine();
                }
                for (int a = 0; a < registerTheAction.size(); a++) {
                    outc << registerTheAction.at(a) << endl;
                }
            } else {
                while (! text.contains(QRegExp("@ENDREGISTERACTIONS@"))) {
                    text = inc.readLine();
                }
                outc << "// You should register your actions here." << endl;
            }
        } else {
            outc << text << endl;
        }
    } while (! text.isNull());
    extFileC.close();
    initCFile.close();
}

void ActionExtensionGenerator::generateTestDataFiles(QString directory, QString testDataDirName) {
    // Do not do anything yet
    // TODO think of the kind of test file we could put here by default...

}
