/*
 *  Copyright (c) 2007,2008,2010 Cyrille Berger <cberger@cberger.net>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation;
 * either version 2, or (at your option) any later version of the License.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; see the file COPYING.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#ifndef _CAUCHY_DEBUG_H_
#define _CAUCHY_DEBUG_H_

#include <iostream>
#include <stdlib.h>
#include <Cauchy/String.h>

class DebugDeleter;

namespace Cauchy {
  class Token;
  class Type;
  /**
   * @internal
   * @ingroup Cauchy
   *
   * Control the debug flow in Cauchy.
   */
  class Debug {
    friend class ::DebugDeleter;
    public:
      Debug();
      ~Debug();
      static bool isDebugEnabled( const String& _libraryName, const String& _fileName, const String& _functionName );
      /**
       * @return the debug stream used to output debug messages
       */
      static std::ostream& debug( const String& _libraryName, const String& _fileName, int _line, const String& _functionName );
      /**
       * @return the warning stream used to output warning messages
       */
      static std::ostream& warning( const String& _libraryName, const String& _fileName, int _line, const String& _functionName );
      /**
       * @return the error stream used to output error messages
       */
      static std::ostream& error( const String& _libraryName, const String& _fileName, int _line, const String& _functionName );
    private:
      struct Private;
  };
  std::ostream& operator<< (std::ostream& ostr, const Token& token);
  std::ostream& operator<< (std::ostream& ostr, const Type& type);
}

#if (defined(__GNUC__) && !( defined(__sun) || defined(sun) )) || ( ( defined(hpux) || defined(__hpux) ) && ( defined(__HP_aCC) || __cplusplus >= 199707L )  )
#  define FUNC_INFO __PRETTY_FUNCTION__
#elif defined(_MSC_VER) && _MSC_VER > 1300
#  define FUNC_INFO __FUNCSIG__
#else
#  define FUNC_INFO ""
#endif

#define CAUCHY_WARNING(msg) \
  Cauchy::Debug::warning(COUMPONENT_NAME, __FILE__, __LINE__, FUNC_INFO ) << msg << std::endl;

#define CAUCHY_ERROR(msg) \
  Cauchy::Debug::error(COUMPONENT_NAME, __FILE__, __LINE__, FUNC_INFO ) << msg << std::endl;

#define CAUCHY_ABORT(msg) \
  CAUCHY_ERROR(msg); \
  abort();

#ifdef CAUCHY_ENABLE_DEBUG_OUTPUT

#include <assert.h>

#define CAUCHY_DEBUG(msg) \
  if(Cauchy::Debug::isDebugEnabled(COUMPONENT_NAME, __FILE__, FUNC_INFO ) ) { \
    Cauchy::Debug::debug(COUMPONENT_NAME, __FILE__, __LINE__, FUNC_INFO ) << msg << std::endl; \
  }

#define CAUCHY_ASSERT(assrt) \
  if( not (assrt ) ) \
  { \
    CAUCHY_ABORT( "Assertion failed: " << #assrt ); \
  }
#define CAUCHY_CHECK_PTR(ptr) \
  if( not (assrt ) ) \
  { \
    CAUCHY_ABORT( "Null pointer: " << #ptr ); \
  }
#define CAUCHY_CHECK_EQUAL(val1, val2) \
  if( val1 != val2 ) \
  { \
    CAUCHY_ABORT( #val1 << " != " << #val2 ); \
  }

#include <vector>

#define CAUCHY_COMPARE_FUNCTION_PARAMETERS( _FUNC_, _PARAMS_ ) \
  compareFunctionParameters( _FUNC_, _PARAMS_ );

#else

#define CAUCHY_DEBUG(msg)
#define CAUCHY_ASSERT(assrt)
#define CAUCHY_CHECK_PTR(ptr) (void)ptr;
#define CAUCHY_CHECK_EQUAL(val1, val2) (void)val1; (void)val2;
#define CAUCHY_COMPARE_FUNCTION_PARAMETERS( _FUNC_, _PARAMS_ ) (void)_FUNC_; (void)_PARAMS_; \

#endif

#endif
