//-----------------------------------------------------------------------------
//  NastDebug.cpp
//-----------------------------------------------------------------------------

#include "NastDebug.h"
#include "NastDumpContextFile.h"

#include <iostream.h>
#include <signal.h>
#include <stdlib.h>

//  nur fuer Unix
#ifndef _MSC_VER
#include <unistd.h>
#endif 

//----------------------------------------------------------------------------
// Meldungen in den error DumpContext schreiben und das Programm verlassen
//----------------------------------------------------------------------------
static CNastDebug NastDebug;
CNastDumpContext* CNastDebug::m_pNastDumpErrors   = new CNastDumpContextFile(cerr);
CNastDumpContext* CNastDebug::m_pNastDumpWarnings = new CNastDumpContextFile(cerr);
CNastDumpContext* CNastDebug::m_pNastDumpLogfile  = new CNastDumpContextFile(cout);

//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
void 
CNastDebug::dumpContextErrors( CNastDumpContext *pDC ) 
{ 
    m_pNastDumpErrors = pDC; 
};

void 
CNastDebug::dumpContextWarnings( CNastDumpContext *pDC ) 
{ 
    m_pNastDumpWarnings = pDC; 
};

void CNastDebug::dumpContextLogfile ( CNastDumpContext *pDC ) 
{ 
    m_pNastDumpLogfile  = pDC; 
};

CNastDumpContext& 
CNastDebug::dumpContextErrors()   
{ 
    return *m_pNastDumpErrors;   
}

CNastDumpContext& 
CNastDebug::dumpContextWarnings() 
{ 
    return *m_pNastDumpWarnings; 
}

CNastDumpContext& 
CNastDebug::dumpContextLogfile()  
{ 
    return *m_pNastDumpLogfile;  
}

CNastDebug::CNastDebug()
{
    //  vorerst nichts zu tun
}

CNastDebug::~CNastDebug()
{
    dumpContextErrors().flush();
    dumpContextWarnings().flush();
    dumpContextLogfile().flush();
    
    delete CNastDebug::m_pNastDumpErrors;
    delete CNastDebug::m_pNastDumpWarnings;
    delete CNastDebug::m_pNastDumpLogfile;

    CNastDebug::m_pNastDumpErrors   = NULL;
    CNastDebug::m_pNastDumpWarnings = NULL;
    CNastDebug::m_pNastDumpLogfile  = NULL;
}
//----------------------------------------------------------------------------
// Meldungen in den error DumpContext schreiben und das Programm verlassen
//----------------------------------------------------------------------------
void 
CNastDebug::fatalError(const char *szAssertion,
        	       const char *szFilename,
        	       int nLine,
        	       const char *szFunction,
        	       const char *szMessage)
{
    CNastDumpContext &dumpContext = CNastDebug::dumpContextErrors();
    dumpContext << NastConfigString();
    dumpContext << "\n";

    if( szAssertion )		// durch ein NAST_ASSERT... ausgeloest ?
    {
        dumpContext << "!!! NAST_ASSERT failed\n";
    }

    if( szFilename )		// Filename angegeben ?
        dumpContext << szFilename << ":";
    dumpContext << nLine << ":";

    if( szFunction )		// Funktionsname angegeben ?
        dumpContext << szFunction << "\n";

    if( szAssertion )		// Assertion als String angegeben ?
    {
        dumpContext << "\n";
        dumpContext << "'" << szAssertion << "'";
    }

    dumpContext << "\n\n";
    if( szMessage )		// Message angeben ?
        dumpContext << szMessage << "\n";

    dumpContext << "\n";
    dumpContext.flush();	// und auf jedem Fall rausschreiben
    
    fatalExit();		// und nichts wie raus
}


void 
CNastDebug::fatalExit()
{
    // abort erhaelt im Gegensatz zu exit den Stackframe
    // Wenn man das Programm mit einem Debugger laufen laesst,
    // dann kann man nach einem FatelExit() noch die lokalen Variablen
    // anschauen.
    // Bei gdb z.B. bt (Backtrace)

    //  IDEE vielleicht laesst sich hier sogar noch ein automatischer
    //  Start des Debuggers reinfummeln. Mit gdb muesst das
    //  funktionieren. Man kann gdb an einen laufenden Prozess
    //  anfuegen.

    //  Wenn es die Funktion abort() aus irgendwelchen Gruenden
    //  nicht geben sollte kann man stattdessen auch ein signal
    //  SIGABORT an den Prozess selbst schicken.

    // falls die Envirnmentvariable NAST_DEBUGGER gesetzt ist 
    // den Debugger starten

    // noch alles rausschreiben

    // so funktionierts leider nicht
    /*
    char *szProg = getenv("NAST_DEBUGGER");
    if( szProg )		// NAST_DEBUGGER gesetzt ?
    {
        char buffName[100]="";	// lang genug fuer den Programmnamen 
        char buffPID[100]="";	// lang genug fuer ProzessID
        sprintf("%s", "debug" );
        sprintf("%d", getpid());
        

        if( fork() == 0 ) // child ?
        {
            // Hmm, jetzt braeuchten wir den vollen Namen des Programm
            // mit Pfad.
            // 
            char *const argv[] = { szProg, buffName, buffPID, 0};
            execvp( szProg, argv );
        }
    }
    */

    abort();
}


