// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "brillo/syslog_logging.h"

#include <syslog.h>
#include <unistd.h>

#include <string>

// syslog.h and base/logging.h both try to #define LOG_INFO and LOG_WARNING.
// We need to #undef at least these two before including base/logging.h.  The
// others are included to be consistent.
namespace {
const int kSyslogDebug    = LOG_DEBUG;
const int kSyslogInfo     = LOG_INFO;
const int kSyslogWarning  = LOG_WARNING;
const int kSyslogError    = LOG_ERR;
const int kSyslogCritical = LOG_CRIT;

#undef LOG_INFO
#undef LOG_WARNING
#undef LOG_ERR
#undef LOG_CRIT
}  // namespace

#include <base/logging.h>

static std::string s_ident;
static std::string s_accumulated;
static bool s_accumulate;
static bool s_log_to_syslog;
static bool s_log_to_stderr;
static bool s_log_header;

static bool HandleMessage(int severity,
                          const char* /* file */,
                          int /* line */,
                          size_t message_start,
                          const std::string& message) {
  switch (severity) {
    case logging::LOG_INFO:
      severity = kSyslogInfo;
      break;

    case logging::LOG_WARNING:
      severity = kSyslogWarning;
      break;

    case logging::LOG_ERROR:
      severity = kSyslogError;
      break;

    case logging::LOG_FATAL:
      severity = kSyslogCritical;
      break;

    default:
      severity = kSyslogDebug;
      break;
  }

  const char* str;
  if (s_log_header) {
    str = message.c_str();
  } else {
    str = message.c_str() + message_start;
  }

  if (s_log_to_syslog)
    syslog(severity, "%s", str);
  if (s_accumulate)
    s_accumulated.append(str);
  return !s_log_to_stderr && severity != kSyslogCritical;
}

namespace brillo {
void SetLogFlags(int log_flags) {
  s_log_to_syslog = (log_flags & kLogToSyslog) != 0;
  s_log_to_stderr = (log_flags & kLogToStderr) != 0;
  if ((log_flags & kLogToStderrIfTty) && isatty(0))
    s_log_to_stderr = true;
  s_log_header = (log_flags & kLogHeader) != 0;
}
int GetLogFlags() {
  int flags = 0;
  flags |= (s_log_to_syslog) ? kLogToSyslog : 0;
  flags |= (s_log_to_stderr) ? kLogToStderr : 0;
  flags |= (s_log_header) ? kLogHeader : 0;
  return flags;
}
void InitLog(int init_flags) {
  logging::LoggingSettings settings;
  settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
  logging::InitLogging(settings);

  const bool kOptionPID = false;
  const bool kOptionTID = false;
  const bool kOptionTimestamp = false;
  const bool kOptionTickcount = false;
  logging::SetLogItems(
      kOptionPID, kOptionTID, kOptionTimestamp, kOptionTickcount);
  logging::SetLogMessageHandler(HandleMessage);
  SetLogFlags(init_flags);
}
void OpenLog(const char* ident, bool log_pid) {
  s_ident = ident;
  openlog(s_ident.c_str(), log_pid ? LOG_PID : 0, LOG_USER);
}
void LogToString(bool enabled) {
  s_accumulate = enabled;
}
std::string GetLog() {
  return s_accumulated;
}
void ClearLog() {
  s_accumulated.clear();
}
bool FindLog(const char* string) {
  return s_accumulated.find(string) != std::string::npos;
}
}  // namespace brillo