// ================================================================
// $Id: errorg.h,v 1.1.1.1 2002/10/21 13:20:03 damez Exp $
//
// errorg.h
//     This is the support to report messages and errors/
//       and debug bugs in BRDFLIB.
//
//  The design of these streams definition was motivated when
//    reading PovRay manual.
//
// Class: CMsgStreams
//
// Licence and usage conditions in November 2003:
// This file can be used and modified only with written permission of
// Vlastimil Havran, Pohodli 27, 57001 Litomysl, the Czech Republic.
// This library is granted to be used by Polina Kondratieva within
// her MPI HIWI job working on BRDFLIB library. The usage condition
// may change in the next version of the library. At the moment,
// the library development is supported by Max-Planck-Institut for
// Informatik, Stuhlsatzenhausweg 85, 66123 Saarbruecken Germany
// See WWW: http://www.mpi-sb.mpg.de
// REPLACEMENT_STRING
//
// Initial coding by Vlastimil Havran, February 2000
//
// Given to BRDFLIB project for the Polina Kondratieva's
// HIWI JOB assignment in November 2003.

#ifndef __ERRMSG_H__
#define __ERRMSG_H__

// BRDFLIB headers
#include "configh.h"


__BEGIN_BRDFLIB_HEADER

// This is the class to be used to define messages stream in different
// context of the program
class CMsgStreams
{
public:
  //the stream types used for redirection
  enum EType{ EE_BANNER, EE_DEBUG, EE_FATAL, EE_APPOPTS, EE_STATS,
	      EE_REFSTATS, EE_STATUS, EE_WARNING};
  
  // stream for reporting name of the program and help
  static ostream *sbanner;

  // stream for reporting debugging messages
  static ostream *sdebug;

  // stream for reporting fatal errors
  static ostream *sfatal;

  // stream for reporting aplication options, when it is run
  static ostream *sappopts;

  // stream for reporting statistics after application run was finished
  // It means the statitistics to a console, not user defined statistics file.
  static ostream *sstats;

  // stream for reporting difference of current application run with
  // reference statistics specified by a user
  static ostream *srefstats;

  // stream for reporting status - what is system doing at the moment
  static ostream *sstatus;

  // stream for reporting suspicious states in the input data
  static ostream *swarning;

  // -------------------------------------------------------------------------
  // the definition of streams, must be run at the main() as first command
  static void Init();

  // the redirection of concrete stream - which stream is one of the static
  // stream above, where is address of cout, cerr or any ofstream
  static void Redirect(CMsgStreams::EType whichStream, ostream* where);

  // These function closes and flushes all opened streams above
  static void CloseAll();

  static const char* FLUSH_WI;
};

// --------------------------------------------------------------------------
// These macros should not be changed -- just for ease of writing messages
// they should be used in the program, e.g.: FATAL << "x < y"

// The MACROS ending with W as DEBUGW assures, that they defing the stream
// without any header report - they can be used as references to the stream
// across the program

// stream for reporting name of the program and help
#define BANNER    (*CMsgStreams::sbanner)
// without initial message
#define BANNERW   (*CMsgStreams::sbanner)

// stream for reporting debugging messages
#define DEBUG     (*CMsgStreams::sdebug) << "DEBUG: "
// without initial message
#define DEBUGW    (*CMsgStreams::sdebug)

// stream for reporting fatal errors
#define FATAL     (*CMsgStreams::sfatal) << "FATAL_ERROR: "
// without initial message
#define FATALW    (*CMsgStreams::sfatal)

// stream for reporting aplication options, when it is run
#define APPOPTS   (*CMsgStreams::sappopts)
// without initial message
#define APPOPTSW  (*CMsgStreams::sappopts)

// stream for reporting statistics
#define STATS     (*CMsgStreams::sstats)
// without initial message
#define STATSW    (*CMsgStreams::sstats)

// stream for reporting difference of reference statistics with
// current application run
#define REFSTATS  (*CMsgStreams::srefstats)
// without initial message
#define REFSTATSW (*CMsgStreams::srefstats)

// stream for reporting status - what is system doing at the moment
#define STATUS    (*CMsgStreams::sstatus)
// without initial message
#define STATUSW   (*CMsgStreams::sstatus)

// stream for reporting suspicious states in the input data
#define WARNING (*CMsgStreams::swarning)
// without initial message
#define WARNINGW   (*CMsgStreams::swarning)

#define WARNING_INFO(text)\
	WARNING << "file :" << __FILE__ << ", line : " << __LINE__ << "\n" << text << CMsgStreams::FLUSH_WI;

// -----------------------------------------------------------------
// This is the function to be used to exit the program when
// some fatal implementation error in the program was detected -
// it reports the core file available immediately for debugging
#if 1
#define FATAL_ABORT { FATAL << "in the file " << __FILE__ \
  << " , on the line " << __LINE__ << endl; FATALW << flush; abort();}
#else
// for debugging to prevent core dumps
#define FATAL_ABORT { FATAL << "in the file " << __FILE__ \
  << " , on the line " << __LINE__ << endl; FATALW << flush; exit(9);}
#endif

// -----------------------------------------------------------------
// This is the function to be used to exit the program when
// some fatal non-implementation error was detected - the incorrect
// input data, not-enough of memory, it does not report the core file.
#define FATAL_EXIT {FATAL<<" in the data detected, exiting at file "\
<<__FILE__<<", on the line "<<__LINE__<<endl; FATALW << flush; exit(3);}


// -------------------------------------------------------------------------- 
// This is for debugging purposes of strange errors
class CDebug
{
public:
  // This is used to locate the code, where the address is changed by
  // some part of the code, that was not expected
  // ------------------------------------------------------------------------
  // the suspicious address 
  static void* addr;

  // the bool if the variable was already set
  static bool  wasSet;

  // possible content of the address
  static float content;
  
  // set the address 
  static void SetAddr(void *newAddr);
  
  // This checks without the knowledge where
  static void DoCheckAddr();

  // the function to be called to check the address content - the error can be
  // found by binary search in the source files. Its content depend on the
  // situation.
  static void DoCheckAddr(char *file, int line);
};
  
// This macro should be put in the program to check the address content 
#define DO_CHECK_ADDR  CDebug::DoCheckAddr(__FILE__, __LINE__)

//#define DO_CHECK_ADDR  CDebug::DoCheckAddr()

#define WASSET CDebug::wasSet


__END_BRDFLIB_HEADER

#endif // __ERRMSG_H__

