/* $Id$ */
// Copyright (C) 2000, International Business Machines
// Corporation and others.  All Rights Reserved.
// This code is licensed under the terms of the Eclipse Public License (EPL).

#ifndef CoinError_H
#define CoinError_H

#include <string>
#include <iostream>
#include <cassert>
#include <cstring>

#include "CoinUtilsConfig.h"
#include "CoinPragma.hpp"

/** A function to block the popup windows that windows creates when the code
    crashes */
void WindowsErrorPopupBlocker();

//-------------------------------------------------------------------
//
// Error class used to throw exceptions
//
// Errors contain:
//
//-------------------------------------------------------------------

/** Error Class thrown by an exception

This class is used when exceptions are thrown.
It contains:
  <ul>
  <li>message text
  <li>name of method throwing exception
  <li>name of class throwing exception or hint
  <li>name of file if assert
  <li>line number
  </ul>
  For asserts class=> optional hint
*/
class CoinError {
  friend void CoinErrorUnitTest();

private:
  CoinError()
    : message_()
    , method_()
    , class_()
    , file_()
    , lineNumber_()
  {
    // nothing to do here
  }

public:
  //-------------------------------------------------------------------
  // Get methods
  //-------------------------------------------------------------------
  /**@name Get error attributes */
  //@{
  /// get message text
  inline const std::string &message() const
  {
    return message_;
  }
  /// get name of method instantiating error
  inline const std::string &methodName() const
  {
    return method_;
  }
  /// get name of class instantiating error (or hint for assert)
  inline const std::string &className() const
  {
    return class_;
  }
  /// get name of file for assert
  inline const std::string &fileName() const
  {
    return file_;
  }
  /// get line number of assert (-1 if not assert)
  inline int lineNumber() const
  {
    return lineNumber_;
  }
  /// Just print (for asserts)
  inline void print(bool doPrint = true) const
  {
    if (!doPrint)
      return;
    if (lineNumber_ < 0) {
      std::cout << message_ << " in " << class_ << "::" << method_ << std::endl;
    } else {
      std::cout << file_ << ":" << lineNumber_ << " method " << method_
                << " : assertion \'" << message_ << "\' failed." << std::endl;
      if (class_ != "")
        std::cout << "Possible reason: " << class_ << std::endl;
    }
  }
  //@}

  /**@name Constructors and destructors */
  //@{
  /// Alternate Constructor
  CoinError(
    std::string message__,
    std::string methodName__,
    std::string className__,
    std::string fileName_ = std::string(),
    int line = -1)
    : message_(message__)
    , method_(methodName__)
    , class_(className__)
    , file_(fileName_)
    , lineNumber_(line)
  {
    print(printErrors_);
  }

  /// Copy constructor
  CoinError(const CoinError &source)
    : message_(source.message_)
    , method_(source.method_)
    , class_(source.class_)
    , file_(source.file_)
    , lineNumber_(source.lineNumber_)
  {
    // nothing to do here
  }

  /// Assignment operator
  CoinError &operator=(const CoinError &rhs)
  {
    if (this != &rhs) {
      message_ = rhs.message_;
      method_ = rhs.method_;
      class_ = rhs.class_;
      file_ = rhs.file_;
      lineNumber_ = rhs.lineNumber_;
    }
    return *this;
  }

  /// Destructor
  virtual ~CoinError()
  {
    // nothing to do here
  }
  //@}

private:
  /**@name Private member data */
  //@{
  /// message test
  std::string message_;
  /// method name
  std::string method_;
  /// class name or hint
  std::string class_;
  /// file name
  std::string file_;
  /// Line number
  int lineNumber_;
  //@}

public:
  /// Whether to print every error
  static bool printErrors_;
};

#ifndef __STRING
#define __STRING(x) #x
#endif

#ifndef __GNUC_PREREQ
#define __GNUC_PREREQ(maj, min) (0)
#endif

#ifndef COIN_ASSERT
#define CoinAssertDebug(expression) assert(expression)
#define CoinAssertDebugHint(expression, hint) assert(expression)
#define CoinAssert(expression) assert(expression)
#define CoinAssertHint(expression, hint) assert(expression)
#else
#ifdef NDEBUG
#define CoinAssertDebug(expression) \
  {                                 \
  }
#define CoinAssertDebugHint(expression, hint) \
  {                                           \
  }
#else
#if defined(__GNUC__) && __GNUC_PREREQ(2, 6)
#define CoinAssertDebug(expression)                              \
  {                                                              \
    if (!(expression)) {                                         \
      throw CoinError(__STRING(expression), __PRETTY_FUNCTION__, \
        "", __FILE__, __LINE__);                                 \
    }                                                            \
  }
#define CoinAssertDebugHint(expression, hint)                    \
  {                                                              \
    if (!(expression)) {                                         \
      throw CoinError(__STRING(expression), __PRETTY_FUNCTION__, \
        hint, __FILE__, __LINE__);                               \
    }                                                            \
  }
#else
#define CoinAssertDebug(expression)             \
  {                                             \
    if (!(expression)) {                        \
      throw CoinError(__STRING(expression), "", \
        "", __FILE__, __LINE__);                \
    }                                           \
  }
#define CoinAssertDebugHint(expression, hint)   \
  {                                             \
    if (!(expression)) {                        \
      throw CoinError(__STRING(expression), "", \
        hint, __FILE__, __LINE__);              \
    }                                           \
  }
#endif
#endif
#if defined(__GNUC__) && __GNUC_PREREQ(2, 6)
#define CoinAssert(expression)                                   \
  {                                                              \
    if (!(expression)) {                                         \
      throw CoinError(__STRING(expression), __PRETTY_FUNCTION__, \
        "", __FILE__, __LINE__);                                 \
    }                                                            \
  }
#define CoinAssertHint(expression, hint)                         \
  {                                                              \
    if (!(expression)) {                                         \
      throw CoinError(__STRING(expression), __PRETTY_FUNCTION__, \
        hint, __FILE__, __LINE__);                               \
    }                                                            \
  }
#else
#define CoinAssert(expression)                  \
  {                                             \
    if (!(expression)) {                        \
      throw CoinError(__STRING(expression), "", \
        "", __FILE__, __LINE__);                \
    }                                           \
  }
#define CoinAssertHint(expression, hint)        \
  {                                             \
    if (!(expression)) {                        \
      throw CoinError(__STRING(expression), "", \
        hint, __FILE__, __LINE__);              \
    }                                           \
  }
#endif
#endif

//#############################################################################
/** A function that tests the methods in the CoinError class. The
    only reason for it not to be a member method is that this way it doesn't
    have to be compiled into the library. And that's a gain, because the
    library should be compiled with optimization on, but this method should be
    compiled with debugging. */
void CoinErrorUnitTest();

#ifdef __LINE__
#define CoinErrorFL(x, y, z) CoinError((x), (y), (z), __FILE__, __LINE__)
#endif

#endif

/* vi: softtabstop=2 shiftwidth=2 expandtab tabstop=2
*/
