/** @file popassert.h
    \brief This file contains the assert functions that are
    used in DEBUG.
*/

#ifndef POPASSERT_H
#define POPASSERT_H


  #ifdef NDEBUG // ASSERTIONS DISABLED

    #define POP_ASSERT(test, cause)
    #define POP_ILLEGAL(cause)

  #else         // ASSERTIONS ENABLED

    #ifdef WIN32         // Under Windows

      #define POP_ASSERT(test, cause)
      #define POP_ILLEGAL(cause)

    #elif defined(LINUX) // Under Linux

      #include <sstream>
      #include <execinfo.h>

      #define GET_BACKTRACE(stream)                                                 \
      {                                                                             \
        const int max_stack_size = 1024;                                            \
        void *buffer[max_stack_size];                                               \
        char **symbols;                                                             \
                                                                                    \
        int nb_symbols = backtrace(buffer, max_stack_size);                         \
        stream << "STACK TRACE (" << nb_symbols - 1 << " frames)" << std::endl;     \
                                                                                    \
        symbols = backtrace_symbols(buffer, nb_symbols);                            \
                                                                                    \
        for (int i = 1; i < nb_symbols; ++i)                                        \
          stream << symbols[i] << std::endl;                                        \
                                                                                    \
        free(symbols);                                                              \
      }

      #define POP_ASSERT(test, cause)                                               \
      {                                                                             \
        if (!(test))                                                                \
        {                                                                           \
          std::ostringstream o;                                                     \
                                                                                    \
          o << "Xdialog --cr-wrap --wrap --left --default-no --title "              \
            << "\"ASSERTION FAILED\" --yesno "                                      \
            << "\"FAILED TEST: "  << #test                << std::endl              \
            << "FILE NAME: "      << __FILE__             << std::endl              \
            << "LINE NUMBER: "    << __LINE__             << std::endl              \
            << "FUNCTION: "       << __PRETTY_FUNCTION__  << std::endl              \
            << "REASON: "         << cause                << std::endl;             \
          GET_BACKTRACE(o);                                                         \
          o << "Do you want to cancel the current execution?\""                     \
            << " 0 0" << std::endl;                                                 \
                                                                                    \
          if (!system(o.str().c_str()))                                             \
            abort();                                                                \
        }                                                                           \
      }

      #define POP_ILLEGAL(cause)                                                    \
      {                                                                             \
        std::ostringstream o;                                                       \
                                                                                    \
        o << "Xdialog --cr-wrap --wrap --left --default-no --title "                \
          << "\"ILLEGAL called\" --yesno "                                          \
          << "\"FILE NAME: "    << __FILE__             << std::endl                \
          << "LINE NUMBER: "    << __LINE__             << std::endl                \
          << "FUNCTION: "       << __PRETTY_FUNCTION__  << std::endl                \
          << "REASON: "         << cause                << std::endl;               \
        GET_BACKTRACE(o);                                                           \
        o << "Do you want to cancel the current execution?\""                       \
          << " 0 0" << std::endl;                                                   \
                                                                                    \
        if (!system(o.str().c_str()))                                               \
          abort();                                                                  \
      }



    #else // Not Windows or Linux

      #error "OS not supported"

    #endif

  #endif  // DEBUG

#endif  // POPASSERT_H

// Other macros to define: WARNING, INFO, DBGOP, PRECONDITION, POSTCONDITION
