/*
 * Worldvisions Weaver Software:
 *   Copyright (C) 1997, 1998 Worldvisions Computer Technology, Inc.
 * 
 * A generic data-logger class with support for multiple receivers.  If
 * no WvLogRcv objects have been created (see wvlogrcv.h) the default is
 * to log to stderr.
 * 
 * WvLog supports partial- and multiple-line log messages.  For example,
 *        log.print("test ");
 *        log.print("string\nfoo");
 * will print:
 *        appname(lvl): test string
 *        appname(lvl): foo
 */
#ifndef __WVLOG_H
#define __WVLOG_H

#include "wvstream.h"
#include <errno.h>

class WvLog;

// a WvLogRcv registers itself with WvLog and prints, captures,
// or transmits log messages.
class WvLogRcvBase
{
    friend WvLog;
protected:
    const char *appname(const WvLog *log) const;
    virtual void log(const WvLog *source, int loglevel,
		     const char *_buf, size_t len) = 0;
public:
    WvLogRcvBase();
    virtual ~WvLogRcvBase();
};


DeclareWvList(WvLogRcvBase);


// a WvLog stream accepts log messages from applications and forwards them
// to all registered WvLogRcv's.
class WvLog : public WvStream
{
    friend WvLogRcvBase;
public:
    enum LogLevel {
	Critical = 0,
	Error,
	Warning,
	Notice,
	Info,
	Debug, Debug1=Debug,
	Debug2,
	Debug3,
	Debug4,
	Debug5,
	
	NUM_LOGLEVELS
    };
    WvString app;

protected:
    const WvLog *parent;
    LogLevel loglevel;
    static WvLogRcvBaseList receivers;
    static int num_receivers, num_logs;
    static WvLogRcvBase *default_receiver;

public:
    WvLog(const WvString &_app, LogLevel _loglevel = Info,
	  const WvLog *par = NULL);
    WvLog(const WvLog &l);
    virtual ~WvLog();

    // fd==-1, but this stream is always ok
    virtual bool isok() const;
    
    // change the loglevel.  This returns the object again, so you can
    // make convenient statements like log.lvl(WvLog::Warning).print(...)
    WvLog &lvl(LogLevel _loglevel)
        { loglevel = _loglevel; return *this; }
    
    // change the loglevel and then print a message.
    size_t operator() (LogLevel _loglevel, const WvString &s)
    { 
	LogLevel l = loglevel; 
	size_t x = lvl(_loglevel).write(s);
	lvl(l);
	return x;
    }
    
    // change the loglevel and then print a formatted message
    inline size_t operator() (LogLevel _loglevel, WVSTRING_FORMAT_DECL)
    { 
	LogLevel l = loglevel;
	size_t x = lvl(_loglevel).print(WVSTRING_FORMAT_CALL);
	lvl(l);
	return x;
    }
    
    // although these appear in WvStream, they need to be re-listed for
    // some reason.
    size_t operator() (const WvString &s)
        { return WvStream::operator()(s); }
    inline size_t operator() (WVSTRING_FORMAT_DECL)
        { return WvStream::operator()(WVSTRING_FORMAT_CALL); }
    
    // split off a new WvLog object with the requested loglevel.  This way
    // you can have log at two or more levels without having to retype
    // log.lvl(WvLog::blahblah) all the time.
    WvLog split(LogLevel _loglevel) const
        { return WvLog(app, _loglevel, this); }
    
    // we override the unbuffered write function, so lines also include the
    // application and log level.
    virtual size_t uwrite(const void *buf, size_t len);
    
    // a useful substitute for the normal C perror() function
    void perror(const WvString &s)
        { print("%s: %s\n", s, strerror(errno)); }
};


#endif // __WVLOG_H
