//#		Filename:	SpatialException.cpp
//#
//#		Author:		John Doug Reynolds, P. Kunszt
//#
//#		Date:		Mar 1997
//#
//#		Copyright (C) 2000  Peter Z. Kunszt, Alex S. Szalay, Aniruddha R. Thakar
//#                     The Johns Hopkins University
//#
//#		Modification history:
//#
//#		Oct. 1998, P. Kunszt : remove Rogue Wave C-string dependency
//#                almost all the interface had to be rewritten.
//#				   Also, use some of the inheritance to avoid
//#				   code duplication. Introduced defaultstr[].
//#     Oct 18, 2001 : Dennis C. Dinge -- Replaced ValVec with std::vector
//#

#include <cstdio>
#include <cstdlib>
#include <string.h>
#include <SpatialException.h>

/* --- SpatialException methods ------------------------------------------------- */
const char *SpatialException::defaultstr[] = { "SDSS Science Archive",
                                               "generic exception",           // These specialized exceptions are
                                               "unimplemented functionality", // currently implemented. If no string
                                               "failed operation",            // is given, this is the standard
                                               "array bounds violation",      // message.
                                               "interface violation" };

#define CONTEXT       0 // indices of exceptions
#define GENERIC       1
#define UNIMPLEMENTED 2
#define FAILURE       3
#define BOUNDS        4
#define INTERFACE     5

SpatialException::~SpatialException() throw()
{
    if (str_ != nullptr)
        delete[] str_;
}

SpatialException::SpatialException(const char *cstr, int defIndex) throw()
{
    try
    {
        if (cstr)
        {
            str_ = new char[slen(cstr) + 1];
            strcpy(str_, cstr);
        }
        else
        {
            str_ = new char[50];
            sprintf(str_, "%s : %s", defaultstr[CONTEXT], defaultstr[defIndex]);
        }
    }
    catch (...)
    {
        delete[] str_;
    }
}

SpatialException::SpatialException(const char *context, const char *because, int defIndex) throw()
{
    try
    {
        const char *tmpc, *tmpb;
        tmpc = context ? context : defaultstr[CONTEXT];
        tmpb = because ? because : defaultstr[defIndex];
        str_ = new char[slen(tmpc) + slen(tmpb) + 50]; // allow extensions
        sprintf(str_, "%s : %s", tmpc, tmpb);
    }
    catch (...)
    {
        delete[] str_;
    }
}

SpatialException::SpatialException(const SpatialException &oldX) throw()
{
    try
    {
        if (oldX.str_)
        {
            str_ = new char[slen(oldX.str_) + 1];
            strcpy(str_, oldX.str_);
        }
    }
    catch (...)
    {
        delete[] str_;
    }
}

SpatialException &SpatialException::operator=(const SpatialException &oldX) throw()
{
    try
    {
        if (&oldX != this) // beware of self-assignment
        {
            if (oldX.str_)
            {
                str_ = new char[slen(oldX.str_) + 1];
                strcpy(str_, oldX.str_);
            }
        }
    }
    catch (...)
    {
        delete[] str_;
    }
    return *this;
}

const char *SpatialException::what() const throw()
{
    try
    {
        return str_;
    }
    catch (...)
    {
        return "";
    }
}

int SpatialException::slen(const char *str) const
{
    if (str)
        return strlen(str);
    return 0;
}

void SpatialException::clear()
{
    if (str_)
        delete[] str_;
}
/* --- SpatialUnimplemented methods --------------------------------------------- */

SpatialUnimplemented::SpatialUnimplemented(const char *cstr) throw() : SpatialException(cstr, UNIMPLEMENTED)
{
}

SpatialUnimplemented::SpatialUnimplemented(const char *context, const char *because) throw()
    : SpatialException(context, because, UNIMPLEMENTED)
{
}

SpatialUnimplemented::SpatialUnimplemented(const SpatialUnimplemented &oldX) throw() : SpatialException(oldX)
{
}

/* --- SpatialFailure methods --------------------------------------------------- */

SpatialFailure::SpatialFailure(const char *cstr) throw() : SpatialException(cstr, FAILURE)
{
}

SpatialFailure::SpatialFailure(const char *context, const char *because) throw()
    : SpatialException(context, because, FAILURE)
{
}

SpatialFailure::SpatialFailure(const char *context, const char *operation, const char *resource,
                               const char *because) throw()
{
    try
    {
        delete[] str_;
        if (!operation && !resource && !because)
        {
            if (!context)
                context = defaultstr[CONTEXT];
            because = "failed operation";
        }
        str_  = new char[slen(context) + slen(operation) + slen(resource) + slen(because) + 50];
        *str_ = '\0';
        if (!context)
            context = defaultstr[CONTEXT];
        sprintf(str_, "%s: ", context);
        if (operation)
        {
            sprintf(str_, "%s %s failed ", str_, operation);
        }
        if (resource)
        {
            if (operation)
                sprintf(str_, "%s on \"%s\"", str_, resource);
            else
                sprintf(str_, "%s trouble with \"%s\"", str_, resource);
        }
        if (because)
        {
            if (operation || resource)
                sprintf(str_, "%s because %s", str_, because);
            else
                sprintf(str_, "%s %s", str_, because);
        }
    }
    catch (...)
    {
        delete[] str_;
    }
}

SpatialFailure::SpatialFailure(const SpatialFailure &oldX) throw() : SpatialException(oldX)
{
}

/* --- SpatialBoundsError methods ----------------------------------------------- */

SpatialBoundsError::SpatialBoundsError(const char *cstr) throw() : SpatialException(cstr, BOUNDS)
{
}

SpatialBoundsError::SpatialBoundsError(const char *context, const char *array, int32 limit, int32 index) throw()
    : SpatialException(context, array, BOUNDS)
{
    try
    {
        if (limit != -1)
        {
            if (array)
                sprintf(str_, "%s[%d]", str_, index);
            else
                sprintf(str_, "%s array index %d ", str_, index);
            if (index > limit)
            {
                sprintf(str_, "%s over upper bound by %d", str_, index - limit);
            }
            else
            {
                sprintf(str_, "%s under lower bound by %d", str_, limit - index);
            }
        }
    }
    catch (...)
    {
        delete[] str_;
    }
}

SpatialBoundsError::SpatialBoundsError(const SpatialBoundsError &oldX) throw() : SpatialException(oldX)
{
}

/* --- SpatialInterfaceError methods -------------------------------------------- */

SpatialInterfaceError::SpatialInterfaceError(const char *cstr) throw() : SpatialException(cstr, INTERFACE)
{
}

SpatialInterfaceError::SpatialInterfaceError(const char *context, const char *because) throw()
    : SpatialException(context, because, INTERFACE)
{
}

SpatialInterfaceError::SpatialInterfaceError(const char *context, const char *argument, const char *because) throw()
{
    try
    {
        delete[] str_;
        str_  = new char[slen(context) + slen(argument) + slen(because) + 128];
        *str_ = '\0';
        if (!context)
            context = defaultstr[CONTEXT];
        sprintf(str_, "%s: ", context);
        if (argument && because)
        {
            sprintf(str_, "%s argument \"%s\" is invalid because %s ", str_, argument, because);
        }
        else if (argument && !because)
        {
            sprintf(str_, "%s invalid argument \"%s\" ", str_, argument);
        }
        else if (!argument)
        {
            if (because)
                sprintf(str_, "%s %s", str_, because);
            else
                sprintf(str_, "%s interface violation", str_);
        }
    }
    catch (...)
    {
        delete[] str_;
    }
}

SpatialInterfaceError::SpatialInterfaceError(const SpatialInterfaceError &oldX) throw() : SpatialException(oldX)
{
}
