#ifndef SIGLOG_H
#define SIGLOG_H


/* Req: iostream, fstream, sstream */

enum outbuf_sink
{
    SINK_STDERR,
    SINK_FILE,
    SINK_SYSLOG
};

enum outbuf_attributes
{
    ATTRIBUTE_MILLISECONDS,  // Record milliseconds in every message
    ATTRIBUTE_YEAR_ONCE,     // Record year in next message
    ATTRIBUTE_SKIP_ONCE      // Skip output of the next message
};


/** siglog own log levels, prefixed with SLOG_ do differentiate with 
 syslog priorities (LOG_ERR, LOG_NOTICE, etc) */
enum log_level {
    SLOG_UNKNOWN = 0,
    SLOG_ERROR = 0x1,
    SLOG_WARN  = 0x2,
    SLOG_NOTE  = 0x4,
    SLOG_INFO  = 0x8,
    SLOG_DEBUG = 0x10,
    SLOG_QUIET   = SLOG_ERROR,
    SLOG_NORMAL  = SLOG_QUIET | SLOG_WARN | SLOG_NOTE,
    SLOG_VERBOSE = SLOG_NORMAL | SLOG_INFO,
    SLOG_ALL = SLOG_VERBOSE | SLOG_DEBUG
};

// Privately defined class
class siglog_outbuf;

class siglog_stream: public std::ostream
{

public:
  siglog_stream( const char* sapp_name_a );
  ~siglog_stream( );

  bool set_log_file( const char* slog_path_a );
  bool set_log_file( const char* slog_path_a,
                     std::ios_base::openmode mode_a );
  bool set_sink_on( enum outbuf_sink sink_a );   // Returns true on error
  bool set_sink_off( enum outbuf_sink sink_a );  // Returns true on error
  bool set_attribute( enum outbuf_attributes attr_a, bool state_a );

// Returns true if any sink is enabled.  This can be used
// to optimized and skip some runtime CPU work.
  bool is_any_sink_enabled(void);

protected:
  siglog_outbuf * buf;

private:

  enum log_level verbosity;

};

#include <cstdlib>
#include <string>
#include <boost/scoped_ptr.hpp>
#include <boost/property_tree/ptree.hpp>
//SIP: remove #define BOOST_FILESYSTEM_VERSION 2
#include "boost/filesystem/operations.hpp"
#include "boost/filesystem/fstream.hpp"
#include "boost/filesystem/exception.hpp"
#include "boost/filesystem/convenience.hpp"

namespace vwr
{
#if 0
}
#endif
namespace iris
{
#if 0
}
#endif

namespace pt = boost::property_tree;
namespace fs = boost::filesystem;

/// Singelton implementation of siglog_stream logger
class SimpleLogger : public siglog_stream
{
private:
    static SimpleLogger * self;
    SimpleLogger(const char * prog_name):siglog_stream(prog_name) {}
    ~SimpleLogger(){}

    static void destroyInstance(void)
        {
            if (self != 0) {
                delete self;
                self = 0;
            }
        }

public:
    static SimpleLogger * getInstance(const char * prog_name = 0)
        {
            if (self == 0) {
                if (prog_name == 0)
                    prog_name = "UnknownProgram";
                self = new SimpleLogger(prog_name);
            }
            atexit(destroyInstance); // Hack!
            return self;
        }
    void configure(const pt::ptree & conf)
        {
            bool log_to_terminal = conf.get<bool>("log_to_terminal", true);
            bool log_to_file = conf.get<bool>("log_to_file", false);
            bool append_to_file = conf.get<bool>("log_to_file", false);
            // bool verbose = conf.get<bool>("verbose", false);
            // bool debug = conf.get<bool>("debug", false);
            std::string log_directory = conf.get<std::string>("log", "/tmp");
            std::string application = conf.get<std::string>("app_name", "Unknown");
            fs::path logfile_path(log_directory);
            if (log_to_file && fs::exists(logfile_path)) {
                if (append_to_file)
                    set_log_file(logfile_path.string().c_str(), std::ios::app);
                else
                    set_log_file(logfile_path.string().c_str());
            }
            if (!log_to_terminal)
                set_sink_off(SINK_STDERR);
                
         }
};

#if 0
{
#endif
}
#if 0
{
#endif
}


#ifdef DEBUG
# define DEBUG_LOG(_STREAM) _STREAM << "DBG: "<< __FILE__ << ": " << __func__ << ": " << __LINE__ << ": "
#else
# define DEBUG_LOG(_STREAM) (_STREAM).set_attribute( ATTRIBUTE_SKIP_ONCE, true ); \
    _STREAM
#endif

#endif /* SIGLOG_H */
