/*=========================================================================

 medInria

 Copyright (c) INRIA 2013 - 2018. All rights reserved.
 See LICENSE.txt for details.
 
  This software is distributed WITHOUT ANY WARRANTY; without even
  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  PURPOSE.

=========================================================================*/

#include <medPluginGenerator.h>

class medPluginGeneratorPrivate
{
public:
    QString plugin;
    QString output;
    QString name;
    pluginType type;
    QString description;
    QString license;
    bool generateClassOnly;
    
    QDir parent;
    QDir target;
};


medPluginGenerator::medPluginGenerator()
{
    this->d = new medPluginGeneratorPrivate;
    d->generateClassOnly = false;
}

medPluginGenerator::~medPluginGenerator()
{
    delete this->d;
    this->d = NULL;
}

void medPluginGenerator::setOutputDirectory(const QString& directory)
{
    d->output = directory;
}

void medPluginGenerator::setName(const QString& name)
{
    d->name = name;
}

void medPluginGenerator::setType(pluginType type)
{
    d->type = type;
}

void medPluginGenerator::setDescription(const QString& desc)
{
    d->description = desc;
}

void medPluginGenerator::setLicense(const QString& license)
{
    d->license = license;
}

void medPluginGenerator::setGenerateClassOnly(bool generateClassOnly)
{
    d->generateClassOnly = generateClassOnly;
}

bool medPluginGenerator::run()
{
    d->parent = QDir(d->output);
    
    if(!d->parent.exists()) {
        qWarning() << "medPluginGenerator: parent directory is not valid.";
        return false;
    }
    
    d->plugin = d->name.replace(0, 1, d->name.left(1).toLower());
    
    if(!d->parent.mkdir(d->plugin)) {
        qWarning() << "medPluginGenerator: unable to create target directory.";
        return false;
    }
    
    d->target = QDir(d->parent);
    
    if(!d->target.cd(d->plugin)) {
        qWarning() << "medPluginGenerator: unable to move to target directory.";
        return false;
    }

    QString baseName = QString(d->plugin).replace(0, 1, d->plugin.left(1).toUpper());
    bool res = false;

    QString CMakelistTemplate = ":template/cmake";
    QString pluginTemplate = ":/template/plugin";

    switch(d->type)
    {
    case DATA:
        res = generateFile(QString(d->plugin).append(".h"),":/template/data/data.h")
                && generateFile(QString(d->plugin).append(".cpp"),":/template/data/data.cpp");
        break;
    case VIEW:
        res = generateFile(QString(d->plugin).append(".h"),":/template/view/view.h")
                && generateFile(QString(d->plugin).append(".cpp"),":/template/view/view.cpp");
        break;
    case LAYERED_VIEW:
        res = generateFile(QString(d->plugin).append(".h"),":/template/view/layeredView.h")
                && generateFile(QString(d->plugin).append(".cpp"),":/template/view/layeredView.cpp");
        break;
    case IMAGE_VIEW:
        res = generateFile(QString(d->plugin).append(".h"),":/template/view/imageView.h")
                && generateFile(QString(d->plugin).append(".cpp"),":/template/view/imageView.cpp");
        break;
    case VIEW_INTERACTOR:
        res = generateFile(QString(d->plugin).append(".h"),":/template/view/interactors/viewInteractor.h")
                && generateFile(QString(d->plugin).append(".cpp"),":/template/view/interactors/viewInteractor.cpp");
        break;
    case LAYERED_INTERACTOR:
        res = generateFile(QString(d->plugin).append(".h"),":/template/view/interactors/layeredViewInteractor.h")
                && generateFile(QString(d->plugin).append(".cpp"),":/template/view/interactors/layeredViewInteractor.cpp");
        break;
    case IMAGE_INTERACTOR:
        res = generateFile(QString(d->plugin).append(".h"),":/template/view/interactors/imageViewInteractor.h")
                && generateFile(QString(d->plugin).append(".cpp"),":/template/view/interactors/imageViewInteractor.cpp");
        break;
    case EXTRA_INTERACTOR:
        res = generateFile(QString(d->plugin).append(".h"),":/template/view/interactors/extraInteractor.h")
                && generateFile(QString(d->plugin).append(".cpp"),":/template/view/interactors/extraInteractor.cpp");
        break;
    case VIEW_NAVIGATOR:
        res = generateFile(QString(d->plugin).append(".h"),":/template/view/navigators/viewNavigator.h")
                && generateFile(QString(d->plugin).append(".cpp"),":/template/view/navigators/viewNavigator.cpp");
        break;
    case LAYERED_NAVIGATOR:
        res = generateFile(QString(d->plugin).append(".h"),":/template/view/navigators/layeredViewNavigator.h")
                && generateFile(QString(d->plugin).append(".cpp"),":/template/view/navigators/layeredViewNavigator.cpp");
        break;
    case IMAGE_NAVIGATOR:
        res = generateFile(QString(d->plugin).append(".h"),":/template/view/navigators/imageViewNavigator.h")
                && generateFile(QString(d->plugin).append(".cpp"),":/template/view/navigators/imageViewNavigator.cpp");
        break;
    case EXTRA_NAVIGATOR:
        res = generateFile(QString(d->plugin).append(".h"),":/template/view/navigators/extraNavigator.h")
                && generateFile(QString(d->plugin).append(".cpp"),":/template/view/navigators/extraNavigator.cpp");
        break;
    case FILTERING:
        CMakelistTemplate = ":template/filtering/cmake";
        pluginTemplate = ":/template/filtering/plugin";
        res = generateFile(QString(d->plugin).append(".h"),":/template/filtering/type.h")
                && generateFile(QString(d->plugin).append(".cpp"),":/template/filtering/type.cpp")
                && generateFile(QString(d->plugin).append("ToolBox.h"),":/template/filtering/typeToolBox.h")
                && generateFile(QString(d->plugin).append("ToolBox.cpp"),":/template/filtering/typeToolBox.cpp");
        break;
    case REGISTRATION:
        CMakelistTemplate = ":template/registration/cmake";
        pluginTemplate = ":/template/registration/plugin";
        res = generateFile(QString(d->plugin).append(".h"),":/template/registration/type.h")
                && generateFile(QString(d->plugin).append(".cpp"),":/template/registration/type.cpp")
                && generateFile(QString("rpi"+ baseName).append(".h"),":/template/registration/rpiBase.h")
                && generateFile(QString("rpi"+ baseName).append(".hxx"),":/template/registration/rpiBase.hxx")
                && generateFile(QString(d->plugin).append("ToolBox.h"),":/template/registration/typeToolBox.h")
                && generateFile(QString(d->plugin).append("ToolBox.cpp"),":/template/registration/typeToolBox.cpp");
        break;
//    TODO
//    case DIFFUSION:
//        break;
    case DATA_READER:
        res = generateFile(QString(d->plugin).append(".h"),":/template/data/reader.h")
                && generateFile(QString(d->plugin).append(".cpp"),":/template/data/reader.cpp");
        break;
    case DATA_WRITER:
        res = generateFile(QString(d->plugin).append(".h"),":/template/data/writer.h")
                && generateFile(QString(d->plugin).append(".cpp"),":/template/data/writer.cpp");
        break;
    case WORKSPACE:
        res = generateFile(QString(d->plugin).append(".h"),":/template/workspace.h")
                && generateFile(QString(d->plugin).append(".cpp"),":/template/workspace.cpp");
        break;
    }

    if(res && !d->generateClassOnly)
    {
        return generateFile("CMakeLists.txt", CMakelistTemplate)
                && generateFile(QString(d->plugin).append("Plugin.h"), pluginTemplate +".h")
                && generateFile(QString(d->plugin).append("Plugin.cpp"), pluginTemplate +".cpp")
                && generateFile(QString(d->plugin).append("PluginExport.h"),":/template/export.h")
                && generateReadmeFile();
    }
    else return res;
}



// /////////////////////////////////////////////////////////////////
// README file
// /////////////////////////////////////////////////////////////////

bool medPluginGenerator::generateReadmeFile()
{
    QFile targetFile(d->target.absoluteFilePath("README.txt"));
    
    if(!targetFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
        qWarning() << "medPluginGenerator: unable to open README.txt for writing";
        return false;
    }
    
    QTextStream stream(&targetFile);
    
    stream << d->description;
    
    targetFile.close();
    
    return true;
}


bool medPluginGenerator::generateFile(QString targetFilename, QString templateFilename)
{
    QFile targetFile(d->target.absoluteFilePath(targetFilename));

    if(!targetFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
        qWarning() << "medPluginGenerator: unable to open" << targetFile.fileName() << "for writing";
        return false;
    }

    QFile templateFile(templateFilename);

    if(!templateFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
        qDebug() << "medPluginGenerator: unable to open template file " << templateFile.fileName() << " for reading";
        return false;
    }

    QTextStream stream(&targetFile);
    QString content = QString(templateFile.readAll())
            .replace("%1", d->plugin)
            .replace("%2", d->plugin.toUpper())
            .replace("%3", QString(d->plugin).replace(0, 1, d->plugin.left(1).toUpper()));

    if(d->generateClassOnly)
    {
        content.replace("#include <"+d->plugin+"PluginExport.h>", "")
               .replace(d->plugin.toUpper()+"PLUGIN_EXPORT", "");
    }
    stream << content;


    targetFile.close();
    templateFile.close();

    return true;
}
