/*! @file

    @id $Id$
*/
//       1         2         3         4         5         6         7         8
// 45678901234567890123456789012345678901234567890123456789012345678901234567890

#ifndef QBROWSERLIB_EXECUTOR_HXX
#define QBROWSERLIB_EXECUTOR_HXX

#include <qbrowserlib/log.hxx>
#include <qbrowserlib/settings.hxx>
#include <qbrowserlib/temporaryfile.hxx>

#include <QtCore/QDir>
#include <QtCore/QProcess>
#include <QtNetwork/QNetworkReply>

namespace qbrowserlib {

  //! Execute external processes
  /*! Implements a singleton pattern */
  class Executor: public QObject {
      
      Q_OBJECT;

    Q_SIGNALS:

      void applicationStarted();
      void applicationFinished();

    private:

      Executor() {} // singleton
      Executor(const Executor&); // singleton

    public:
              
      static Executor& instance() {
        static Executor _instance;
        return _instance;
      }
      
      ~Executor() {
        TRC;
        for (DownloadProcesses::iterator it(_downloadProcesses.begin());
             it!=_downloadProcesses.end(); ++it) {
          LOG<<"cleanup:"<<it->second->fileName();
          it->second->setAutoRemove(qbrowserlib::Settings::instance()
                                    .flag("CloseApps"));
          delete it->second;
          it->second = 0;
          if (qbrowserlib::Settings::instance().flag("CloseApps")) {
            LOG<<"terminate process";
            it->first->terminate();
            delete it->first;
          }
        }
      }

    public Q_SLOTS:

      void run(QNetworkReply* reply, QString filename, QString command) {
        TRC; LOG<<filename<<command;
        _reply = reply;
        _filename = filename;
        _command = command;
        if (_reply->isFinished()) {
          LOG<<"run immediate";
          downloadFinished();
        } else {
          LOG<<"run later";
          assert(connect(reply, SIGNAL(finished()), SLOT(downloadFinished())));
        }
      }

    private Q_SLOTS:

      void downloadFinished() {
        TRC;
        TemporaryFile *file(new TemporaryFile
                            (QDir::tempPath()+QDir::separator()
                             +QFileInfo(_filename).fileName()));
        file->open();
        _reply->seek(0);
        file->write(_reply->readAll());
        file->close();
        LOG<<"Stored as:"<<file->fileName();
        QProcess* process(new QProcess);
        _downloadProcesses[process] = file;
        assert(connect(process, SIGNAL(finished(int, QProcess::ExitStatus)),
                       SLOT(processFinished())));
        QStringList args(_command.split(" ")
                         .replaceInStrings("%1", file->fileName()));
        QString prg(args.takeFirst());
        LOG<<"Running:"<<prg<<args.join(" ");
        process->start(prg, args);
        applicationStarted();
      }
      
      void processFinished() {
        TRC;
        if (_downloadProcesses.find(qobject_cast<QProcess*>(sender()))
            == _downloadProcesses.end()) return;
        if (_downloadProcesses[qobject_cast<QProcess*>(sender())])
          _downloadProcesses[qobject_cast<QProcess*>(sender())]
            ->setAutoRemove(qbrowserlib::Settings::instance()
                            .flag("CloseApps"));
        delete _downloadProcesses[qobject_cast<QProcess*>(sender())];
        _downloadProcesses.erase(qobject_cast<QProcess*>(sender()));
        applicationFinished();
      }

    private:
      
      typedef std::map<QProcess*, TemporaryFile*> DownloadProcesses;
      DownloadProcesses _downloadProcesses;
      QNetworkReply* _reply;
      QString _filename;
      QString _command;
  };
  
}

#endif
