/* Distributed under the Apache License, Version 2.0.
   See accompanying NOTICE file for details.*/

#pragma once

class Logger;
#include "LBMExports.h"
#include <sstream>
class log_lib; // Encapsulates 3rd party logging library

namespace lbm
{
  // Not happy with how std does this for floats/doubles
  std::string to_string(int i);
  std::string to_string(int i[3]);
  std::string to_string(unsigned int i);
  std::string to_string(size_t t);
  std::string to_string(size_t t[3]);
  std::string to_string(float f);
  std::string to_string(double d);
}

class LBM_DECL Loggable
{
public:

  Loggable(Logger* logger=nullptr);
  Loggable(std::string const& logfile);
  virtual ~Loggable();

  virtual Logger* GetLogger() const;
  virtual void    SetLogger(Logger& logger);

  virtual void Debug(std::string const&  msg, std::string const&  origin = "") const;
  virtual void Debug(std::stringstream &msg, std::string const&  origin = "") const;
  virtual void Debug(std::ostream &msg, std::string const&  origin = "") const;

  virtual void Info(std::string const&  msg, std::string const&  origin = "") const;
  virtual void Info(std::stringstream &msg, std::string const&  origin = "") const;
  virtual void Info(const std::stringstream &msg, std::string const&  origin = "") const;
  virtual void Info(std::ostream &msg, std::string const&  origin = "") const;

  virtual void Warning(std::string const&  msg, std::string const&  origin = "") const;
  virtual void Warning(std::stringstream &msg, std::string const&  origin = "") const;
  virtual void Warning(std::ostream &msg, std::string const&  origin = "") const;

  virtual void Error(std::string const&  msg, std::string const&  origin = "") const;
  virtual void Error(std::stringstream &msg, std::string const&  origin = "") const;
  virtual void Error(std::ostream &msg, std::string const&  origin = "") const;

  virtual void Fatal(std::string const&  msg, std::string const&  origin = "") const;
  virtual void Fatal(std::stringstream &msg, std::string const&  origin = "") const;
  virtual void Fatal(std::ostream &msg, std::string const&  origin = "") const;

  std::string to_string(int i);
  std::string to_string(int i[3]);
  std::string to_string(unsigned int i);
  std::string to_string(size_t t);
  std::string to_string(size_t t[3]);
  std::string to_string(float f);
  std::string to_string(double d);

protected:
  bool myLogger;
  Logger* m_Logger;
};

#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4100)
#endif
class LBM_DECL LoggerForward
{
public:
  virtual void ForwardDebug(std::string const&  msg, std::string const&  origin){};
  virtual void ForwardInfo(std::string const&  msg, std::string const&  origin){};
  virtual void ForwardWarning(std::string const&  msg, std::string const&  origin){};
  virtual void ForwardError(std::string const&  msg, std::string const&  origin){};
  virtual void ForwardFatal(std::string const&  msg, std::string const&  origin){};
};
#ifdef _MSC_VER
#pragma warning(pop)
#endif

class LBM_DECL Logger
{
  friend Loggable;
public:
  Logger(std::string const&  logFilename = "");
  virtual ~Logger();

  static void Initialize();
  static void Deinitialize();

  void LogToConsole(bool b);

  void ResetLogFile(std::string const&  logFilename ="");

  enum class level
  {
    Debug,
    Info,
    Warn,
    Error,
    Fatal
  };
  void SetLogLevel(level  level);
  level GetLogLevel();

  virtual void SetForward(LoggerForward* forward);
  virtual bool HasForward();

  virtual void Debug(std::string const&  msg, std::string const&  origin = "");
  virtual void Debug(std::stringstream &msg, std::string const&  origin = "");
  virtual void Debug(std::ostream &msg, std::string const&  origin = "");

  virtual void Info(std::string const&  msg, std::string const&  origin = "");
  virtual void Info(std::stringstream &msg, std::string const&  origin = "");
  virtual void Info(const std::stringstream &msg, std::string const&  origin = "");
  virtual void Info(std::ostream &msg, std::string const&  origin = "");

  virtual void Warning(std::string const&  msg, std::string const&  origin = "");
  virtual void Warning(std::stringstream &msg, std::string const&  origin = "");
  virtual void Warning(std::ostream &msg, std::string const&  origin = "");

  virtual void Error(std::string const&  msg, std::string const&  origin = "");
  virtual void Error(std::stringstream &msg, std::string const&  origin = "");
  virtual void Error(std::ostream &msg, std::string const&  origin = "");

  virtual void Fatal(std::string const&  msg, std::string const&  origin = "");
  virtual void Fatal(std::stringstream &msg, std::string const&  origin = "");
  virtual void Fatal(std::ostream &msg, std::string const&  origin = "");

  std::string to_string(int i);
  std::string to_string(int i[3]);
  std::string to_string(unsigned int i);
  std::string to_string(size_t t);
  std::string to_string(size_t t[3]);
  std::string to_string(float f);
  std::string to_string(double d);

protected:

  virtual std::string FormatLogMessage(std::string const&  origin, std::string const&  msg);

  LoggerForward* m_Forward;
private:
  log_lib* _log_lib;
};
