/***************************************************************************
**
**  This file is part of QGpCoreTools.
**
**  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)
**
***************************************************************************/

#ifndef MESSAGE_H
#define MESSAGE_H

#include "Translations.h"
#include "QGpCoreToolsDLLExport.h"
#include "MessageContext.h"
#include "Mutex.h"

namespace QGpCoreTools {

  #define MSG_ID Message::messageId(__FILE__, __LINE__)

  class QGPCORETOOLS_EXPORT Message
  {
    TRANSLATIONS("Message")
  public:
    Message();
    virtual ~Message() {}

    void beginContext(bool quiet=false);
    void endContext();

    static uint messageId(const char * fileName, int lineNumber);

    enum Answer {Answer0, Answer1, Answer2};
    enum Severity {Question, Information, Warning, Critical, Fatal};

    static void wrongTextFormat(FILE * fErr, const QString&caption, const QString&fileName);
    static void wrongTextFormat(QTextStream&sErr, const QString&caption);
    static QString getOpenFileName(const QString &caption,
                                   const QString &filter=QString(),
                                   const QString &directory=QString(),
                                   const QString &bottomMessage=QString());

    static QString getSaveFileName(const QString &caption,
                                   const QString &filter=QString(),
                                   const QString &selection=QString(),
                                   const QString &bottomMessage=QString());

    static QStringList getOpenFileNames(const QString &caption,
                                        const QString &filter=QString(),
                                        const QString &directory=QString(),
                                        const QString &bottomMessage=QString());

    static QString getExistingDirectory(const QString &caption,
                                        const QString &directory=QString(),
                                        const QString &bottomMessage=QString());

    static inline Answer information(uint msgId, const QString &caption, const QString &text,
                                     bool againOption=false);
    static inline Answer information(uint msgId, const QString &caption, const QString &text,
                                     QString answer0, bool againOption=false);
    static inline Answer information(uint msgId, const QString &caption, const QString &text,
                                     QString answer0, QString answer1, bool againOption=false);
    static Answer information(uint msgId, const QString &caption, const QString &text,
                              QString answer0, QString answer1, QString answer2, bool againOption=false);

    static inline Answer warning(uint msgId, const QString &caption, const QString &text,
                                 bool againOption=false);
    static inline Answer warning(uint msgId, const QString &caption, const QString &text,
                                 QString answer0, bool againOption=false);
    static inline Answer warning(uint msgId, const QString &caption, const QString &text,
                                 QString answer0, QString answer1, bool againOption=false);
    static Answer warning(uint msgId, const QString &caption, const QString &text,
                          QString answer0, QString answer1, QString answer2, bool againOption=false);

    static inline Answer critical(uint msgId, const QString &caption, const QString &text,
                                  bool againOption=false);
    static inline Answer critical(uint msgId, const QString &caption, const QString &text,
                                  QString answer0, bool againOption=false);
    static inline Answer critical(uint msgId, const QString &caption, const QString &text,
                                  QString answer0, QString answer1, bool againOption=false);
    static Answer critical(uint msgId, const QString &caption, const QString &text,
                           QString answer0, QString answer1, QString answer2, bool againOption=false);

    static inline Answer question(uint msgId, const QString &caption, const QString &text,
                                  bool againOption=false);
    static inline Answer question(uint msgId, const QString &caption, const QString &text,
                                  QString answer0, bool againOption=false);
    static inline Answer question(uint msgId, const QString &caption, const QString &text,
                                  QString answer0, QString answer1, bool againOption=false);
    static Answer question(uint msgId, const QString &caption, const QString &text,
                           QString answer0, QString answer1, QString answer2, bool againOption=false);

    static QString ok() {return tr("OK");}
    static QString cancel() {return tr("Cancel");}
    static QString yes() {return tr("Yes");}
    static QString no() {return tr("No");}
    static QString close() {return tr("Close");}
    static QString abort() {return tr("Abort");}
    static QString retry() {return tr("Retry");}
    static QString ignore() {return tr("Ignore");}
    static QString yesAll() {return tr("Yes to all");}
    static QString noAll() {return tr("No to all");}
    static QString severityString(Severity sev);
  protected:
    inline bool hasAutoAnswer(uint msgId) const;
    inline bool quiet() const;
    void setAutoAnswer(uint msgId, Answer a);
    Answer autoAnswer(uint msgId,
                       Severity sev,
                       QString caption,
                       const QString &text,
                       QString answer0,
                       QString answer1,
                       QString answer2);
    virtual Answer message(uint msgId,
                            Severity sev,
                            QString caption,
                            const QString &text,
                            QString answer0,
                            QString answer1,
                            QString answer2,
                            bool againOption);
    virtual QString getOpenFileNameInternal(const QString &caption,
                                            const QString &filter,
                                            const QString &directory,
                                            const QString &bottomMessage);

    virtual QString getSaveFileNameInternal(const QString &caption,
                                            const QString &filter,
                                            const QString &selection,
                                            const QString &bottomMessage);

    virtual QStringList getOpenFileNamesInternal(const QString &caption,
                                                 const QString &filter,
                                                 const QString &directory,
                                                 const QString &bottomMessage);

    virtual QString getExistingDirectoryInternal(const QString &caption,
                                                 const QString &directory,
                                                 const QString &bottomMessage);

  private:
    static QString directoryPath(const QString &directory);
    // Relates the process level to the answers selected by the user
    class Context {
    public:
      Context(bool q=false) {quiet=q;}

      QMap<uint, Answer> answers;
      bool quiet;
    };
    QStack<Context> _contexts;
    mutable Mutex _contextMutex;
  };

  inline bool Message::hasAutoAnswer(uint msgId) const
  {
    QMutexLocker ml(&_contextMutex);
    return _contexts.top().answers.contains(msgId);
  }

  inline bool Message::quiet() const
  {
    QMutexLocker ml(&_contextMutex);
    return _contexts.top().quiet;
  }

  inline Message::Answer Message::information(uint msgId, const QString &caption, const QString &text,
                                              bool againOption)
  {
    return information(msgId, caption, text, QString(), QString(), QString(), againOption);
  }

  inline Message::Answer Message::information(uint msgId, const QString &caption, const QString &text,
                                                     QString answer0, bool againOption)
  {
    return information(msgId, caption, text, answer0, QString(), QString(), againOption);
  }

  inline Message::Answer Message::information(uint msgId, const QString &caption, const QString &text,
                                                     QString answer0, QString answer1, bool againOption)
  {
    return information(msgId, caption, text, answer0, answer1, QString(), againOption);
  }

  inline Message::Answer Message::warning(uint msgId, const QString &caption, const QString &text,
                                                 bool againOption)
  {
    return warning(msgId, caption, text, QString(), QString(), QString(), againOption);
  }

  inline Message::Answer Message::warning(uint msgId, const QString &caption, const QString &text,
                                                 QString answer0, bool againOption)
  {
    return warning(msgId, caption, text, answer0, QString(), QString(), againOption);
  }

  inline Message::Answer Message::warning(uint msgId, const QString &caption, const QString &text,
                                                 QString answer0, QString answer1, bool againOption)
  {
    return warning(msgId, caption, text, answer0, answer1, QString(), againOption);
  }

  inline Message::Answer Message::critical(uint msgId, const QString &caption, const QString &text,
                                                  bool againOption)
  {
    return critical(msgId, caption, text, QString(), QString(), QString(), againOption);
  }

  inline Message::Answer Message::critical(uint msgId, const QString &caption, const QString &text,
                                                  QString answer0, bool againOption)
  {
    return critical(msgId, caption, text, answer0, QString(), QString(), againOption);
  }

  inline Message::Answer Message::critical(uint msgId, const QString &caption, const QString &text,
                                                  QString answer0, QString answer1, bool againOption)
  {
    return critical(msgId, caption, text, answer0, answer1, QString(), againOption);
  }

  inline Message::Answer Message::question(uint msgId, const QString &caption, const QString &text,
                                                  bool againOption)
  {
    return question(msgId, caption, text, QString(), QString(), QString(), againOption);
  }
  inline Message::Answer Message::question(uint msgId, const QString &caption, const QString &text,
                                                  QString answer0, bool againOption)
  {
    return question(msgId, caption, text, answer0, QString(), QString(), againOption);
  }
  inline Message::Answer Message::question(uint msgId, const QString &caption, const QString &text,
                                                  QString answer0, QString answer1, bool againOption)
  {
    return question(msgId, caption, text, answer0, answer1, QString(), againOption);
  }

} // namespace QGpCoreTools

#endif // MESSAGE_H
