/** @file

    $Id$

    $Date$
    $Author$

    @copy &copy; Marc W&auml;ckerlin
    @license LGPL, see file <a href="license.html">COPYING</a>

*/
#include <mrw/stacktrace.hpp>
#include <mrw/exception.hpp>
#include <exception>
#include <log4cxx/logger.h>

#ifndef _T
#define _T
#endif

namespace mrw {

  /** @addtogroup AutoTrace

      @section trclog4cxx Trace using the log4cxx Library

      If you link to the library @c libmrwexclog4cxx using a linker
      option such as: @c -lmrwexclog4cxx, then an unexpected and a
      terminate handler are registered, that trace a fatal error using
      the log4cxx library. You don't need to change a single line in
      your code!

      The log4cxx library is located at:
       - http://logging.apache.org/log4cxx

      @note The configurator is not installed automatically. If you
      want to trace e.g. on the console, you have to call @c
      log4cxx::BasicConfigurator::configure(); as first statement in
      your @c main(). @see @ref AutoInitLog4cxx if you also want to
      automatically configure @c log4cxx.
  */
  //@{

  /** @brief unexpected handler, that traces using log4cxx

      The unexpected handler is installed automatically when you link
      to @c -lmrwexclog4cxx. The implementation of this unexpected
      handler is as follows:

      @code
  void unexpected_log4cxx() {
    log4cxx::LoggerPtr logger(log4cxx::Logger::getLogger(_T("mrw.stacktrace")));
    logger->fatal("Unexpected Exception", __FILE__, __LINE__);
    StackTrace::createSymtable();
    std::string st((std::string)StackTrace());
    try {
      throw;
    } catch (const mrw::exception& x) {
      logger->fatal(std::string("Reason:\n")+x.what()
                    +"\nStack:+\n"+x.stacktrace());
    } catch (const std::exception& x) {
      logger->fatal(std::string("Reason:\n")+x.what()
                    +"\nStack:\n"+st);
    } catch (...) {
      logger->fatal(std::string("Reason: **** not available ****")
                   +"\nStack:\n"+st);
    }
    throw std::bad_exception();
  }
      @endcode

  */
  void unexpected_log4cxx() {
    log4cxx::LoggerPtr logger(log4cxx::Logger::getLogger(_T("mrw.stacktrace")));
    logger->fatal("Unexpected Exception", __FILE__, __LINE__);
    StackTrace::createSymtable();
    std::string st((std::string)StackTrace());
    try {
      throw;
    } catch (const mrw::exception& x) {
      logger->fatal(std::string("Reason:\n")+x.what()
                    +"\nStack:\n"+x.stacktrace());
    } catch (const std::exception& x) {
      logger->fatal(std::string("Reason:\n")+x.what()
                    +"\nStack:\n"+st);
    } catch (...) {
      logger->fatal(std::string("Reason: **** not available ****")
                   +"\nStack:\n"+st);
    }
    throw std::bad_exception();
  }

  /** @brief terminate handler, that traces using log4cxx

      The terminate handler is installed automatically when you link
      to @c -lmrwexclog4cxx. The implementation of this terminate
      handler is as follows:

      @code
  void terminate_log4cxx() {
    log4cxx::LoggerPtr logger(log4cxx::Logger::getLogger(_T("mrw.stacktrace")));
    logger->fatal("Uncaught Exception", __FILE__, __LINE__);
    StackTrace::createSymtable();
    std::string st((std::string)StackTrace());
    try {
      throw;
      exit(0);
    } catch (const mrw::exception& x) {
      logger->fatal(std::string("Reason:\n")+x.what()
                    +"\nStack:+\n"+x.stacktrace());
    } catch (const std::exception& x) {
      logger->fatal(std::string("Reason:\n")+x.what()
                    +"\nStack:\n"+st);
    } catch (...) {
      logger->fatal(std::string("Reason: **** not available ****")
                    +"\nStack:\n"+st);
    }
    exit(1);
  }
      @endcode

  */
  void terminate_log4cxx() {
    log4cxx::LoggerPtr logger(log4cxx::Logger::getLogger(_T("mrw.stacktrace")));
    logger->fatal("Uncaught Exception", __FILE__, __LINE__);
    StackTrace::createSymtable();
    std::string st((std::string)StackTrace());
    try {
      throw;
    } catch (const mrw::exception& x) {
      logger->fatal(std::string("Reason:\n")+x.what()
                    +"\nStack:\n"+x.stacktrace());
    } catch (const std::exception& x) {
      logger->fatal(std::string("Reason:\n")+x.what()
                    +"\nStack:\n"+st);
    } catch (...) {
      logger->fatal(std::string("Reason: **** not available ****")
                    +"\nStack:\n"+st);
    }
    exit(1);
  }

  //@}

  class AutoStackTrace {
    public:
    AutoStackTrace() {
      std::set_unexpected(&mrw::unexpected_log4cxx);
      std::set_terminate(&mrw::terminate_log4cxx);
    }
  };

  // initialize stack traces (load symbols)
  static AutoStackTrace _autoStackTrace;

}
