Subversion Repositories public iLand

Rev

Rev 1220 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

/********************************************************************************************
**    iLand - an individual based forest landscape and disturbance model
**    http://iland.boku.ac.at
**    Copyright (C) 2009-  Werner Rammer, Rupert Seidl
**
**    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 "consoleshell.h"

#include <QtCore>
#include <QtDebug>
//#include <QKeyEvent>

#include "global.h"
#include "model.h"
#include "modelcontroller.h"
#include "version.h"

QTextStream *ConsoleShell::mLogStream = 0;
bool ConsoleShell::mFlushLog = false;

// a try to really get keyboard strokes in console mode...
// did not work.
class KeyboardTaker : public QThread
 {
 public:
     void run();
     bool stop;
 };

 void KeyboardTaker::run()
 {
     stop = false;
     QTextStream qin(stdin, QFile::ReadOnly);
     while (!stop) {
         QString input = qin.read(1);
         if (!input.isNull()) {
             // .. process input
             qWarning() << "input:" << input;
         }
     }
 }

ConsoleShell::ConsoleShell()
{
}

/*
*/


void ConsoleShell::run()
{

    QString xml_name = QCoreApplication::arguments().at(1);
    // get the number of years to run...
    bool ok;
    int years = QCoreApplication::arguments().at(2).toInt(&ok);
    if (years<0 || !ok) {
        qDebug() << QCoreApplication::arguments().at(2) << "is an invalid number of years to run!";
        QCoreApplication::quit();
        return;
    }

    if (!QFile::exists(xml_name)) {
        qDebug() << "invalid XML project file: " << xml_name;
        QCoreApplication::quit();
        return;
    }
    try {

        ModelController iland_model;
        GlobalSettings::instance()->setModelController( &iland_model );
        QObject::connect(&iland_model, SIGNAL(year(int)),SLOT(runYear(int)));
        iland_model.setFileName(xml_name);
        if (iland_model.hasError()) {
            qWarning() << "!!!! ERROR !!!!";
            qWarning() << iland_model.lastError();
            qWarning() << "!!!! ERROR !!!!";
            QCoreApplication::quit();
            return;
        }

        mParams.clear();
        if (QCoreApplication::arguments().count()>3) {
            qWarning() << "set command line values:";
            for (int i=3;i<QCoreApplication::arguments().count();++i) {
                QString line = QCoreApplication::arguments().at(i);
                line = line.remove(QChar('"')); // drop quotes
                mParams.append(line);
                //qDebug() << qPrintable(line);
                QString key = line.left(line.indexOf('='));
                QString value = line.mid(line.indexOf('=')+1);
                const_cast<XmlHelper&>(GlobalSettings::instance()->settings()).setNodeValue(key, value);
                qWarning() << QString("set '%1' to value '%2'. result: '%3'").arg(key).arg(value).arg(GlobalSettings::instance()->settings().value(key));
            }
        }
        setupLogging();

        qDebug() << "**************************************************";
        qDebug() << "***********     iLand console session     ********";
        qDebug() << "**************************************************";

        qWarning() << "*** creating model...";
        qWarning() << "**************************************************";

        iland_model.create();
        if (iland_model.hasError()) {
            qWarning() << "!!!! ERROR !!!!";
            qWarning() << iland_model.lastError();
            qWarning() << "!!!! ERROR !!!!";
            QCoreApplication::quit();
            return;
        }
        runJavascript("onCreate");
        qWarning() << "**************************************************";
        qWarning() << "*** running model for" << years << "years";
        qWarning() << "**************************************************";

        iland_model.run(years + 1);
        if (iland_model.hasError()) {
            qWarning() << "!!!! ERROR !!!!";
            qWarning() << iland_model.lastError();
            qWarning() << "!!!! ERROR !!!!";
            QCoreApplication::quit();
            return;
        }
        runJavascript("onFinish");

        qWarning() << "**************************************************";
        qWarning() << "*** model run finished.";
        qWarning() << "**************************************************";

    } catch (const IException &e) {
        qWarning() << "*** An exception occured ***";
        qWarning() << e.message();
    }
    catch (const std::exception &e) {
        qWarning() << "*** An (std)exception occured ***";
        qWarning() << e.what();
    }
    QCoreApplication::quit();


}

void ConsoleShell::runYear(int year)
{
    printf("%s: simulating year %d ...\n", QDateTime::currentDateTime().toString("hh:mm:ss").toLocal8Bit().data(), year-1);
}

static QMutex qdebug_mutex;
void myMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
 {
    Q_UNUSED(context);
    QMutexLocker m(&qdebug_mutex);

    switch (type) {
    case QtDebugMsg:
        *ConsoleShell::logStream() << msg << endl;
        if (ConsoleShell::flush())
            ConsoleShell::logStream()->flush();
        break;
    case QtWarningMsg:
        *ConsoleShell::logStream() << msg << endl;
        if (ConsoleShell::flush())
            ConsoleShell::logStream()->flush();
        printf("%s: %s\n", QDateTime::currentDateTime().toString("hh:mm:ss").toLocal8Bit().data(), msg.toLocal8Bit().data());
        break;
// available from qt5.5
//    case QtInfoMsg:
//        *ConsoleShell::logStream() << msg << endl;
//        if (ConsoleShell::flush())
//            ConsoleShell::logStream()->flush();
//        printf("%s: %s\n", QDateTime::currentDateTime().toString("hh:mm:ss").toLocal8Bit().data(), msg.toLocal8Bit().data());

//        break;
    case QtCriticalMsg:
        *ConsoleShell::logStream() << msg << endl;
        if (ConsoleShell::flush())
            ConsoleShell::logStream()->flush();
        printf("Critical: %s\n", msg.toLocal8Bit().data());
        break;
    case QtFatalMsg:
        *ConsoleShell::logStream() << msg << endl;
        if (ConsoleShell::flush())
            ConsoleShell::logStream()->flush();
        printf("Fatal: %s\n", msg.toLocal8Bit().data());
    }
 }


void ConsoleShell::setupLogging()
{
    if (mLogStream) {
        if (mLogStream->device())
            delete mLogStream->device();
        delete mLogStream;
        mLogStream = NULL;
    }

    QString fname = GlobalSettings::instance()->settings().value("system.logging.logFile", "logfile.txt");
    mFlushLog = GlobalSettings::instance()->settings().valueBool("system.logging.flush");
    QString timestamp = QDateTime::currentDateTime().toString("yyyyMMdd_hhmmss");
    fname.replace("$date$", timestamp);
    fname = GlobalSettings::instance()->path(fname, "log");
    QFile *file = new QFile(fname);

    if (!file->open(QIODevice::WriteOnly)) {
        qDebug() << "cannot open logfile" << fname;
    } else {
        qDebug() << "Log output is redirected to logfile" << fname;
        mLogStream = new QTextStream(file);
    }
    qInstallMessageHandler(myMessageOutput);


}

void ConsoleShell::runJavascript(const QString key)
{
    for (int i=0;i<mParams.count(); ++i) {
        QString line=mParams[i];
        QString pkey = line.left(line.indexOf('='));
        if (pkey == key) {
            QString command = line.mid(line.indexOf('=')+1);
            // execute the function
            qWarning() << "executing trigger" << key;
            qWarning() << GlobalSettings::instance()->executeJavascript(command);
        }
    }


}