//==================================================================================================
// S t a n d a r d                                                                        Interface
// E r r o r
//                                                                                By Bruno Bachelet
//==================================================================================================
// Copyright (c) 1999-2016
// Bruno Bachelet - bruno@nawouak.net - http://www.nawouak.net
//
// This file is part of the B++ Library. This library is free software; you can redistribute it
// and/or modify it under the terms of the GNU Library General Public License as published by the
// Free Software Foundation; either version 2 of the License, or (at your option) any later
// version.
//
// 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 Library General Public License for more details (http://www.gnu.org).

/*DESCRIPTION*/
/* This module provides facilities to manage errors. */

// File Name //-------------------------------------------------------------------------------------
#line __LINE__ "standard/error.hpp"

// Guardian //--------------------------------------------------------------------------------------
#ifndef guStandardError
#define guStandardError

// Headers //---------------------------------------------------------------------------------------
#include <stdexcept> /*INCLUDE*/
#include <bpp/standard/environment.hpp> /*INCLUDE*/
#include <bpp/standard/type.hpp> /*INCLUDE*/

namespace bpp {

// Importation/Exportation //-----------------------------------------------------------------------
#ifdef STANDARD_DLL
 #define dll_export DLL_EXPORT
#else
 #define dll_export DLL_IMPORT
#endif

// Namespaces //------------------------------------------------------------------------------------
#define public_area  standardError
#define private_area standardError_private

namespace public_area  { /*NAMESPACE*/ using namespace standardType; }
namespace private_area { using namespace public_area; }

extern_module_name;

// Initialization //--------------------------------------------------------------------------------
#define iniStandardError
has_initializer;

// Macrocommands //---------------------------------------------------------------------------------
#ifdef EVENT_SPY_MODE
 /*MACROCOMMAND*/
 /* The expression <CODE>prLine</CODE> is integrated into the source code if
    <CODE>EVENT_SPY_MODE</CODE> is defined. */
 #define event_spy_mode(prLine) prLine

 /*MACROCOMMAND*/
 /* Gives a name to a method or function that can be then traced (do not use it with inline
    methods and functions). */
 #define method_name(prMethodName)                                                       \
  const standardError_private::clEventSpy _spy_(prMethodName,private_area::goModuleName) \

 /*MACROCOMMAND*/ /* Sends an error message from a traceable method or function. */
 #define send_error(prError)                                                                     \
  ( (prError).module()=private_area::goModuleName, (prError).method()=_spy_.method(),            \
    (prError).file()=__FILE__, (prError).line()=__LINE__+1, standardError::throwError(prError) ) \

 /*MACROCOMMAND*/
 /* Sends an error message from an inline method or function. <CODE>prMethodName</CODE> is the
    name of the method or function from which the error is sent. */
 #define send_inline_error(prError,prMethodName)                                                 \
  ( (prError).module()=private_area::goModuleName, (prError).method()=prMethodName,              \
    (prError).file()=__FILE__, (prError).line()=__LINE__+1, standardError::throwError(prError) ) \

#else
 #define event_spy_mode(prLine)

 #define method_name(prMethodName) static const tcString _methodName_ = prMethodName

 #define send_error(prError)                                                                     \
  ( (prError).module()=private_area::goModuleName, (prError).method()=_methodName_,              \
    (prError).file()=__FILE__, (prError).line()=__LINE__+1, standardError::throwError(prError) ) \

 #define send_inline_error(prError,prMethodName)                                                 \
  ( (prError).module()=private_area::goModuleName, (prError).method()=prMethodName,              \
    (prError).file()=__FILE__, (prError).line()=__LINE__+1, standardError::throwError(prError) ) \

#endif

#ifdef TESTING_MODE
 /*MACROCOMMAND*/
 /* Activated if <CODE>TESTING_MODE</CODE> is defined. Sends an error message if
    <CODE>prCondition</CODE> is evaluated to <CODE>false</CODE>. */
 #define assertion(prCondition,prError) if (not (prCondition)) send_error(prError)

 /*MACROCOMMAND*/
 /* Activated if <CODE>TESTING_MODE</CODE> is defined. Displays a flag for the debugging. */
 #define flag(prFlag) {                                                         \
  environment::out("Flag ",false,true); environment::out(#prFlag,false);        \
  environment::out(" [",false); environment::out(__FILE__,false);               \
  environment::out("][",false); environment::out(tyCardinal(__LINE__+1),false); \
  environment::out("]",true); }                                                 \

 /*MACROCOMMAND*/
 /* Activated if <CODE>TESTING_MODE</CODE> is defined. Displays the value of a variable for
    the debugging. */
 #define spy(prVariable) {                  \
  environment::out(#prVariable,false,true); \
  environment::out(" = ");                  \
  environment::out(prVariable,true); }      \

#else
 #define assertion(prCondition,prError)
 #define flag(prFlag)
 #define spy(prVariable)
#endif

/*MACROCOMMAND*/ /* Default error handling for initializers. */
#define initializer_catch                                                                   \
 catch (ctError & agError) { outError(agError); environment::terminate(); }                 \
 catch (tcString agMessage) { outError(agMessage); environment::terminate(); }              \
 catch (ctException & agException) { outException(agException); environment::terminate(); } \
 catch (...) { outUnexpectedError(); environment::terminate(); }                            \

/*MACROCOMMAND*/ /* Default error handling for programs. */
#define program_catch                                               \
 catch (ctError & agError) {                                        \
  outError(agError);                                                \
  if (environment::informationDisplayed()) environment::nextLine(); \
  clearError();                                                     \
  return (environment::quit(environment::failure));                 \
 }                                                                  \
                                                                    \
 catch (tcString agMessage) {                                       \
  outError(agMessage);                                              \
  if (environment::informationDisplayed()) environment::nextLine(); \
  clearError();                                                     \
  return (environment::quit(environment::failure));                 \
 }                                                                  \
                                                                    \
 catch (ctException & agException) {                                \
  outException(agException);                                        \
  if (environment::informationDisplayed()) environment::nextLine(); \
  clearError();                                                     \
  return (environment::quit(environment::failure));                 \
 }                                                                  \
                                                                    \
 catch (...) {                                                      \
  outUnexpectedError();                                             \
  if (environment::informationDisplayed()) environment::nextLine(); \
  clearError();                                                     \
  return (environment::quit(environment::failure));                 \
 }                                                                  \
                                                                    \
 if (environment::informationDisplayed()) environment::nextLine();  \
 return (environment::quit(environment::success));                  \

// Types & Classes //-------------------------------------------------------------------------------
namespace public_area {
 //------------------------------------------------------------------------------------------Classes
 class clError;
 //-----------------------------------------------------------------------------------Variable Types
 /*TYPE*/ /* Exception sent by the STL. */
 typedef std_exception clException;

 /*TYPE*/ /* List of errors sent by the B++ Library. */
 typedef std_vector(const clError *) clErrorS;
 //-----------------------------------------------------------------------------------Constant Types
 typedef const clError     ctError;
 typedef const clErrorS    ctErrorS;
 typedef const clException ctException;
}

namespace private_area {
 #ifdef EVENT_SPY_MODE
  class                           clEventSpy;
  typedef std_vector(tcString)    clStringS;
  enumeration { start, end }      tyEventKind;
  typedef std_vector(tyEventKind) clEventKindS;
 #endif

 typedef std::ostream clOutStream;
}

// Functions Interface //---------------------------------------------------------------------------
namespace public_area {
 inline tyBoolean operator == (ctError &,ctError &);

 function void outError(ctError &);
 function void outError(private_area::clOutStream &,ctError &);
 function void outError(tcString);
 function void outError(private_area::clOutStream &,tcString);
 function void outException(ctException &);
 function void outException(private_area::clOutStream &,ctException &);
 function void outUnexpectedError(void);
 function void outUnexpectedError(private_area::clOutStream &);

 event_spy_mode ( function void outTrace(private_area::clOutStream &); )

 function void throwError(ctError &);
 function void clearError(void);
}

namespace private_area { testing_mode ( function void test(void); ) }

// Errors //----------------------------------------------------------------------------------------
namespace public_area {
 /*ERROR*/ extern_error erInvalidErrorNumber; /* Invalid error number. */
 /*ERROR*/ extern_error erNone; /* No error. */
 /*ERROR*/ extern_error erUnexpected; /* Unexpected error. */

 /*ERROR*/ extern_error erDataLocationParameterMissing;
 /* The <CODE>data_location</CODE> parameter is missing in the initialization file. */

 /*ERROR*/ extern_error erTemporaryLocationParameterMissing;
 /* The <CODE>temporary_location</CODE> parameter is missing in the initialization file. */

 testing_mode (
  /*ERROR*/ extern_error erTestingLocationParameterMissing;
  /* The <CODE>testing_location</CODE> parameter is missing in the initialization file. */
 )

 extern_error erCreateThread;
 extern_error erMutexNotAvailable;
 extern_error erMutexUnlocked;
}

// Constants & Variables //-------------------------------------------------------------------------
/*CONSTANT*/ /* List of the errors declared in the B++ Library. */
extern_dynamic_constant(public,clErrorS,goErrorS,errors);

/*VARIABLE*/ /* Indicates if an error has been thrown. */
extern_static_constant(public,tyBoolean,goErrorThrown,errorThrown);

/*VARIABLE*/ /* Returns the pending error that is currently being thrown. */
extern_dynamic_constant(public,ctError,goCurrentError,currentError);

extern_static_constant(private,clMutex,goErrorMutex,?);

event_spy_mode (
 extern_dynamic_constant(private,clEventKindS,goEventKindS,?);
 extern_dynamic_constant(private,clStringS,goMethodS,?);
 extern_dynamic_constant(private,clStringS,goModuleS,?);
 extern_static_constant(private,clMutex,goSpyMutex,?);

 extern_static_constant(private,tcString,goEventTraceFileName,?);
 extern_static_constant(private,tyCardinal,goTraceSize,?);
)

// E r r o r  Interface //--------------------------------------------------------------------------
namespace public_area {
 /*CLASS clError */ /* Represents an error sent by the B++ Library. */
 class clError {
  //-----------------------------------------------------------------------------------------Friends
  friend inline tyBoolean operator == (ctError &,ctError &);
  //-----------------------------------------------------------------------------------------Private
  private_property clError & operator = (ctError &);
  //------------------------------------------------------------------------------------------Public
  /*ATTRIBUTE clError */ /* Message of the error. */
  read_only_attribute(tcString,atMessage,message);

  /*ATTRIBUTE clError */ /* Number of the error. */
  read_only_attribute(tyCardinal,atNumber,number);

  /*ATTRIBUTE clError */ /* Module where the error occurs. */
  read_write_attribute(tcString,atModule,module);

  /*ATTRIBUTE clError */ /* Method where the error occurs. */
  read_write_attribute(tcString,atMethod,method);

  /*ATTRIBUTE clError */ /* File where the error occurs. */
  read_write_attribute(tcString,atFile,file);

  /*ATTRIBUTE clError */ /* Line where the error occurs. */
  read_write_attribute(tyCardinal,atLine,line);

  public_property constructor clError(void);
  public_property constructor clError(ctError &);
  public_property destructor  clError(void) {}

  public_property void create(tcString);
 };
}

// E v e n t S p y  Interface //--------------------------------------------------------------------
event_spy_mode (
 namespace private_area {
  class clEventSpy {
   private_property constructor clEventSpy(const clEventSpy &);
   private_property clEventSpy & operator = (const clEventSpy &);

   read_only_attribute(tcString,atMethod,method);
   read_only_attribute(tcString,atModule,module);

   public_property constructor clEventSpy(tcString,tcString);
   public_property destructor  clEventSpy(void);
  };
 }
)

// Functions Inline //------------------------------------------------------------------------------
namespace public_area  {
 //--------------------------------------------------------------------------------------Operator ==
 /*FUNCTION*/ /* Checks if two errors are the same. */
 inline tyBoolean operator == (ctError & agError1,ctError & agError2)
 { return (agError1.number()==agError2.number()); }
}

namespace private_area {}

// E r r o r  Inline //-----------------------------------------------------------------------------
namespace public_area {
 //---------------------------------------------------------------------------------Copy Constructor
 /*METHOD clError */ /* Builds an error from another one. */
 inline clError::clError(ctError & agError)
 : atMessage(agError.atMessage), atNumber(agError.atNumber), atModule(agError.atModule),
   atMethod(agError.atMethod), atFile(agError.atFile), atLine(agError.atLine) {}
 //------------------------------------------------------------------------------Default Constructor
 /*METHOD clError */ /* Builds a default error. */
 inline clError::clError(void)
 : atMessage(), atNumber(), atModule(), atMethod(), atFile(), atLine(0) {}
}

// End //-------------------------------------------------------------------------------------------
}
#undef dll_export
#undef public_area
#undef private_area
#endif
 
//==================================================================================================
// S t a n d a r d                                                                   Implementation
// E r r o r
//                                                                                By Bruno Bachelet
//==================================================================================================
// Copyright (c) 1999-2016
// Bruno Bachelet - bruno@nawouak.net - http://www.nawouak.net
//
// This file is part of the B++ Library. This library is free software; you can redistribute it
// and/or modify it under the terms of the GNU Library General Public License as published by the
// Free Software Foundation; either version 2 of the License, or (at your option) any later
// version.
//
// 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 Library General Public License for more details (http://www.gnu.org).

// File Name //-------------------------------------------------------------------------------------
#line __LINE__ "standard/error.cpp"

// DLL Belonging //---------------------------------------------------------------------------------
#define STANDARD_DLL

// Headers //---------------------------------------------------------------------------------------
#include <bpp/file_name.hpp> /*NEED*/
#include <bpp/standard/class.hpp> /*NEED*/
#include <bpp/standard/error.hpp> /*INTERFACE*/

namespace bpp {

// Namespaces //------------------------------------------------------------------------------------
#define public_area  standardError
#define private_area standardError_private
#define dll_export   DLL_EXPORT

namespace public_area  {}
namespace private_area { using namespace standardBasicString; }

static_module_name("Standard/Error");

// Initialization //--------------------------------------------------------------------------------
#undef iniStandardError
static_constant(private_area::clInitializer,goInitializer);

// Errors //----------------------------------------------------------------------------------------
namespace public_area {
 static_error erInvalidErrorNumber;
 static_error erNone;
 static_error erUnexpected;

 static_error erDataLocationParameterMissing;
 static_error erTemporaryLocationParameterMissing;

 testing_mode ( static_error erTestingLocationParameterMissing; )

 static_error erCreateThread;
 static_error erMutexNotAvailable;
 static_error erMutexUnlocked;
}

// Constants & Variables //-------------------------------------------------------------------------
dynamic_constant(clErrorS,goErrorS);
static_constant(tyBoolean,goErrorThrown);
dynamic_constant(ctError,goCurrentError);
static_constant(clMutex,goErrorMutex);

event_spy_mode (
 dynamic_constant(clEventKindS,goEventKindS);
 dynamic_constant(clStringS,goMethodS);
 dynamic_constant(clStringS,goModuleS);
 static_constant(clMutex,goSpyMutex);

 static_constant(tcString,goEventTraceFileName);
 static_constant(tyCardinal,goTraceSize);
)

// Static Members //--------------------------------------------------------------------------------
namespace public_area  {}
namespace private_area {}

// Functions Implementation //----------------------------------------------------------------------
namespace public_area  {
 //-----------------------------------------------------------------------------------------OutError
 /*FUNCTION*/ /* Displays information about an error. */
 function void outError(ctError & agError) {
  using namespace environment;

  environment_private::clOutFile lcFout;

  nextLine();
  inform("-=-=- E R R O R -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-");
  out(" The following error has occurred:",true,true);
  out(" Number = ",false,true); out(agError.number(),true);
  out(" Message = ",false,true); out(agError.message(),true);
  out(" Module = ",false,true); out(agError.module(),true);
  out(" Method = ",false,true); out(agError.method(),true);
  out(" File = ",false,true); out(agError.file(),true);
  out(" Line = ",false,true); out(agError.line(),true);
  nextLine();
  out(" Flags = ",false,true);
  outFlags();
  nextLine();
  out(" Environment Variable = ",false,true); out(BPP_TOOLS_ENVIRONMENT_VARIABLE,true);
  out(" Random Seed = ",false,true); out(environment::randomSeed(),true);
  out(" Starting Date = ",false,true); out(environment::startingDate(),true);
  out(" Elapsed Hundredths = ",false,true); out(tyInteger(currentClock()-startingClock()),true);

  event_spy_mode (
   nextLine();
   out(" For more details, see the '",false,true); out(private_area::goEventTraceFileName);
   out("' file.",true);
  )

  out("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-",true,true);

  event_spy_mode (
   lcFout.open(private_area::goEventTraceFileName,ios::out|ios::trunc);
   lcFout << "===============================================================================" << end_line;
   lcFout << " E v e n t s   T r a c e                                 Debugging Information" << end_line;
   lcFout << "===============================================================================" << end_line;
   lcFout << end_line;
   outInformation(lcFout);
   lcFout << end_line;
   lcFout << "[>] Last Events Registered:" << end_line;
   lcFout << end_line;
   outTrace(lcFout);
   lcFout << end_line;
   outError(lcFout,agError);
   lcFout << end_line;
   lcFout << "===============================================================================" << end_line;
   lcFout.close();
  )
 }
 //-----------------------------------------------------------------------------------------OutError
 /*FUNCTION*/ /* Writes into a stream information about an error. */
 function void outError(private_area::clOutStream & agStream,ctError & agError) {
  using namespace environment;

  agStream << "[!] -=-=- E R R O R -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-" << end_line;
  agStream << "     The following error has occurred:" << end_line;
  agStream << "     Number = " << agError.number() << end_line;
  agStream << "     Message = " << agError.message() << end_line;
  agStream << "     Module = " << agError.module() << end_line;
  agStream << "     Method = " << agError.method() << end_line;
  agStream << "     File = " << agError.file() << end_line;
  agStream << "     Line = " << agError.line() << end_line;
  agStream << end_line;
  agStream << "     Flags = ";
  outFlags(agStream);
  agStream << end_line;
  agStream << "     Environment Variable = " << BPP_TOOLS_ENVIRONMENT_VARIABLE << end_line;
  agStream << "     Random Seed = " << randomSeed() << end_line;
  agStream << "     Starting Date = " << startingDate() << end_line;
  agStream << "     Elapsed Hundredths = " << tyInteger(currentClock()-startingClock()) << end_line;
  agStream << "    -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-" << end_line;
 }
 //-----------------------------------------------------------------------------------------OutError
 /*FUNCTION*/ /* Displays information about a non declared error. */
 function void outError(tcString agMessage) {
  using namespace environment;

  environment_private::clOutFile lcFout;

  nextLine();
  inform("-=-=- E R R O R -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-");
  out(" The following error has occurred:",true,true);
  out(" Message = ",false,true); out(agMessage,true);
  nextLine();
  out(" Flags = ",false,true);
  outFlags();
  nextLine();
  out(" Environment Variable = ",false,true); out(BPP_TOOLS_ENVIRONMENT_VARIABLE,true);
  out(" Random Seed = ",false,true); out(randomSeed(),true);
  out(" Starting Date = ",false,true); out(startingDate(),true);
  out(" Elapsed Hundredths = ",false,true); out(tyInteger(currentClock()-startingClock()),true);

  event_spy_mode (
   nextLine();
   out(" For more details, see the '",false,true); out(private_area::goEventTraceFileName);
   out("' file.",true);
  )

  out("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-",true,true);

  event_spy_mode (
   lcFout.open(private_area::goEventTraceFileName,ios::out|ios::trunc);
   lcFout << "===============================================================================" << end_line;
   lcFout << " E v e n t s   T r a c e                                 Debugging Information" << end_line;
   lcFout << "===============================================================================" << end_line;
   lcFout << end_line;
   outInformation(lcFout);
   lcFout << end_line;
   lcFout << "[>] Last Events Registered:" << end_line;
   lcFout << end_line;
   outTrace(lcFout);
   lcFout << end_line;
   outError(lcFout,agMessage);
   lcFout << end_line;
   lcFout << "===============================================================================" << end_line;
   lcFout.close();
  )
 }
 //-----------------------------------------------------------------------------------------OutError
 /*FUNCTION*/ /* Writes into a stream information about a non declared error. */
 function void outError(private_area::clOutStream & agStream,tcString agMessage) {
  using namespace environment;

  agStream << "[!] -=-=- E R R O R -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-" << end_line;
  agStream << "     The following error has occurred:" << end_line;
  agStream << "     Message = " << agMessage << end_line;
  agStream << end_line;
  agStream << "     Flags = ";
  outFlags(agStream);
  agStream << end_line;
  agStream << "     Environment Variable = " << BPP_TOOLS_ENVIRONMENT_VARIABLE << end_line;
  agStream << "     Random Seed = " << randomSeed() << end_line;
  agStream << "     Starting Date = " << startingDate() << end_line;
  agStream << "     Elapsed Hundredths = " << (tyInteger(currentClock()-startingClock())) << end_line;
  agStream << "    -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-" << end_line;
 }
 //-------------------------------------------------------------------------------------OutException
 /*FUNCTION*/ /* Displays information about an STL exception. */
 function void outException(ctException & agException) {
  using namespace environment;

  environment_private::clOutFile lcFout;

  nextLine();
  inform("-=-=- S T L   E R R O R -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-");
  out(" The following error has occurred:",true,true);
  out(" Message = ",false,true); out(agException.what(),true);
  nextLine();
  out(" Flags = ",false,true);
  outFlags();
  nextLine();
  out(" Environment Variable = ",false,true); out(BPP_TOOLS_ENVIRONMENT_VARIABLE,true);
  out(" Random Seed = ",false,true); out(randomSeed(),true);
  out(" Starting Date = ",false,true); out(startingDate(),true);
  out(" Elapsed Hundredths = ",false,true); out(tyInteger(currentClock()-startingClock()),true);

  event_spy_mode (
   nextLine();
   out(" For more details, see the '",false,true); out(private_area::goEventTraceFileName);
   out("' file.",true);
  )

  out("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-",true,true);

  event_spy_mode (
   lcFout.open(private_area::goEventTraceFileName,ios::out|ios::trunc);
   lcFout << "===============================================================================" << end_line;
   lcFout << " E v e n t s   T r a c e                                 Debugging Information" << end_line;
   lcFout << "===============================================================================" << end_line;
   lcFout << end_line;
   outInformation(lcFout);
   lcFout << end_line;
   lcFout << "[>] Last Events Registered:" << end_line;
   lcFout << end_line;
   outTrace(lcFout);
   lcFout << end_line;
   outException(lcFout,agException);
   lcFout << end_line;
   lcFout << "===============================================================================" << end_line;
   lcFout.close();
  )
 }
 //-------------------------------------------------------------------------------------OutException
 /*FUNCTION*/ /* Writes into a stream information about an STL exception. */
 function void outException(private_area::clOutStream & agStream,ctException & agException) {
  using namespace environment;

  agStream << "[!] -=-=- S T L   E R R O R -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-" << end_line;
  agStream << "     The following error has occurred:" << end_line;
  agStream << "     Message = " << agException.what() << end_line;
  agStream << end_line;
  agStream << "     Flags = ";
  outFlags(agStream);
  agStream << end_line;
  agStream << "     Environment Variable = " << BPP_TOOLS_ENVIRONMENT_VARIABLE << end_line;
  agStream << "     Random Seed = " << randomSeed() << end_line;
  agStream << "     Starting Date = " << startingDate() << end_line;
  agStream << "     Elapsed Hundredths = " << (tyInteger(currentClock()-startingClock())) << end_line;
  agStream << "    -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-" << end_line;
 }
 //-------------------------------------------------------------------------------OutUnexpectedError
 /*FUNCTION*/ /* Displays the context of the program when an unexpected error occurs. */
 function void outUnexpectedError(void) {
  using namespace environment;

  environment_private::clOutFile lcFout;

  nextLine();
  inform("-=-=- E R R O R -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-");
  out(" An unexpected error has occurred.",true,true);
  nextLine();
  out(" Flags = ",false,true);
  outFlags();
  nextLine();
  out(" Environment Variable = ",false,true); out(BPP_TOOLS_ENVIRONMENT_VARIABLE,true);
  out(" Random Seed = ",false,true); out(randomSeed(),true);
  out(" Starting Date = ",false,true); out(startingDate(),true);
  out(" Elapsed Hundredths = ",false,true); out(tyInteger(currentClock()-startingClock()),true);

  event_spy_mode (
   nextLine();
   out(" For more details, see the '",false,true); out(private_area::goEventTraceFileName);
   out("' file.",true);
  )

  out("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-",true,true);

  event_spy_mode (
   lcFout.open(private_area::goEventTraceFileName,ios::out|ios::trunc);
   lcFout << "===============================================================================" << end_line;
   lcFout << " E v e n t s   T r a c e                                 Debugging Information" << end_line;
   lcFout << "===============================================================================" << end_line;
   lcFout << end_line;
   outInformation(lcFout);
   lcFout << end_line;
   lcFout << "[>] Last Events Registered:" << end_line;
   lcFout << end_line;
   outTrace(lcFout);
   lcFout << end_line;
   outUnexpectedError(lcFout);
   lcFout << end_line;
   lcFout << "===============================================================================" << end_line;
   lcFout.close();
  )
 }
 //------------------------------------------------------------------------------OutUnexepectedError
 /*FUNCTION*/
 /* Writes into a stream the context of the program when an unexpected error occurs. */
 function void outUnexpectedError(private_area::clOutStream & agStream) {
  using namespace environment;

  agStream << "[!] -=-=- E R R O R -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-" << end_line;
  agStream << "     An unexpected error has occurred." << end_line;
  agStream << end_line;
  agStream << "     Flags = ";
  outFlags(agStream);
  agStream << end_line;
  agStream << "     Environment Variable = " << BPP_TOOLS_ENVIRONMENT_VARIABLE << end_line;
  agStream << "     Random Seed = " << randomSeed() << end_line;
  agStream << "     Starting Date = " << startingDate() << end_line;
  agStream << "     Elapsed Hundredths = " << (tyInteger(currentClock()-startingClock())) << end_line;
  agStream << "    -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-" << end_line;
 }
 //-----------------------------------------------------------------------------------------OutTrace
 event_spy_mode (
  /*FUNCTION*/ /* Writes into a stream the trace of the method and function calls. */
  function void outTrace(private_area::clOutStream & agStream) {
   using namespace private_area;

   safe_yes ( private_area::goSpyMutex.lock(); )

   clString lcBlankSpace("");

   tyCardinal lcCounter = goEventKindS->size();

   if (goEventKindS->size()==0) agStream << "    None" << end_line;

   while (lcCounter>0) {
    lcCounter--;

    if ((*goEventKindS)[lcCounter]==start) {
     agStream << "    Event: " << lcBlankSpace << "=> " << (*goModuleS)[lcCounter] << " - ";
     agStream << (*goMethodS)[lcCounter] << end_line;
     lcBlankSpace+="   ";
    }
    else {
     if (lcBlankSpace.size()>2) lcBlankSpace.resize(lcBlankSpace.size()-3);
     agStream << "    Event: " << lcBlankSpace << "<= " << (*goModuleS)[lcCounter] << " - ";
     agStream << (*goMethodS)[lcCounter] << end_line;
    }
   }

   safe_yes ( private_area::goSpyMutex.release(); )
  }
 )
 //---------------------------------------------------------------------------------------ClearError
 /*FUNCTION*/ /* Clears any pending error that is currently being thrown. */
 function void clearError(void) {
  safe_yes ( private_area::goErrorMutex.lock(); )
  private_area::goErrorThrown=false;
  private_area::goCurrentError=&erNone;
  safe_yes ( private_area::goErrorMutex.release(); )
 }
 //---------------------------------------------------------------------------------------ThrowError
 /*FUNCTION*/ /* Throws an error. */
 function void throwError(ctError & agError) {
  safe_yes ( private_area::goErrorMutex.lock(); )

  if (private_area::goErrorThrown) {
   private_area::outError(standardError::currentError());
   private_area::outError(agError);
   safe_yes ( private_area::goErrorMutex.release(); )
   environment::terminate();
  }
  else {
   private_area::goErrorThrown=true;
   private_area::goCurrentError=&agError;
   safe_yes ( private_area::goErrorMutex.release(); )
   throw agError;
  }
 }
}

namespace private_area {
 //----------------------------------------------------------------------------SendCreateThreadError
 function void sendCreateThreadError(void) {
  erCreateThread.module()="Standard/Thread";
  erCreateThread.method()="createThread";
  erCreateThread.file()=__FILE__;
  erCreateThread.line()=__LINE__+1;
  throwError(erCreateThread);
 }
 //-----------------------------------------------------------------------SendMutexNotAvailableError
 function void sendMutexNotAvailableError(void) {
  erMutexUnlocked.module()="Standard/Thread";
  erMutexUnlocked.method()="mutex::lock/release/tryLock";
  erMutexUnlocked.file()=__FILE__;
  erMutexUnlocked.line()=__LINE__+1;
  throwError(erMutexNotAvailable);
 }
 //---------------------------------------------------------------------------SendMutexUnlockedError
 function void sendMutexUnlockedError(void) {
  erMutexUnlocked.module()="Standard/Thread";
  erMutexUnlocked.method()="mutex::release";
  erMutexUnlocked.file()=__FILE__;
  erMutexUnlocked.line()=__LINE__+1;
  throwError(erMutexUnlocked);
 }
}

// E r r o r Implementation //----------------------------------------------------------------------
namespace public_area {
 //-------------------------------------------------------------------------------------------Create
 /*METHOD clError */ /* Declares an error with a given message. */
 property void clError::create(tcString agMessage) {
  safe_yes ( private_area::goErrorMutex.lock(); )
  atMessage=agMessage;
  atNumber=private_area::goErrorS->size();
  atMethod="";
  atModule="";
  private_area::goErrorS->push_back(this);
  safe_yes ( private_area::goErrorMutex.release(); )
 }
}

// E v e n t S p y  Implementation //---------------------------------------------------------------
#ifdef EVENT_SPY_MODE
namespace private_area {
 //--------------------------------------------------------------------------------------Constructor
 property clEventSpy::clEventSpy(tcString agMethod,tcString agModule)
 : atMethod(agMethod), atModule(agModule) {
  safe_yes ( private_area::goSpyMutex.lock(); )
  goEventKindS->insert(goEventKindS->begin(),start);
  goMethodS->insert(goMethodS->begin(),agMethod);
  goModuleS->insert(goModuleS->begin(),agModule);

  if (goEventKindS->size()>goTraceSize) {
   goEventKindS->pop_back();
   goMethodS->pop_back();
   goModuleS->pop_back();
  }

  safe_yes ( private_area::goSpyMutex.release(); )
 }
 //---------------------------------------------------------------------------------------Destructor
 property clEventSpy::~clEventSpy(void) {
  safe_yes ( private_area::goSpyMutex.lock(); )
  goEventKindS->insert(goEventKindS->begin(),end);
  goMethodS->insert(goMethodS->begin(),atMethod);
  goModuleS->insert(goModuleS->begin(),atModule);

  if (goEventKindS->size()>goTraceSize) {
   goEventKindS->pop_back();
   goMethodS->pop_back();
   goModuleS->pop_back();
  }

  safe_yes ( private_area::goSpyMutex.release(); )
 }
}
#endif

// I n i t i a l i z e r  Implementation //---------------------------------------------------------
namespace private_area {
 //--------------------------------------------------------------------------------------------Start
 property void clInitializer::start(void) {
  if (atCounter++ == 0) {
   try {
    #include <bpp/modules.hpp> /*NEED*/
    registerStop(this);
    environment::informInitialization(goModuleName);

    event_spy_mode (
     goEventKindS = new clEventKindS;
     goMethodS    = new clStringS;
     goModuleS    = new clStringS;

     goEventTraceFileName = EVENT_TRACE_FILE;
     goTraceSize          = EVENT_TRACE_SIZE;
    )

    method_name("initializer::constructor");

    goErrorS       = new clErrorS;
    goErrorThrown  = false;
    goCurrentError = &erNone;

    erInvalidErrorNumber.create("Invalid error number.");
    erNone.create("No error.");
    erUnexpected.create("Unexpected error.");

    erDataLocationParameterMissing.create("The 'data_location' parameter is missing.");
    erTemporaryLocationParameterMissing.create("The 'temporary_location' parameter is missing.");

    if (environment::parameters().count(clString("data_location"))==0)
     send_error(erDataLocationParameterMissing);

    if (environment::parameters().count(clString("temporary_location"))==0)
     send_error(erTemporaryLocationParameterMissing);

    testing_mode (
     erTestingLocationParameterMissing.create("The 'testing_location' parameter is missing.");

     if (environment::parameters().count(clString("testing_location"))==0)
      send_error(erTestingLocationParameterMissing);
    )

    // Thread Module Initialization //
    standardClass_private::goDemangleMutex             = new standardThread::clMutex();
    standardThread_private::goDisplayMutex             = new standardThread::clMutex();
    standardThread_private::goMallocMutex              = new standardThread::clMutex();
    standardThread_private::sendCreateThreadError      = private_area::sendCreateThreadError;
    standardThread_private::sendMutexNotAvailableError = private_area::sendMutexNotAvailableError;
    standardThread_private::sendMutexUnlockedError     = private_area::sendMutexUnlockedError;

    erCreateThread.create("Can't create a new thread.");
    erMutexNotAvailable.create("The mutex facility is not available.");
    erMutexUnlocked.create("The mutex is unlocked.");
   }

   initializer_catch;
  }
 }
 //---------------------------------------------------------------------------------------------Stop
 property void clInitializer::stop(void) {
  environment::informTermination(goModuleName);

  delete goErrorS;

  event_spy_mode (
   delete goEventKindS;
   delete goMethodS;
   delete goModuleS;
  )
 }
}

// End //-------------------------------------------------------------------------------------------
}