/*****************************************************************************
 * $CAMITK_LICENCE_BEGIN$
 *
 * CamiTK - Computer Assisted Medical Intervention ToolKit
 * (c) 2001-2025 Univ. Grenoble Alpes, CNRS, Grenoble INP - UGA, TIMC, 38000 Grenoble, France
 *
 * Visit http://camitk.imag.fr for more information
 *
 * This file is part of CamiTK.
 *
 * CamiTK is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * CamiTK 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 version 3 for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with CamiTK.  If not, see <http://www.gnu.org/licenses/>.
 *
 * $CAMITK_LICENCE_END$
 ****************************************************************************/

#ifndef INTERFACELOGGER_H
#define INTERFACELOGGER_H

// -- Core stuff
#include "CamiTKAPI.h"

class QObject;

#include <QDir>
#include <QFileInfo>

namespace camitk {

/**
 * @ingroup group_sdk_libraries_core_utils
 *
 * @brief
 * The CamiTK logger interface provides a flexible tracing system to CamiTK applications.
 * Messages can logged on the standard output or on a file (or both) and can also show QMessageBox dialog.
 *
 * CamiTK Logger Interface defines the API for all logger used by CamiTK applications.
 *
 * For more information about how to use log @see Log and CamiTKLogger
 */

class CAMITK_API InterfaceLogger {

public:

#ifdef ERROR
#define CAMITK_WINDOWS_SYSTEM_ERROR_SAFEGUARD ERROR
#undef ERROR
#endif
    /// @enum LogLevel: how chatty should the log output be... @see getLogLevel()
    enum LogLevel {
        NONE = 0,  ///< No message is logged
        ERROR = 1,  ///< Only error messages are logged
        WARNING = 2,  ///< Only Warning and Error messages are logged
        INFO = 3,  ///< information, warning and error messages are logged
        TRACE = 4,  ///< all types of messages are logged
    };

#ifdef CAMITK_WINDOWS_SYSTEM_ERROR_SAFEGUARD
#define ERROR CAMITK_WINDOWS_SYSTEM_ERROR_SAFEGUARD
#endif

    /// empty virtual destructor, to avoid memory leak
    virtual ~InterfaceLogger() = default;

    /** Get the current verbosity level of the log.
     */
    virtual LogLevel getLogLevel() = 0;

    /** Sets Current verbosity level of the log.
     */
    virtual void setLogLevel(LogLevel level) = 0;

    /** Allows the logger to write on std::cout
     */
    virtual void setLogToStandardOutput(bool writeToStdOut) = 0;

    /** check if the logger is currently writing on standard output (std::cout)
     *  @return true if the logger is currently writing on std output, false otherwise.
     */
    virtual bool getLogToStandardOutput() = 0;

    /** Ask the logger to write to the log file.
     *  By default, the directory to write to is the subdirectory "CamiTK" in the system temporary directory.
     *  The file name itself will be determined by the logger.
     *
     *  @return true if the logger is going to log into the file (if the parameter is true, it also means that there
     *          was no error in opening the logfile for writing in the log file directory)
     */
    virtual bool setLogToFile(bool writeToFile) = 0;

    /** Set the specific directory to write to (default is the subdirectory "CamiTK" in the system temporary directory).
     *  If the log directory is different than the existing one:
     *  - if moveExistingLogFile is true (default), the current log file is moved to the new directory, new messages will
     *    be appened
     *  - if moveExistingLogFile is false, a new log file is generated, previous log file is kept untouched in the previous
     *    temporary directory
     *
     * @param directoryName the new directory to use for the log file
     * @param moveExistingLogFile if true, the existing log file is move to the new directory and use to append the log messages
     *        from now.
     *
     * @return if the logger is already logging to a file, returns true if the log file could have been created in the given directory, otherwise returns the log to file status.
     */
    virtual bool setLogFileDirectory(QDir directoryName, bool moveExistingLogFile = true) = 0;

    /// check if the logger is currently writing on a file
    virtual bool getLogToFile() = 0;

    /// @return the current file information about the current log file
    virtual QFileInfo getLogFileInfo() = 0;

    /** Set the lowest log level that will open modal message box for messages instead
     *  of (silently/undisruptedly) write on std output.
     */
    virtual void setMessageBoxLevel(LogLevel level) = 0;

    /// @return get the current lowest log level that will generate modal message box
    virtual LogLevel getMessageBoxLevel() = 0;

    /** Allows the logger to add debug information to the log message.
     *  Debug information contains the filename, line number and method names where the log was called.
     *  Note that the exact content of the method name debug information depends on the compiler.
     */
    virtual void setDebugInformation(bool) = 0;

    /// @return true if the logger is currently printing the debug information in the log message.
    virtual bool getDebugInformation() = 0;

    /** By default a logger should always show the time-stamp in the form of "yyyy-MM-dd HH:mm:ss.zzz"
     *  In test environment, reproducible log message might be prefered. In this case the time
     *  stamp can be disabled.
     *  @param showTimeStamp if false the time stamp is not printed in log message.
     */
    virtual void setTimeStampInformation(bool showTimeStamp) = 0;

    /// @return true if the logger is currently printing the time stamp information in the log messages.
    virtual bool getTimeStampInformation() = 0;

    /** Log a message:
     *  If the logger is allowed to write on standard output, it will display the message (and timestamp) on the standard output
     *  If the logger is allowed to write on a file, it will also display the message in the log file.
     *
     *  The level parameter gives the current message level that has to be compared with the logger level:
     *  if this level is greater or equals to the current log level, the current message will be logged.
     *
     *  Example: if the logger level is at WARNING, only ERROR and WARNING level messages will be displayed.
     *
     *  If in a static method or a non QObject class, then call this method with an empty last parameter.
     */
    virtual QString log(const QString msg, const LogLevel level, char const* fileName, char const* methodName, int lineNumber, const QObject* sender = nullptr) = 0;
};

}

#endif // INTERFACELOGGER_H
