//COTD (09/27/2001) submitted by Squint [flipcode@squint.clara.co.uk]

// ErrorStack.h

#ifndef ErrorStack_H
#define ErrorStack_H

////////////////////////////////////////////////////////////////
// Class header for ErrorStack
////////////////////////////////////////////////////////////////

#include <vector>
#include <string>
#include <stdarg.h>

class ErrorStack
{
    private:
        ErrorStack() {}                                 // Constructor
        virtual ~ErrorStack() {}                        // Destructor
        ErrorStack (const ErrorStack &);                // Singleton so no copy constructor
        ErrorStack & operator= (const ErrorStack &);    // Singleton so no assignment operator
    protected:
        std::vector <std::string> Stack;                // This stores the error messages
    public:
        static class ErrorStack * Instance () { static ErrorStack * TheInstance = 0; if(TheInstance) return TheInstance; else return (TheInstance = new class ErrorStack); }
        void Clear();                                   // This empties the stack
        void Push(const char * fmt, ...);               // This adds an error message to the stack
        void Push(const std::string & str);             // This adds an error message to the stack
        std::string Report();                           // This returns a formatted string of all errors in the stack
};

// These are shortcut functions for the above singleton:
extern void PushError(const char * fmt, ...);
extern void PushError(const std::string & str);

#endif // ErrorStack_H





// ErrorStack.cpp





///////////////////////////////////////////////////////////////////////////////
// Class body for ErrorStack
///////////////////////////////////////////////////////////////////////////////

#include "ErrorStack.h"

#include <stdio.h>

using namespace std;

///////////////////////////////////////////////////////////////////////////////
// Clear:
// Empties the error stack.
// Needs calling if you attempt to continue from an error, which may include
// anywhere you choose to completely ignore one.
///////////////////////////////////////////////////////////////////////////////
void ErrorStack::Clear()
{
    Stack.clear();
}

///////////////////////////////////////////////////////////////////////////////
// Push:
// Adds an error message to the stack.
///////////////////////////////////////////////////////////////////////////////
void ErrorStack::Push(const std::string & str)
{
    Stack.push_back(str);
}

///////////////////////////////////////////////////////////////////////////////
// Push:
// Adds an error message to the stack.
///////////////////////////////////////////////////////////////////////////////
void ErrorStack::Push(const char *fmt, ...)
{
    static char str[8192];
    
    va_list argptr;
    va_start(argptr, fmt);
    vsprintf(str, fmt, argptr);
    va_end(argptr);

    Stack.push_back(str);
}

///////////////////////////////////////////////////////////////////////////////
// Report:
// Returns the errors on the stack as a single formatted string.
///////////////////////////////////////////////////////////////////////////////
string ErrorStack::Report()
{
    string str;
    vector<string>::iterator s;
    
    if(Stack.size())
    {
        s = Stack.begin();
        str = *s++;
        while(s != Stack.end())
        {
            str = *s + " [" + str + "]";
            ++s;
        }
    }
    else
    {
        str = "No Error";
    }
    
    return(str);
}

///////////////////////////////////////////////////////////////////////////////
// The following functions are global, and exist to simplify the use of the
// error stack:
///////////////////////////////////////////////////////////////////////////////


///////////////////////////////////////////////////////////////////////////////
// PushError:
// Pushes a string onto the error stack.
///////////////////////////////////////////////////////////////////////////////
void PushError(const string & str)
{
    ErrorStack::Instance()->Push(str);    
}

///////////////////////////////////////////////////////////////////////////////
// PushError:
// Pushes a string, which can include formatting, onto the error stack.
///////////////////////////////////////////////////////////////////////////////
void PushError(const char *fmt, ...)
{
    static char str[8192];
    
    va_list argptr;
    va_start(argptr, fmt);
    vsprintf(str, fmt, argptr);
    va_end(argptr);

    ErrorStack::Instance()->Push(str);    
}





// Example code





#include <stdio.h>

#include "First.h"
#include "ErrorStack.h"

int main(int argc, char **argv)
{
    First first;
    
    if(!(first.DoSomething()))
    {
        PushError("Do something failed");
        printf("%s\n", ErrorStack::Instance()->Report().c_str());
        exit(0);
    }
    return(0);
}


#include "Second.h"

class First
{
    protected:
        Second second;
    public:
        bool DoSomething();
};


#include "First.h"
#include "ErrorStack.h"

bool First::DoSomething()
{
    if(second.DoSomethingElse())
    {
        return(true);
    }
    else
    {
        PushError("Failed to do something else");
        return(false);
    }
}


class Second
{
    public:
        bool DoSomethingElse();
};



#include "Second.h"
#include "ErrorStack.h"

bool Second::DoSomethingElse()
{
    // This always fails:
    PushError("This always fails");
    return(false);
}
