// File Import.h by az

#ifndef IMPORT_H
#define IMPORT_H

#include <QWidget>
#include <QProcess>

#include <QDialog>
#include <QStringList>
#include <QDir>
#include <QCheckBox>
#include <QGridLayout>
#include <QPushButton>
#include <QLabel>
#include <QLineEdit>
#include <QDoubleValidator>

#include <map>
#include "SimNode.h"

#include <QDebug>
#include <QApplication>

class QString;
class QFile;
class QLabel;
class RTMSimulator;

/**
 * @brief Class that ist just used to display a custom information in a PopUp Window
 */
class InfoBox : public QWidget
{
public:
    InfoBox(QString);
    void setText(QString);
private:
    QLabel* m_pLabel;
};

/**
 * @brief Class that is used to display a widget to receive user input for configuring gmsh.
 *
 * Gmsh is the 3D finite element grid generator used to create a meshed models out of a conventional 3D model.
 */
class MeshSettingsWidget : public QDialog
{
    Q_OBJECT
public:
    MeshSettingsWidget(QWidget* parent = 0) : QDialog(parent)
    {
        QGridLayout* layout = new QGridLayout(this);
        setLayout(layout);
        QLabel* pLabelMinLength = new QLabel(this);
        QLabel* pLabelMaxLength = new QLabel(this);
        QLabel* pLabelLengthFactor = new QLabel(this);
        pEditMinLength = new QLineEdit(this);
        pEditMaxLength = new QLineEdit(this);
        pEditLengthFactor = new QLineEdit(this);
        pCheckBoxUseVolumes = new QCheckBox(this);
        pButtonOk = new QPushButton(this);
        pButtonOk->setDisabled(true);
        QPushButton* pButtonCancel = new QPushButton(this);

        QDoubleValidator* validator = new QDoubleValidator(this);
        pEditMinLength->setValidator(validator);
        pEditMaxLength->setValidator(validator);
        pEditLengthFactor->setValidator(validator);

        connect(pEditMinLength,SIGNAL(textChanged(QString)),this,SLOT(textChanged(QString)));
        connect(pEditMaxLength,SIGNAL(textChanged(QString)),this,SLOT(textChanged(QString)));
        connect(pEditLengthFactor,SIGNAL(textChanged(QString)),this,SLOT(textChanged(QString)));

        pLabelMinLength->setText("Minimum Length:");
        pLabelMaxLength->setText("Maximum Length:");
        pLabelLengthFactor->setText("Length Factor:");
        pCheckBoxUseVolumes->setText("Use Volumes");
        pButtonOk->setText("Ok");
        pButtonCancel->setText("Cancel");

        layout->addWidget(pLabelMinLength,0,0);
        layout->addWidget(pLabelMaxLength,1,0);
        layout->addWidget(pLabelLengthFactor,2,0);
        layout->addWidget(pEditMinLength,0,1);
        layout->addWidget(pEditMaxLength,1,1);
        layout->addWidget(pEditLengthFactor,2,1);
        layout->addWidget(pCheckBoxUseVolumes,3,0);
        layout->addWidget(pButtonOk,4,0);
        layout->addWidget(pButtonCancel,4,1);

        connect(pButtonOk, SIGNAL(clicked()), this, SLOT(accept()));
        connect(pButtonCancel, SIGNAL(clicked()), this, SLOT(reject()));
    }

    double minLength(){ return pEditMinLength->text().toDouble();}
    double maxLength(){	return pEditMaxLength->text().toDouble();}
    double lengthFactor(){ return pEditLengthFactor->text().toDouble();}
    bool useVolumes(){return pCheckBoxUseVolumes->isChecked();}

protected slots:
    /**
     * Validates the values entered by the user.
     */
    void textChanged(QString /*newText*/)
    {
        bool valid1, valid2, valid3;
        int pos = 0;
        QString minLength = pEditMinLength->text();
        QString maxLength = pEditMaxLength->text();
        QString lengthFactor = pEditLengthFactor->text();
        valid1 = pEditMinLength->validator()->validate(minLength,pos) && !minLength.isEmpty();
        pos = 0;
        valid2 = pEditMaxLength->validator()->validate(maxLength,pos) && !maxLength.isEmpty();
        pos = 0;
        valid3 = pEditLengthFactor->validator()->validate(lengthFactor,pos) && !lengthFactor.isEmpty();
        pButtonOk->setEnabled(valid1 && valid2 && valid3);
    }

private:
    QLineEdit* pEditMinLength;
    QLineEdit* pEditMaxLength;
    QLineEdit* pEditLengthFactor;
    QCheckBox* pCheckBoxUseVolumes;
    QPushButton* pButtonOk;
};

/**
 * @brief This class contains just one static function that executes gmsh with the apropriate arguments.
 */
class Gmsh : public QObject
{
public:
    /**
     * Executes gmsh with the user defined parameters.
     * @param pFile File to import
     * @returns Filename of the temporary file that contains the meshed 3D model
     */
    static QString mesh(QFile* pFile)
    {
        QString tempFileName;
        QDir tempDir(QDir::tempPath());
        for(int i=0; i<9999; i++)
        {
            tempFileName = tempDir.absoluteFilePath(QString("gmsh_out.").append(QString().setNum(i)));
            if(!QFileInfo(tempFileName).exists())
                break;
        }

        MeshSettingsWidget meshSettingsWidget;
        if(QDialog::Accepted == meshSettingsWidget.exec())
        {
            QString useVolumes;
            if(meshSettingsWidget.useVolumes())
                useVolumes = "-3";
            else
                useVolumes = "-2";

            QStringList arguments;
            arguments	<< pFile->fileName()
                    << "-o" << tempFileName
                    << "-clmin" << QString().setNum(meshSettingsWidget.minLength())
                    << "-clmax" << QString().setNum(meshSettingsWidget.maxLength())
                    << "-clscale" << QString().setNum(meshSettingsWidget.lengthFactor())
                    << useVolumes;

#if defined(Q_OS_LINUX)
            QProcess::execute( "gmsh", arguments );
#else
#if defined(Q_OS_MAC)
            QFileInfo fi(qApp->arguments().at(0));
            QProcess::execute( fi.dir().absoluteFilePath("gmsh"), arguments );
#else
            QProcess::execute( "gmsh.exe", arguments );
#endif
#endif
        }
        return tempFileName;
    }
};

/**
 * @brief This class is used to generate temporary import objects.
 * Such an object handles the importation of an external file.
 */
class Import : public QObject //needs to be QObject so we can use tr()
{
    RTMSimulator* m_pSimulator;
    int m_numberOfNodes;
    int m_numberOfElements;

private:
    bool readSizeInformation(QFile* pFile);
    bool importNodes(QFile* pFile);
    bool importConnections(QFile* pFile);

public:
    Import(QString strFile, RTMSimulator* pSimulator);
};


#endif //IMPORT_H
