/*! @file

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

#ifndef __SAVEORRUN_HXX__
#define __SAVEORRUN_HXX__

#include <qbrowserlib/log.hxx>
#include <qbrowserlib/ui_saveorrun.h>
#include <qbrowserlib/executor.hxx>

#include <QtCore/QUrl>
#include <QtNetwork/QNetworkReply>
#include <QtGui/QDialog>
#include <QtGui/QFileDialog>
#include <QtGui/QFileSystemModel>
#include <QtGui/QDialogButtonBox>
#include <QtGui/QMessageBox>
#include <QtGui/QDesktopServices>
#include <memory>

#include <cassert>

//! @addtogroup qbrowserlib
//! @{

namespace qbrowserlib {

  //! Ask User for Saving or Opening a Download
  class SaveOrRun: public QWidget, public Ui::SaveOrRun {
      Q_OBJECT;

    signals:

      void accept();

    public:
    
      SaveOrRun(QNetworkReply* reply, Executor* executor,
                QString type, QString src,
                QWidget* p=0): QWidget(p), _reply(reply), _executor(executor) {
        TRC;
        setupUi(this);
        QString obj(remoteFilename());
        _rememberPath->setVisible(false);
        _rememberTool->setVisible(false);
        // _program->setText(QDesktopServices::storageLocation
        //                   (QDesktopServices::ApplicationsLocation));
        delete _openInExternalApplication; _openInExternalApplication = 0;
        _object->setText(obj);
        _type->setText(type);
        _source->setText(src);
        _filename->setText(savePath()+QDir::separator()+obj);
      }

      //! Run configured application if mime type is preconfigured.
      bool handlePreconfigured() {
        TRC;
        QString filename(remoteFilename());
        QStringList type
          (_executor->settings()->mimetype
           (_reply->header(QNetworkRequest::ContentTypeHeader).toString(),
            filename));
        if (!type.isEmpty()) {
          LOG<<"Start Application";
          hide();
          filename.replace(QRegExp("^(.*)\\."+type.at(0)+"$"),
                           "\\1"); // remove extension
          assert(connect(_executor, SIGNAL(applicationStarted()),
                         SIGNAL(accept())));
          _executor->run(_reply, filename+"."+type.at(0), type.at(1));
          return true;
        }
        return false;
      }

      QString remoteFilename() {
        TRC;
        QString filename
          (QString::fromUtf8(_reply->rawHeader("Content-Disposition")));
        if (filename.contains
            (QRegExp("^\\s*attachment\\s*;\\s*filename\\s*=\\s*\"[^\"]+\""))) {
          LOG<<"From Content-Disposition";
          filename = filename.replace
            (QRegExp("^\\s*attachment\\s*;\\s*filename\\s*=\\s*\"([^\"]+)\".*"),
             "\\1");
        } else {
          LOG<<"From path";
          filename =
            QFileInfo(!_reply->url().toLocalFile().isEmpty()
                      ?_reply->url().toLocalFile()
                      :_reply->url().path()).fileName();
        }
        LOG<<"Filename:"<<filename;
        return filename;
      }

      QString filename() {
        TRC;
        return _filename->text();
      }

      QString program() {
        TRC;
        return QString();
        // return _program->text();
      }

    public Q_SLOTS:

      void save() {
        TRC;
        QFile file(filename());
        file.open(QIODevice::WriteOnly);
        file.write(_reply->readAll());
        file.close();
        accept();
      }

      void open() {
        TRC;
        QFile file(filename());
        file.open(QIODevice::WriteOnly);
        file.write(_reply->readAll());
        file.close();
        QDesktopServices::openUrl(QUrl::fromLocalFile(file.fileName()));
        accept();
      }

      void run() {
        TRC; LOG<<program()<<filename();
        _executor->run(_reply, filename(), program()+" %1");
        accept();
      }
    
    protected Q_SLOTS:

      void on__saveFileAs_clicked(bool=true) {
        TRC;
        if (QFileInfo(filename()).exists()
            && QMessageBox::question(this, tr("File Exists"),
                                     tr("File already exists:\n\n"
                                        "%1\n\n"
                                        "Overwrite?").arg(filename()),
                                     QMessageBox::Yes|QMessageBox::No)
            == QMessageBox::No) return;
        save();
      }

      void on__openFolder_clicked(bool=true) {
        TRC;
        if (QFileInfo(filename()).exists()
            && QMessageBox::question(this, tr("File Exists"),
                                     tr("File already exists:\n\n"
                                        "%1\n\n"
                                        "Overwrite?").arg(filename()),
                                     QMessageBox::Yes|QMessageBox::No)
            == QMessageBox::No) return;
        open();
      }

      void on__openFileIn_clicked(bool=true) {
        TRC;
        if (!QFile::exists(program())
            || !QFileInfo(program()).isExecutable()) {
          QMessageBox::warning(this, tr("No Program"),
                               tr("Not an executable Program:\n\n"
                                  "%1\n\n"
                                  "Specify full path to executable program")
                               .arg(program()));
          return;
        }
        run();
      }

      void on__browseSaveAs_clicked(bool) {
        TRC;
        QString saveFile
          (QFileDialog::getSaveFileName(this, tr("Save File As ..."),
                                        _filename->text(), QString(), 0,
                                        QFileDialog::DontConfirmOverwrite));
        if (!saveFile.size()) return;
        if (QFileInfo(saveFile).isDir())
          saveFile += QDir::separator()+_object->text();
        _filename->setText(saveFile);
        on__saveFileAs_clicked();
      }

      void on__browseOpenWith_clicked(bool) {
        TRC;
        QString openFile
          (QFileDialog::getOpenFileName(this, tr("Open File With ..."),
                                        program()));
        if (!openFile.size()) return;
        // _program->setText(openFile);
        on__openFileIn_clicked();
      }
      
      QString savePath() {
        TRC;
        QString path(QDir::homePath());
        QStringList defpaths;
        defpaths<<"downloads"<<"Downloads"<<"Documents"
                <<tr("Dokumente", "Documents folder in local language")
                <<"Desktop"
                <<tr("Arbeitsfläche", "Desktop folder in local language");
        for (QStringList::iterator it(defpaths.begin()); it!=defpaths.end(); ++it)
          if (QFile::exists(QDir::homePath()+QDir::separator()+*it)) {
            path = QDir::homePath()+QDir::separator()+*it;
            break;
          }
        return path;
      }

    private:
      
      friend class SaveOrRunDialog;
      QNetworkReply* _reply;
      Executor* _executor;
      
  };

  class SaveOrRunPlugin: public SaveOrRun {
      Q_OBJECT;
    
    public:
    
      SaveOrRunPlugin(QNetworkReply* reply, Executor* executor,
                      const QUrl& url, const QString&  mime,
                      bool kiosk=false, QWidget* p=0):
          SaveOrRun(reply, executor,
                    mime, url.toString(), p) {
        TRC;
        setAutoFillBackground(true);
        _type->setText(mime);
        _source->setText(url.host());
        assert(connect(this, SIGNAL(accept()), SLOT(hide())));
      }

    protected Q_SLOTS:

      void hide() {
        _stack->setCurrentIndex(1);
      }
    
  };

  class SaveOrRunDialog: public QDialog {
      Q_OBJECT;
    
    public:
      
      SaveOrRunDialog(QNetworkReply* reply, Executor* executor,
                      QString type, QString src,
                      bool kiosk=false, QWidget* p=0):
          QDialog(p), _sor(new SaveOrRun(reply, executor, type, src)) {
        TRC;
        setWindowTitle(tr("Unknown File Type"));
        QVBoxLayout* l(new QVBoxLayout(this));
        l->addWidget(_sor);
        l->addWidget(_buttons = new QDialogButtonBox(QDialogButtonBox::Cancel));
        assert(connect(_sor, SIGNAL(accept()), SLOT(accept())));
        assert(connect(_buttons, SIGNAL(rejected()), SLOT(reject())));
      }

      bool handlePreconfigured() {
        return _sor->handlePreconfigured();
      }

    protected:

      SaveOrRun* _sor;
      QDialogButtonBox* _buttons;
    
  };

}

//! @}

#endif
