/***************************************************************************
**
**  This file is part of QGpGuiTools.
**
**  This library is free software; you can redistribute it and/or
**  modify it under the terms of the GNU Lesser General Public
**  License as published by the Free Software Foundation; either
**  version 2.1 of the License, or (at your option) any later version.
**
**  This file 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 Lesser General Public
**  License for more details.
**
**  You should have received a copy of the GNU Lesser General Public
**  License along with this library; if not, write to the Free Software
**  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
**
**  See http://www.geopsy.org for more information.
**
**  Created: 2005-10-04
**  Copyright: 2005-2019
**    Marc Wathelet
**    Marc Wathelet (LGIT, Grenoble, France)
**
***************************************************************************/

#include "GuiMessage.h"
#include "Application.h"
#include "BugReport.h"
#include "MessageBox.h"
#include "Dialog.h"
#include "Settings.h"

namespace QGpGuiTools {

  GuiMessage::GuiMessage()
  {
    TRACE;
    connect(this, SIGNAL (asyncMessageSignal(Message::Answer *, QWaitCondition *, uint,
                                             int, QString, const QString &, QString,
                                             QString, QString, bool)),
             this, SLOT (asyncMessageSlot(Message::Answer *, QWaitCondition *, uint,
                         int, QString, const QString &, QString,
                         QString, QString, bool)),
             Qt::QueuedConnection);
    connect(this, SIGNAL (asyncGetOpenFileNameSignal(QString *, QWaitCondition *,
                          const QString &, const QString &, const QString &, const QString &)),
             this, SLOT (asyncGetOpenFileNameSlot(QString *, QWaitCondition *,
                         const QString &, const QString &, const QString &, const QString &)),
             Qt::QueuedConnection);
    connect(this, SIGNAL (asyncGetSaveFileNameSignal(QString *, QWaitCondition *,
                          const QString &, const QString &, const QString &, const QString &)),
             this, SLOT (asyncGetSaveFileNameSlot(QString *, QWaitCondition *,
                         const QString &, const QString &, const QString &, const QString &)),
             Qt::QueuedConnection);
    connect(this, SIGNAL (asyncGetOpenFileNamesSignal(QStringList *, QWaitCondition *,
                          const QString &, const QString &, const QString &, const QString &)),
             this, SLOT (asyncGetOpenFileNamesSlot(QStringList *, QWaitCondition *,
                         const QString &, const QString &, const QString &, const QString &)),
             Qt::QueuedConnection);
    connect(this, SIGNAL (asyncGetExistingDirectorySignal(QString *, QWaitCondition *,
                          const QString &, const QString &, const QString &)),
             this, SLOT (asyncGetExistingDirectorySlot(QString *, QWaitCondition *,
                         const QString &, const QString &, const QString &)),
             Qt::QueuedConnection);
  }

  Message::Answer GuiMessage::message(uint msgId,
                                       Severity sev,
                                       QString caption,
                                       const QString &text,
                                       QString answer0,
                                       QString answer1,
                                       QString answer2,
                                       bool againOption)
  {
    if(againOption && hasAutoAnswer(msgId)) {
      return autoAnswer(msgId, sev, caption, text, answer0, answer1, answer2);
    }
    if(answer1.isEmpty() && answer2.isEmpty() && quiet()) {
      App::log(severityString(sev)+caption+"----\n");
      App::log(text+"\n");
      return Answer0;
    }

    Message::Answer a;
    if(QThread::currentThread()==Application::instance()->mainThread()) {
      MessageBox *d=new MessageBox(QApplication::activeWindow());
      d->setWindowTitle(caption);
      d->setMessage(text);
      d->setButton(0, answer0);
      d->setButton(1, answer1);
      d->setButton(2, answer2);
      d->setSeverity(sev);
      if(againOption) d->addAgainOption();
      Settings::getRect(d, QString("Message%1").arg(msgId));
      d->exec();
      Settings::setRect(d, QString("Message%1").arg(msgId));
      a=d->answer();
      if(againOption && !d->showAgain()) {
        setAutoAnswer(msgId, a);
      }
      delete d;
    } else {
      Mutex m;
      m.lock();
      QWaitCondition reply;
      emit asyncMessageSignal(&a, &reply, msgId, sev, caption, text, answer0, answer1, answer2, againOption);
      reply.wait(&m);
      m.unlock();
    }
    return a;
  }

  void GuiMessage::asyncMessageSlot(Message::Answer *a, QWaitCondition *reply, uint msgId,
                  int sev, QString caption, const QString &text,
                  QString answer0, QString answer1, QString answer2,
                  bool againOption)
  {
    TRACE;
    *a=message(msgId, (Severity)sev, caption, text, answer0, answer1, answer2, againOption);
    reply->wakeAll();
  }

  void GuiMessage::asyncGetOpenFileNameSlot(QString *a, QWaitCondition *reply,
                                            const QString &caption, const QString &filter,
                                            const QString &directory, const QString &bottomMessage)
  {
    TRACE;
    *a=getOpenFileName(caption, filter, directory, bottomMessage);
    reply->wakeAll();
  }

  void GuiMessage::asyncGetSaveFileNameSlot(QString *a, QWaitCondition *reply,
                                            const QString &caption, const QString &filter,
                                            const QString &selection, const QString &bottomMessage)
  {
    TRACE;
    *a=getSaveFileName(caption, filter, selection, bottomMessage);
    reply->wakeAll();
  }

  void GuiMessage::asyncGetOpenFileNamesSlot(QStringList *a, QWaitCondition *reply,
                                             const QString &caption, const QString &filter,
                                             const QString &directory, const QString &bottomMessage)
  {
    TRACE;
    *a=getOpenFileNames(caption, filter, directory, bottomMessage);
    reply->wakeAll();
  }

  void GuiMessage::asyncGetExistingDirectorySlot(QString *a, QWaitCondition *reply,
                                                 const QString &caption, const QString &dir,
                                                 const QString &bottomMessage)
  {
    TRACE;
    *a=getExistingDirectory(caption, dir, bottomMessage);
    reply->wakeAll();
  }

  /*!
    Always returns an absolute path, normal dialog with save-retore mechanism.

    Uses the native dialog box for Mac users.
  */
  QString GuiMessage::getSaveFileNameInternal(const QString &caption, const QString &filter,
                                              const QString &selection, const QString &bottomMessage)
  {
    TRACE;
    QString fileName;
    if(QThread::currentThread()==Application::instance()->mainThread()) {
      QString key="filter-"+QString::number(qHash(filter));
      // Mac dialog does not support filter selection, temporarily abandoned.
      /*#ifdef Q_OS_MAC
      Q_UNUSED(selection)
      fileName=QFileDialog::getSaveFileName(qApp->activeWindow(), caption, Settings::getPath(key));
      if(!fileName.isEmpty()) {
        QFileInfo finfo(fileName);
        Settings::setPath(key, finfo.dir());
      }
      #else*/
      FileDialog fd(qApp->activeWindow(), caption, Settings::getPath(key), filter);
      fd.setOption(QFileDialog::DontUseNativeDialog, true);
      if(!bottomMessage.isNull()) {
        QGridLayout *layout=qobject_cast<QGridLayout *>(fd.layout());
        if(layout) {
          QLabel *label=new QLabel(bottomMessage);
          label->setTextInteractionFlags(Qt::TextBrowserInteraction);
          label->setWordWrap(true);
          layout->addWidget(label, layout->rowCount(), 0, 1, layout->columnCount());
        } else {
          App::log(bottomMessage+"\n");
        }
      }
      fd.setFileMode(QFileDialog::AnyFile);
      fd.setAcceptMode(QFileDialog::AcceptSave);
      fd.getRect(key);
      QString filterStr=Settings::getFilter(key);
      if(!filterStr.isEmpty()) fd.selectNameFilter(filterStr);
      fd.setHistory(Settings::getDirHistory(key));
      if(!selection.isEmpty()) {
        QFileInfo fi(selection);
        fd.setDirectory(fi.path());
        fd.selectFile(fi.fileName());
      }
      if(fd.exec()==QDialog::Accepted && !fd.selectedFiles().isEmpty()) {
        fileName=fd.selectedFiles().first();
        QFileInfo finfo(fileName);
        if(finfo.suffix().isEmpty()) {
          QString ext=fd.selectedNameFilter().section("*.", 1)
                        .section(QRegExp("[ )]"), 0, 0).trimmed();
          if(ext!="*" && !ext.isEmpty() &&
             finfo.suffix().toLower()!=ext.toLower() &&
             finfo.completeSuffix().toLower()!=ext.toLower()) {
            fileName+="." + ext;
            finfo.setFile(fileName);
            if(finfo.exists()) {
              if(Message::warning(MSG_ID, caption, tr("%1 already exists. Do you want to replace it?").arg(finfo.fileName()),
                                  Message::no(), Message::yes())==Message::Answer0) {
                return QString();
              }
            }
          }
        }
        fd.setRect(key);
        Settings::setPath(key, finfo.dir());
        Settings::setDirHistory(key , finfo.dir());
        Settings::setFilter(key, fd.selectedNameFilter());
      }
      //#endif
    } else {
      Mutex m;
      m.lock();
      QWaitCondition reply;
      emit asyncGetSaveFileNameSignal(&fileName, &reply, caption, filter, selection, bottomMessage);
      reply.wait(&m);
      m.unlock();
    }
    return fileName;
  }

  /*!
    Always returns an absolute path, normal dialog with save-retore mechanism.

    Uses the native dialog box for Mac users.
  */
  QString GuiMessage::getOpenFileNameInternal(const QString &caption, const QString &filter,
                                              const QString &directory, const QString &bottomMessage)
  {
    TRACE;
    QString fileName;
    if(QThread::currentThread()==Application::instance()->mainThread()) {
      QString key="filter-"+QString::number(qHash(filter));
      // Mac dialog does not support filter selection, temporarily abandoned.
      /*#ifdef Q_OS_MAC
      fileName=QFileDialog::getOpenFileName(qApp->activeWindow(), caption, Settings::getPath(key), filter);
      if(!fileName.isEmpty()) {
        QFileInfo finfo(fileName);
        Settings::setPath(key, finfo.dir());
      }
      #else*/
      FileDialog fd(qApp->activeWindow(), caption, Settings::getPath(key), filter);
      fd.setOption(QFileDialog::DontUseNativeDialog, true);
      if(!bottomMessage.isNull()) {
        QGridLayout *layout=qobject_cast<QGridLayout *>(fd.layout());
        if(layout) {
          QLabel *label=new QLabel(bottomMessage);
          label->setTextInteractionFlags(Qt::TextBrowserInteraction);
          label->setWordWrap(true);
          layout->addWidget(label, layout->rowCount(), 0, 1, layout->columnCount());
        } else {
          App::log(bottomMessage+"\n");
        }
      }
      fd.setFileMode(QFileDialog::ExistingFile);
      fd.getRect(key);
      QString filterStr=Settings::getFilter(key);
      if(!filterStr.isEmpty()) fd.selectNameFilter(filterStr);
      fd.setHistory(Settings::getDirHistory(key));
      if(!directory.isEmpty()) fd.setDirectory(directory);
      if(fd.exec()==QDialog::Accepted && !fd.selectedFiles().isEmpty()) {
        fileName=fd.selectedFiles().first();
        fd.setRect(key);
        QFileInfo finfo(fileName);
        Settings::setPath(key, finfo.dir());
        Settings::setDirHistory(key , finfo.dir());
        Settings::setFilter(key, fd.selectedNameFilter());
      }
      //#endif
    } else {
      Mutex m;
      m.lock();
      QWaitCondition reply;
      emit asyncGetOpenFileNameSignal(&fileName, &reply, caption, filter, directory, bottomMessage);
      reply.wait(&m);
      m.unlock();
    }
    return fileName;
  }


  /*!
    Always returns an absolute path, normal dialog with save-retore mechanism.

    Uses the native dialog box for Mac users.
  */
  QString GuiMessage::getExistingDirectoryInternal(const QString &caption, const QString &dir,
                                                   const QString &bottomMessage)
  {
    TRACE;
    QString fileName;
    if(QThread::currentThread()==Application::instance()->mainThread()) {
      static const QString key="filter-directory";
      QString curDir;
      if(dir.isEmpty()) {
        curDir=Settings::getPath(caption);
      } else {
        curDir=dir;
      }
      // Mac dialog does not support filter selection, temporarily abandoned.
      /*#ifdef Q_OS_MAC
      fileName=QFileDialog::getExistingDirectory(qApp->activeWindow(), caption, curDir);
      if(!fileName.isEmpty()) {
        QFileInfo finfo(fileName);
        Settings::setPath(key, finfo.dir());
      }
      #else*/
      FileDialog fd(qApp->activeWindow(), caption, curDir);
      fd.setOption(QFileDialog::DontUseNativeDialog, true);
      if(!bottomMessage.isNull()) {
        QGridLayout *layout=qobject_cast<QGridLayout *>(fd.layout());
        if(layout) {
          QLabel *label=new QLabel(bottomMessage);
          label->setTextInteractionFlags(Qt::TextBrowserInteraction);
          label->setWordWrap(true);
          layout->addWidget(label, layout->rowCount(), 0, 1, layout->columnCount());
        } else {
          App::log(bottomMessage+"\n");
        }
      }
      fd.setFileMode(QFileDialog::Directory);
      fd.getRect(key);
      fd.setHistory(Settings::getDirHistory(key));
      if(fd.exec()==QDialog::Accepted && !fd.selectedFiles().isEmpty()) {
        fileName=fd.selectedFiles().first();
        fd.setRect(caption);
        Settings::setPath(caption, fileName);
        Settings::setDirHistory(caption, fileName);
      }
      //#endif
    } else {
      Mutex m;
      m.lock();
      QWaitCondition reply;
      emit asyncGetExistingDirectorySignal(&fileName, &reply, caption, dir, bottomMessage);
      reply.wait(&m);
      m.unlock();
    }
    return fileName;
  }

  /*!
    Always returns an absolute path, normal dialog with save-retore mechanism.

    Uses the native dialog box for Mac users.
  */
  QStringList GuiMessage::getOpenFileNamesInternal(const QString &caption, const QString &filter,
                                                   const QString&directory, const QString &bottomMessage)
  {
    TRACE;
    QStringList fileNames;
    if(QThread::currentThread()==Application::instance()->mainThread()) {
      QString key="filter-"+QString::number(qHash(filter));
      // Mac dialog does not support filter selection, temporarily abandoned.
      /* #ifdef Q_OS_MAC
      fileNames=QFileDialog::getOpenFileNames(qApp->activeWindow(), caption, Settings::getPath(key));
      if(!fileNames.isEmpty()) {
        QFileInfo finfo(fileNames.first());
        Settings::setPath(key, finfo.dir());
      }
      #else */
      FileDialog fd(qApp->activeWindow(), caption, Settings::getPath(key), filter);
      fd.setOption(QFileDialog::DontUseNativeDialog, true);
      if(!bottomMessage.isNull()) {
        QGridLayout *layout=qobject_cast<QGridLayout *>(fd.layout());
        if(layout) {
          QLabel *label=new QLabel(bottomMessage);
          label->setTextInteractionFlags(Qt::TextBrowserInteraction);
          label->setWordWrap(true);
          layout->addWidget(label, layout->rowCount(), 0, 1, layout->columnCount());
        } else {
          App::log(bottomMessage+"\n");
        }
      }
      fd.setFileMode(QFileDialog::ExistingFiles);
      fd.getRect(key);
      QString filterStr=Settings::getFilter(key);
      if(!filterStr.isEmpty()) fd.selectNameFilter(filterStr);
      fd.setHistory(Settings::getDirHistory(key));
      if(!directory.isEmpty()) fd.setDirectory(directory);
      if(fd.exec()==QDialog::Accepted) {
        fileNames=fd.selectedFiles();
        QFileInfo finfo(fileNames.first());
        fd.setRect(key);
        Settings::setPath(key, finfo.dir());
        Settings::setDirHistory(key , finfo.dir());
        Settings::setFilter(key, fd.selectedNameFilter());
      }
      //#endif
    } else {
      Mutex m;
      m.lock();
      QWaitCondition reply;
      emit asyncGetOpenFileNamesSignal(&fileNames, &reply, caption, filter, directory, bottomMessage);
      reply.wait(&m);
      m.unlock();
    }
    return fileNames;
  }

} // namespace QGpGuiTools
