// vi:set ft=cpp: -*- Mode: C++ -*-
/**
 * \internal
 * \file
 * \brief Debug interface
 */
/*
 * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
 *               Alexander Warg <warg@os.inf.tu-dresden.de>
 *     economic rights: Technische Universität Dresden (Germany)
 *
 * License: see LICENSE.spdx (in this directory or the directories above)
 */
#pragma once

#include <l4/sys/types.h>

namespace L4Re { namespace Util {
class Err
{
public:
  enum Level
  {
    Normal = 0,
    Fatal,
  };

  static char const *const levels[];

  void tag() const
  { cprintf("%s: %s", _component, levels[_l]); }

  int printf(char const *fmt, ...) const
    __attribute__((format(printf,2,3)));

  int cprintf(char const *fmt, ...) const
    __attribute__((format(printf,2,3)));

  constexpr Err(Level l, char const *component) : _l(l), _component(component)
  {}

private:
  Level _l;
  char const *_component;
};


class Dbg
{
private:
  void tag() const;

#ifndef NDEBUG

  unsigned long _m;
  char const *const _component;
  char const *const _subsys;

# ifndef __clang__

  int printf_impl(char const *fmt, ...) const
    __attribute__((format(printf, 2, 3)));

  int cprintf_impl(char const *fmt, ...) const
    __attribute__((format(printf, 2, 3)));

# endif

public:
  static unsigned long level;

  static void set_level(unsigned long l) { level = l; }

  bool is_active() const { return _m & level; }

# ifdef __clang__

  int printf(char const *fmt, ...) const
    __attribute__((format(printf, 2, 3)));

  int cprintf(char const *fmt, ...) const
    __attribute__((format(printf, 2, 3)));

# else

  int __attribute__((always_inline, format(printf, 2, 3)))
  printf(char const *fmt, ...) const
  {
    if (!(level & _m))
      return 0;

    return printf_impl(fmt, __builtin_va_arg_pack());
  }

  int __attribute__((always_inline, format(printf, 2, 3)))
  cprintf(char const *fmt, ...) const
  {
    if (!(level & _m))
      return 0;

    return cprintf_impl(fmt, __builtin_va_arg_pack());
  }

# endif

  explicit constexpr
  Dbg() : _m(1), _component(0), _subsys(0) { };

  explicit constexpr
  Dbg(unsigned long mask, char const *comp, char const *subs)
  : _m(mask), _component(comp), _subsys(subs)
  {}

#else

public:
  static void set_level(unsigned long) {}
  bool is_active() const { return false; }

  int printf(char const * /*fmt*/, ...) const
    __attribute__((format(printf, 2, 3)))
  { return 0; }

  int cprintf(char const * /*fmt*/, ...) const
    __attribute__((format(printf, 2, 3)))
  { return 0; }

  explicit constexpr
  Dbg() {}

  explicit constexpr
  Dbg(unsigned long, char const *, char const *) {}

#endif

};

}}

