#ifndef AVIFILE_AVM_OUTPUT_H
#define AVIFILE_AVM_OUTPUT_H

#include "avm_default.h"

/** Logging levels */
enum AvmLevel {
    AVML_STRERROR = 128, // when orred to level number bellow it shows (%s) strerror output

    AVML_LASTFLAG = 8,
    AVML_ERROR = 1 << AVML_LASTFLAG,   // serious error (leads to application problem)
    AVML_ERRORNO = AVML_ERROR | AVML_STRERROR,
    AVML_WARN = 2 << AVML_LASTFLAG,    // warning
    AVML_WARNNO = AVML_WARN | AVML_STRERROR,
    AVML_HINT = 3 << AVML_LASTFLAG,    // useful hint for user
    AVML_INFO = 4 << AVML_LASTFLAG,    // useful trace for running program
    AVML_DEBUG = 5 << AVML_LASTFLAG,   // debug trace
    AVML_DETAIL = 6 << AVML_LASTFLAG   // detailed debug trace
};

#ifdef __cplusplus
#include <stdarg.h>

/**********
 * WARNING - this file is meant to be used by internal avifile application
 * DO NOT USE in your own project!
 * the API here could change in any minute
 */


AVM_BEGIN_NAMESPACE;

//typedef void (*handlerFuncPtr) (const char* s, int opt);

class AvmOutput
{
public:
    static void createAvmOutput();
    static int getLevel() { return m_iLevel; }
    static AvmOutput* singleton() { return m_pSelf; }
    ~AvmOutput();
    void write(const char* mode, const char* format, ...) _avm_printf_attr(3, 4); // debuglevel 0
    void write(const char* mode, int debuglevel, const char* format, ...) _avm_printf_attr(4, 5); // any debuglevel
    void vwrite(const char* mode, const char* format, va_list va) _avm_printf_attr(3, 0);
    void vwrite(const char* mode, int debuglevel, const char* format, va_list va) _avm_printf_attr(4, 0);
    void setDebugLevel(const char* mode, int level);
    void resetDebugLevels(int level = 0);
private:
    AvmOutput();                    		//!< Only to be called by createAvmOutput
    AvmOutput(const AvmOutput&);		//!< Forbid copy constructor
    AvmOutput& operator=(const AvmOutput&);	//!< Forbid assignment
    void vwrite(const char* format, va_list va) _avm_printf_attr(2, 0);
    void flush();
    struct AvmOutputPrivate;
    struct AvmOutputPrivate* priv;
    static AvmOutput* m_pSelf;
    static int m_iLevel;
};

static inline AvmOutput* AvmOutput() { return AvmOutput::singleton(); }

class AvmOutputLog
{
    const char* m_sOutputMode;
public:
    AvmOutputLog(const char* outputMode) : m_sOutputMode(outputMode) {}
    ~AvmOutputLog() {}
    void setOutputMode(const char* s) { m_sOutputMode = s; }
    const char* getOutputMode() const { return m_sOutputMode; }
};

AVM_END_NAMESPACE;

#ifdef __GNUC__
#define AVMOUT(lev, args...) \
    do { if (lev < avm::AvmOutput::getLevel()) { avm::AvmOutput()->write(getOutputMode(), (int)lev, ## args); } } while (0)
#else
#define AVMOUT(lev, ...) \
    do { if (lev < avm::AvmOutput::getLevel()) { avm::AvmOutput()->write(getOutputMode(), (int)lev, __VA_ARGS__); } } while (0)
#endif

#define AVM_WRITE avm::AvmOutput()->write

#endif // __cplusplus

AVM_BEGIN_EXTERN_C;
/** C interface **/
void avm_printf(const char* mode, const char* format, ...)  _avm_printf_attr(2, 3);
void avm_dprintf(const char* mode, int debuglevel, const char* format, ...)  _avm_printf_attr(3, 4);
//#define avml(level, section, fmt, args...) do { if (avm_output_level >= level) avm_printf(section, fmt, ## args); } while (0)
AVM_END_EXTERN_C;

#endif // AVIFILE_AVM_OUTPUT_H
