/** @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 <iostream>

namespace mrw {

  /** @addtogroup grpStackTrace */
  //@{

  /** @defgroup AutoTrace Automated Unexpected and Terminate Handler
                          with Stack Trace

      @brief Don't care about the unexpected handler, don't care about
      a try-catch in the main, let the library do all the repetitive
      work for you.

      For all your programs it is recommended to implement an
      identical unexpected handler, that rethrows, catches the @c
      mrw::exception, @c std::exception and all unknown exceptions,
      traces them and finally quits with a throw of a @c
      std::bad_exception. You are also required to write a @c try @c
      catch block around all in your @c main, so that you don't miss
      any exception. The only thing that may be different from project
      to project is, how tracing is done. The MRW C++ Class Library
      provides you with additional libraries you can link to. By
      linking to the library, you get an unexpected handler and an
      exception trace in the @c main for free: You don't need to add a
      single line of code, just link to one more library! The
      libraries differ in how tracing is done.

      The Implementation is done with a static instance of a class that
      sets the unexpected handler in the constructor.

      @section trcstderr Trace using std::cerr

      If you link to the library @c libmrwexcstderr using a linker
      option such as: @c -lmrwexcstderr, then an unexpected and a
      terminate handler are registered, that trace to the standard
      error stream @c std::cerr. You don't need to change a single
      line in your code!
  */
  //@{
  
  /** @brief unexpected handler, that traces to @c std::cerr

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

      @code
  void unexpected_stderr() {
    std::cerr<<"UNEXPECTED EXCEPTION: ----------------------------"<<std::endl;
    try {
      StackTrace::createSymtable();
      throw;
    } catch (const mrw::exception& x) {
      std::cerr<<"---------- Reason:"<<std::endl
               <<x.what()<<std::endl
               <<"---------- Stack:"<<std::endl
               <<x.stacktrace();
    } catch (const std::exception& x) {
      std::string st((std::string)StackTrace());
      std::cerr<<"---------- Reason:"<<std::endl
               <<x.what()<<std::endl
               <<"---------- Stack: "<<std::endl<<st;
    } catch (...) {
      std::string st((std::string)StackTrace());
      std::cerr<<"---------- Reason: **** not available ****"<<std::endl
               <<"---------- Stack:"<<std::endl<<st;
    }
    std::cerr<<"-------------------------------------------------"<<std::endl;
    throw std::bad_exception();
  }
      @endcode

  */
  void unexpected_stderr() {
    std::cerr<<"UNEXPECTED EXCEPTION: ----------------------------"<<std::endl;
    try {
      StackTrace::createSymtable();
      throw;
    } catch (const mrw::exception& x) {
      std::cerr<<"---------- Reason:"<<std::endl
               <<x.what()<<std::endl
               <<"---------- Stack:"<<std::endl
               <<x.stacktrace();
    } catch (const std::exception& x) {
      std::string st((std::string)StackTrace());
      std::cerr<<"---------- Reason:"<<std::endl
               <<x.what()<<std::endl
               <<"---------- Stack:"<<std::endl<<st;
    } catch (...) {
      std::string st((std::string)StackTrace());
      std::cerr<<"---------- Reason: **** not available ****"<<std::endl
               <<"---------- Stack:"<<std::endl<<st;
    }
    std::cerr<<"-------------------------------------------------"<<std::endl;
    throw std::bad_exception();
  }

  /** @brief terminate handler, that traces to @c std::cerr

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

      @code
  void terminate_stderr() {
    std::cerr<<"UNCAUGHT EXCEPTION: ----------------------------"<<std::endl;
    try {
      throw;
    } catch (const mrw::exception& x) {
      StackTrace::createSymtable();
      std::cerr<<"---------- Reason:"<<std::endl
               <<x.what()<<std::endl
               <<"---------- Stack:"<<std::endl
               <<x.stacktrace();
    } catch (const std::exception& x) {
      std::cerr<<"---------- Reason:"<<std::endl
               <<x.what()<<std::endl
               <<"---------- Stack:  **** not available ****"<<std::endl;
    } catch (...) {
      std::cerr<<"---------- Reason: **** not available ****"<<std::endl
               <<"---------- Stack:  **** not available ****"<<std::endl;
    }
    std::cerr<<"-------------------------------------------------"<<std::endl;
    exit(1);
  }
      @endcode

  */
  void terminate_stderr() {
    std::cerr<<"UNCAUGHT EXCEPTION: ----------------------------"<<std::endl;
    try {
      throw;
    } catch (const mrw::exception& x) {
      StackTrace::createSymtable();
      std::cerr<<"---------- Reason:"<<std::endl
               <<x.what()<<std::endl
               <<"---------- Stack:"<<std::endl
               <<x.stacktrace();
    } catch (const std::exception& x) {
      std::cerr<<"---------- Reason:"<<std::endl
               <<x.what()<<std::endl
               <<"---------- Stack:  **** not available ****"<<std::endl;
    } catch (...) {
      std::cerr<<"---------- Reason: **** not available ****"<<std::endl
               <<"---------- Stack:  **** not available ****"<<std::endl;
    }
    std::cerr<<"-------------------------------------------------"<<std::endl;
    exit(1);
  }

  //@}
  //@}

  class AutoStackTrace {
    public:
    AutoStackTrace() {
      std::set_unexpected(&mrw::unexpected_stderr);
      std::set_terminate(&mrw::terminate_stderr);
    }
  };

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

}
