/*****************************************************************************
 * $CAMITK_LICENCE_BEGIN$
 *
 * CamiTK - Computer Assisted Medical Intervention ToolKit
 * (c) 2001-2016 Univ. Grenoble Alpes, CNRS, TIMC-IMAG UMR 5525 (GMCAO)
 *
 * 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 CAMITKLOG_H
#define CAMITKLOG_H

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

// -- stl stuff
#include <stdlib.h>

// -- QT stuff
#include <QDateTime>

namespace camitk {
// information for the user, generic information, always here.
#define CAMITK_INFO(CLASSNAME, METHODNAME, MSG) Log("INFO", CLASSNAME, METHODNAME, MSG)
#define CAMITK_INFO_IF(B, CLASSNAME, METHODNAME, MSG)          \
{                                                       \
    if (((B))) {                                            \
        CAMITK_INFO(CLASSNAME, METHODNAME, MSG)                    \
    }                                                     \
}

// important errors use this macro. May result in seg faulting the app. Always enabled.
#define CAMITK_ERROR(CLASSNAME, METHODNAME, MSG) Log("ERROR", CLASSNAME, METHODNAME, MSG)
#define CAMITK_ERROR_IF(B, CLASSNAME, METHODNAME, MSG)         \
{                                                       \
    if ((B)) {                                              \
        CAMITK_ERROR(CLASSNAME, METHODNAME, MSG)                   \
    }                                                     \
}

// ---------------- Warning and Debug default values ----------------
#define CAMITK_WARNING(CLASSNAME, METHODNAME, MSG) ;
#define CAMITK_DEBUG(CLASSNAME, METHODNAME, MSG) ;

// ---------------- CAMITK_LOG_WARNING ----------------
#ifdef CAMITK_LOG_WARNING
// enable log level 1 : warning
#undef CAMITK_WARNING
#define CAMITK_WARNING(CLASSNAME, METHODNAME, MSG) Log("WARNING", CLASSNAME, METHODNAME, MSG)
#define CAMITK_WARNING_IF(B, CLASSNAME, METHODNAME, MSG)       \
    {                                                       \
        if ((B)) {                                              \
            CAMITK_WARNING(CLASSNAME, METHODNAME, MSG)                 \
        }                                                     \
    }
#endif // CAMITK_LOG_WARNING


// ---------------- CAMITK_LOG_DEBUG ----------------
#ifdef CAMITK_LOG_DEBUG
// enable log level 1 : warning
#undef CAMITK_WARNING
#define CAMITK_WARNING(CLASSNAME, METHODNAME, MSG) Log("WARNING", CLASSNAME, METHODNAME, MSG)
#define CAMITK_WARNING_IF(B, CLASSNAME, METHODNAME, MSG)       \
    {                                                       \
        if ((B)) {                                              \
            CAMITK_WARNING(CLASSNAME, METHODNAME, MSG)                 \
        }                                                     \
    }

// enable log level 2 : debug
#undef CAMITK_DEBUG
#define CAMITK_DEBUG(CLASSNAME, METHODNAME, MSG) Log("DEBUG", CLASSNAME, METHODNAME, MSG)
#define CAMITK_DEBUG_IF(B, CLASSNAME, METHODNAME, MSG)         \
    {                                                       \
        if ((B)) {                                              \
            CAMITK_DEBUG(CLASSNAME, METHODNAME, MSG)                   \
        }                                                     \
    }
#endif // CAMITK_LOG_DEBUG

/// log macro
#define Log(TYPE, CLASSNAME, METHODNAME, MSG)                                                                  \
{                                                                                                                    \
    (*camitk::Log::getLogStream()) << (TYPE);                                                                            \
    if (camitk::Log::getShowUser()) {                                                                                    \
        (*camitk::Log::getLogStream()) << " " << camitk::Log::getUserInformation();                                          \
    }                                                                                                                  \
    if (camitk::Log::getShowTime()) {                                                                                    \
        (*camitk::Log::getLogStream()) << " " << QDateTime::currentDateTime().toString(Qt::ISODate).toStdString();         \
    }                                                                                                                  \
    (*camitk::Log::getLogStream()) << " | " << (CLASSNAME) << "::" <<  (METHODNAME)  << std::endl;                     \
    (*camitk::Log::getLogStream()) << MSG << std::endl;                                                                \
    (*camitk::Log::getLogStream()) << "-----------------------------" << std::endl;                                      \
    camitk::Log::getLogStream()->flush();                                                                                \
}

/**
 * @ingroup group_sdk_libraries_core_utils
 *
 * @brief
 * This class is a log utility. It helps you to log messages anywhere in your code for different
 * levels: CAMITK_INFO, CAMITK_ERROR, CAMITK_WARNING and CAMITK_DEBUG.
 * Log macros CAMITK_INFO and CAMITK_ERROR are always enabled.
 * Log macros CAMITK_WARNING and CAMITK_DEBUG are two optional macro, disabled by default.
 *
 * Logs are defined by macros, which can be switch off at compile time.
 * The log behaviour is defined directly by the value of 2 cmake variables: CAMITK_LOG_FILE and CAMITK_LOG_LEVEL.
 *
 * For CAMITK_LOG_LEVEL consider the following table:
 * <table>
 *    <tr><td>CAMITK_LOG_LEVEL</td><td>Enabled macros</td></tr>
 *    <tr><td>1</td><td>CAMITK_ERROR / CAMITK_WARNING </td></tr>
 *    <tr><td>2</td><td>CAMITK_ERROR / CAMITK_WARNING / CAMITK_DEBUG </td> </tr>
 * </table>
 *
 * For CAMITK_LOG_FILE:
 * You can choose to save logs into "log.txt" file in the executable directory.
 * If this file does not exist, it is automatically created when the application is executed.
 * This option is configured by cmake variable CAMITK_LOG_FILE.
 *
 * How to use the macro in the source:
 * - Be sure that the file Log.h is correctly include in the working file.
 * - insert the MACRO that you want to use, it will be enabled depending of the log level
 *   defined at compile time.
 *
 *       Example :
 *       CAMITK_INFO("class used", "method used", "message" << std::endl);
 *
 *
 */

class CAMITK_API Log {
public :
    /// show date/time information in logs
    static void showTime(bool);

    /// get show time information
    static bool getShowTime();

    /// show or not the user information
    static void showUser(bool);

    /// get the status of show user information
    static bool getShowUser();

    /// Method used to open the log File
    static void openLogFile();

    /// Method used to close the log File
    static void closeLogFile();

    /// get the logFile (singleton) @return the currently opened ofstream or cout if the log file has not yet be opened
    static std::ostream * getLogStream();

    /// get the user information
    static std::string getUserInformation();

private :
    /// the log file
    static std::ofstream * logFilePtr;

    /// show time info
    static bool showTimeInfo;

    /// show user info
    static bool showUserInfo;
};

}

#endif // CAMITKLOG_H
