/* 
 * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; version 2 of the
 * License.
 * 
 * This program 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 General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301  USA
 */

#ifndef __BASE_LOG_IMPL_H__
#define __BASE_LOG_IMPL_H__

#include <string>
#include <stdarg.h>
#include "base/common.h"

namespace base
{
#if defined(DEBUG) || defined(_DEBUG) || defined(ENABLE_DEBUG)
    #define DEFAULT_LOG_TO_STDERR 1
#else
    #define DEFAULT_LOG_TO_STDERR 0
#endif

class BASELIBRARY_PUBLIC_FUNC Logger
{
  public:
    // Note: When adding or changing integer id of log level mind that 
    // the numbers must be sequential from 0 to N. Also make sure that
    // log_impl.cpp:LevelText array is valid for new enum values
    enum LogLevel {
      LogNone     = 0, 
      LogError    = 1, 
      LogWarning  = 2, 
      LogInfo     = 3, 
      LogDebug    = 4, 
      LogDebug2   = 5, 
      LogDebug3   = 6, 
      NumOfLevels = LogDebug3
    };

    Logger(const bool stderr_log, const std::string& target_file);
    Logger(const std::string& dir, const bool stderr_log = DEFAULT_LOG_TO_STDERR, const std::string& file_name = "wb", int limit = 10); // Later logdir or set of log files can be passed

    static void enable_level(const LogLevel level);
    static void disable_level(const LogLevel level);
    static void logv(const LogLevel level, const char* const domain, const char* format, va_list args);
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4)
    static void log(const LogLevel level, const char* const domain, const char* format, ...) __attribute__((__format__ (__printf__, 3, 4)));
#else
    static void log(const LogLevel level, const char* const domain, const char* format, ...);
#endif
    static void log_exc(const LogLevel level, const char* const domain, const char* msg, const std::exception &exc);
    static std::string get_state();
    static void set_state(const std::string& state);
    static std::string log_filename();
    static std::string log_dir();

    static std::string active_level();
    static bool active_level(const std::string& value);

  private:
    struct LoggerImpl;
    static LoggerImpl* _impl;
};

} // End of namespace

#ifdef DEFAULT_LOG_DOMAIN

#undef log_error
#undef log_exception
#undef log_warning
#undef log_info
#undef log_debug
#undef log_debug2
#undef log_debug3

// log_domain is defined by DEFAULT_LOG_DOMAIN macro from base/log.h
#define log_error(...) base::Logger::log(base::Logger::LogError, default_log_domain, __VA_ARGS__)
#define log_exception(msg, exc) base::Logger::log_exc(base::Logger::LogError, default_log_domain, msg, exc)
#define log_warning(...) base::Logger::log(base::Logger::LogWarning, default_log_domain, __VA_ARGS__)
#define log_info(...) base::Logger::log(base::Logger::LogInfo, default_log_domain, __VA_ARGS__)
#define log_debug(...) base::Logger::log(base::Logger::LogDebug, default_log_domain, __VA_ARGS__)
#define log_debug2(...) base::Logger::log(base::Logger::LogDebug2, default_log_domain, __VA_ARGS__)
#define log_debug3(...) base::Logger::log(base::Logger::LogDebug3, default_log_domain, __VA_ARGS__)

#endif // ifdef DEFAULT_LOG_DOMAIN

#endif

