/*
 * SPDX-FileCopyrightText: 2004 Copyright contributors to the cppTango project
 *
 * SPDX-License-Identifier: LGPL-3.0-or-later
 */

#include <tango/server/Except.h>

#include <tango/internal/utils.h>

#include <tango/client/ApiExcept.h>
#include <tango/client/NamedDevFailedList.h>
#include <tango/common/defines.h>
#include <tango/server/DeviceImpl.h>

namespace Tango
{

char Except::mess[256];
omni_mutex Except::the_mutex;

void Except::print_exception(const CORBA::Exception &e)
{
    print_exception(e, std::cerr);
}

//+----------------------------------------------------------------------------
//
// method :         print_exception
//
// description :     This method prints the information embedded in
//            a Tango exception.
//
// in :            e : Reference to the exception object
//
//-----------------------------------------------------------------------------

void Except::print_exception(const CORBA::Exception &e, std::ostream &os)
{
    const CORBA::SystemException *se;

    //
    // For a CORBA::SystemException, use the OB function
    //

    if((se = dynamic_cast<const CORBA::SystemException *>(&e)) != nullptr)
    {
        Tango::Except::the_mutex.lock();
        os << print_CORBA_SystemException(se) << std::endl;
        Tango::Except::the_mutex.unlock();
    }

    //
    // If it is a CORBA::UserException
    //

    else if(dynamic_cast<const CORBA::UserException *>(&e) != nullptr)
    {
        const Tango::DevFailed *te;
        const Tango::NamedDevFailedList *mdf;

        //
        // Print the Tango::NamedDevFailedList exception contents
        //

        if((mdf = dynamic_cast<const Tango::NamedDevFailedList *>(&e)) != nullptr)
        {
            os << "Tango NamedDevFailedList exception" << std::endl;
            for(unsigned long i = 0; i < mdf->err_list.size(); i++)
            {
                os << "   Exception for object " << mdf->err_list[i].name << std::endl;
                os << "   Index of object in call (starting at 0) = " << mdf->err_list[i].idx_in_call << std::endl;
                for(unsigned long j = 0; j < mdf->err_list[i].err_stack.length(); j++)
                {
                    os << "       Severity = " << mdf->err_list[i].err_stack[j].severity << std::endl;
                    os << "       Error reason = " << mdf->err_list[i].err_stack[j].reason.in() << std::endl;
                    os << "       Desc : " << mdf->err_list[i].err_stack[j].desc.in() << std::endl;
                    os << "       Origin : " << mdf->err_list[i].err_stack[j].origin.in() << std::endl;
                }
            }
            os << "   Summary exception" << std::endl;
            for(unsigned long j = 0; j < mdf->errors.length(); j++)
            {
                os << "       Severity = " << mdf->errors[j].severity << std::endl;
                os << "       Error reason = " << mdf->errors[j].reason.in() << std::endl;
                os << "       Desc : " << mdf->errors[j].desc.in() << std::endl;
                os << "       Origin : " << mdf->errors[j].origin.in() << std::endl;
                os << std::endl;
            }
        }

        //
        // Print the Tango::DevFailed exception contents
        //

        else if((te = dynamic_cast<const Tango::DevFailed *>(&e)) != nullptr)
        {
            for(unsigned long i = 0; i < te->errors.length(); i++)
            {
                os << "Tango exception" << std::endl;
                os << "Severity = " << te->errors[i].severity << std::endl;
                os << "Error reason = " << te->errors[i].reason.in() << std::endl;
                os << "Desc : " << te->errors[i].desc.in() << std::endl;
                os << "Origin : " << te->errors[i].origin.in() << std::endl;
                os << std::endl;
            }
        }

        //
        // For an unknown CORBA::UserException
        //

        else
        {
            os << "Unknown CORBA user exception" << std::endl;
        }
    }

    //
    // For an unknown exception type
    //

    else
    {
        os << "Unknown exception type !!!!!!" << std::endl;
    }
}

//+----------------------------------------------------------------------------
//
// method :         print_CORBA_SystemException
//
// description :     This method prints the information embedded in
//            a CORBA system exception.
//
// in :            e : Pointer to the exception object
//
//-----------------------------------------------------------------------------

char *Except::print_CORBA_SystemException(const CORBA::SystemException *e)
{
    const CORBA::BAD_PARAM *bad;
    const CORBA::NO_MEMORY *mem;
    const CORBA::IMP_LIMIT *lim;
    const CORBA::COMM_FAILURE *comm;
    const CORBA::INV_OBJREF *inv;
    const CORBA::NO_PERMISSION *perm;
    const CORBA::INTERNAL *inter;
    const CORBA::MARSHAL *mar;
    const CORBA::INITIALIZE *ini;
    const CORBA::NO_IMPLEMENT *impl;
    const CORBA::BAD_TYPECODE *type;
    const CORBA::BAD_OPERATION *op;
    const CORBA::NO_RESOURCES *res;
    const CORBA::NO_RESPONSE *resp;
    const CORBA::BAD_INV_ORDER *inv_ord;
    const CORBA::TRANSIENT *tra;
    const CORBA::OBJ_ADAPTER *adap;
    const CORBA::OBJECT_NOT_EXIST *not_ex;
    const CORBA::INV_POLICY *pol;

    //
    // It seems that omniORB for Win32 is not compiled with the RTTI enabled
    // (/GR option). We can't use dynamic_casting here.
    // We are using CORBA _downcast() method !!!
    //

    if(CORBA::UNKNOWN::_downcast(e) != nullptr)
    {
        ::strcpy(mess, "UNKNOWN CORBA system exception");
    }
    else if((bad = CORBA::BAD_PARAM::_downcast(e)) != nullptr)
    {
        ::strcpy(mess, "BAD_PARAM CORBA system exception: ");
        const char *err_msg = bad->NP_minorString();
        if(err_msg == nullptr)
        {
            ::strcat(mess, "ORB has returned NULL pointer !");
        }
        else
        {
            ::strcat(mess, err_msg);
        }
    }
    else if((mem = CORBA::NO_MEMORY::_downcast(e)) != nullptr)
    {
        ::strcpy(mess, "NO_MEMORY CORBA system exception: ");
        const char *err_msg = mem->NP_minorString();
        if(err_msg == nullptr)
        {
            ::strcat(mess, "ORB has returned NULL pointer !");
        }
        else
        {
            ::strcat(mess, err_msg);
        }
    }
    else if((lim = CORBA::IMP_LIMIT::_downcast(e)) != nullptr)
    {
        ::strcpy(mess, "IMP_LIMIT CORBA system exception: ");
        const char *tmp = lim->NP_minorString();
        if(tmp == nullptr)
        {
            ::strcat(mess, "Unknown minor code: ");
            TangoSys_MemStream st;
            st << std::hex << lim->minor() << std::dec << std::ends;
            std::string s = st.str();
            ::strcat(mess, s.c_str());
        }
        else
        {
            ::strcat(mess, tmp);
        }
    }
    else if((comm = CORBA::COMM_FAILURE::_downcast(e)) != nullptr)
    {
        ::strcpy(mess, "COMM_FAILURE CORBA system exception: ");
        const char *tmp = comm->NP_minorString();
        if(tmp == nullptr)
        {
            ::strcat(mess, "Unknown minor code: ");
            TangoSys_MemStream st;
            st << std::hex << comm->minor() << std::dec << std::ends;

            std::string s = st.str();
            ::strcat(mess, s.c_str());
        }
        else
        {
            ::strcat(mess, tmp);
        }
    }
    else if((inv = CORBA::INV_OBJREF::_downcast(e)) != nullptr)
    {
        ::strcpy(mess, "INV_OBJREF CORBA system exception: ");
        const char *err_msg = inv->NP_minorString();
        if(err_msg == nullptr)
        {
            ::strcat(mess, "ORB has returned NULL pointer !");
        }
        else
        {
            ::strcat(mess, err_msg);
        }
    }
    else if((perm = CORBA::NO_PERMISSION::_downcast(e)) != nullptr)
    {
        ::strcpy(mess, "NO_PERMISSION CORBA system exception: ");
        const char *err_msg = perm->NP_minorString();
        if(err_msg == nullptr)
        {
            ::strcat(mess, "ORB has returned NULL pointer !");
        }
        else
        {
            ::strcat(mess, err_msg);
        }
    }
    else if((inter = CORBA::INTERNAL::_downcast(e)) != nullptr)
    {
        ::strcpy(mess, "INTERNAL CORBA system exception: ");
        const char *err_msg = inter->NP_minorString();
        if(err_msg == nullptr)
        {
            ::strcat(mess, "ORB has returned NULL pointer !");
        }
        else
        {
            ::strcat(mess, err_msg);
        }
    }
    else if((mar = CORBA::MARSHAL::_downcast(e)) != nullptr)
    {
        ::strcpy(mess, "MARSHAL CORBA system exception: ");
        const char *err_msg = mar->NP_minorString();
        if(err_msg == nullptr)
        {
            ::strcat(mess, "ORB has returned NULL pointer !");
        }
        else
        {
            ::strcat(mess, err_msg);
        }
    }
    else if((ini = CORBA::INITIALIZE::_downcast(e)) != nullptr)
    {
        ::strcpy(mess, "INITIALIZE CORBA system exception: ");
        const char *err_msg = ini->NP_minorString();
        if(err_msg == nullptr)
        {
            ::strcat(mess, "ORB has returned NULL pointer !");
        }
        else
        {
            ::strcat(mess, err_msg);
        }
    }
    else if((impl = CORBA::NO_IMPLEMENT::_downcast(e)) != nullptr)
    {
        ::strcpy(mess, "NO_IMPLEMENT CORBA system exception: ");
        const char *err_msg = impl->NP_minorString();
        if(err_msg == nullptr)
        {
            ::strcat(mess, "ORB has returned NULL pointer !");
        }
        else
        {
            ::strcat(mess, err_msg);
        }
    }
    else if((type = CORBA::BAD_TYPECODE::_downcast(e)) != nullptr)
    {
        ::strcpy(mess, "BAD_TYPECODE CORBA system exception: ");
        const char *err_msg = type->NP_minorString();
        if(err_msg == nullptr)
        {
            ::strcat(mess, "ORB has returned NULL pointer !");
        }
        else
        {
            ::strcat(mess, err_msg);
        }
    }
    else if((op = CORBA::BAD_OPERATION::_downcast(e)) != nullptr)
    {
        ::strcpy(mess, "BAD_OPERATION CORBA system exception: ");
        const char *err_msg = op->NP_minorString();
        if(err_msg == nullptr)
        {
            ::strcat(mess, "ORB has returned NULL pointer !");
        }
        else
        {
            ::strcat(mess, err_msg);
        }
    }
    else if((res = CORBA::NO_RESOURCES::_downcast(e)) != nullptr)
    {
        ::strcpy(mess, "NO_RESOURCES CORBA system exception: ");
        const char *err_msg = res->NP_minorString();
        if(err_msg == nullptr)
        {
            ::strcat(mess, "ORB has returned NULL pointer !");
        }
        else
        {
            ::strcat(mess, err_msg);
        }
    }
    else if((resp = CORBA::NO_RESPONSE::_downcast(e)) != nullptr)
    {
        ::strcpy(mess, "NO_RESPONSE CORBA system exception: ");
        const char *err_msg = resp->NP_minorString();
        if(err_msg == nullptr)
        {
            ::strcat(mess, "ORB has returned NULL pointer !");
        }
        else
        {
            ::strcat(mess, err_msg);
        }
    }
    else if((inv_ord = CORBA::BAD_INV_ORDER::_downcast(e)) != nullptr)
    {
        ::strcpy(mess, "BAD_INV_ORDER CORBA system exception: ");
        const char *err_msg = inv_ord->NP_minorString();
        if(err_msg == nullptr)
        {
            ::strcat(mess, "ORB has returned NULL pointer !");
        }
        else
        {
            ::strcat(mess, err_msg);
        }
    }
    else if((tra = CORBA::TRANSIENT::_downcast(e)) != nullptr)
    {
        ::strcpy(mess, "TRANSIENT CORBA system exception: ");
        const char *tmp = tra->NP_minorString();
        if(tmp == nullptr)
        {
            ::strcat(mess, "Unknown minor code: ");
            TangoSys_MemStream st;
            st << std::hex << tra->minor() << std::dec << std::ends;

            std::string s = st.str();
            ::strcat(mess, s.c_str());
        }
        else
        {
            ::strcat(mess, tmp);
        }
    }
    else if((adap = CORBA::OBJ_ADAPTER::_downcast(e)) != nullptr)
    {
        ::strcpy(mess, "OBJ_ADAPTER CORBA system exception: ");
        const char *err_msg = adap->NP_minorString();
        if(err_msg == nullptr)
        {
            ::strcat(mess, "ORB has returned NULL pointer !");
        }
        else
        {
            ::strcat(mess, err_msg);
        }
    }
    else if((not_ex = CORBA::OBJECT_NOT_EXIST::_downcast(e)) != nullptr)
    {
        ::strcpy(mess, "OBJECT_NOT_EXIST CORBA system exception: ");
        const char *err_msg = not_ex->NP_minorString();
        if(err_msg == nullptr)
        {
            ::strcat(mess, "ORB has returned NULL pointer !");
        }
        else
        {
            ::strcat(mess, err_msg);
        }
    }
    else if((pol = CORBA::INV_POLICY::_downcast(e)) != nullptr)
    {
        ::strcpy(mess, "INV_POLICY CORBA system exception: ");
        const char *err_msg = pol->NP_minorString();
        if(err_msg == nullptr)
        {
            ::strcat(mess, "ORB has returned NULL pointer !");
        }
        else
        {
            ::strcat(mess, err_msg);
        }
    }
    else
    {
        ::strcpy(mess, "CORBA unknown system exception !!!!!!!!");
    }

    return mess;
}

//+----------------------------------------------------------------------------
//
// method :         print_CORBA_SystemException_r
//
// description :     This method prints the information embedded in
//            a CORBA system exception. This is the reentrant version of
//          print_CORBA_SystemException method
//
// in :            e           : Pointer to the exception object
//              error_msg   : Pointer to an already allocated char * buffer
//              buffer_size : Size of error_msg buffer
//
//-----------------------------------------------------------------------------

char *Except::print_CORBA_SystemException_r(const CORBA::SystemException *e, char *error_msg)
{
    const CORBA::BAD_PARAM *bad;
    const CORBA::NO_MEMORY *mem;
    const CORBA::IMP_LIMIT *lim;
    const CORBA::COMM_FAILURE *comm;
    const CORBA::INV_OBJREF *inv;
    const CORBA::NO_PERMISSION *perm;
    const CORBA::INTERNAL *inter;
    const CORBA::MARSHAL *mar;
    const CORBA::INITIALIZE *ini;
    const CORBA::NO_IMPLEMENT *impl;
    const CORBA::BAD_TYPECODE *type;
    const CORBA::BAD_OPERATION *op;
    const CORBA::NO_RESOURCES *res;
    const CORBA::NO_RESPONSE *resp;
    const CORBA::BAD_INV_ORDER *inv_ord;
    const CORBA::TRANSIENT *tra;
    const CORBA::OBJ_ADAPTER *adap;
    const CORBA::OBJECT_NOT_EXIST *not_ex;
    const CORBA::INV_POLICY *pol;

    //
    // It seems that omniORB for Win32 is not compiled with the RTTI enabled
    // (/GR option). We can't use dynamic_casting here.
    // We are using CORBA _downcast() method !!!
    //

    if(CORBA::UNKNOWN::_downcast(e) != nullptr)
    {
        ::strcpy(error_msg, "UNKNOWN CORBA system exception");
    }
    else if((bad = CORBA::BAD_PARAM::_downcast(e)) != nullptr)
    {
        ::strcpy(error_msg, "BAD_PARAM CORBA system exception: ");
        const char *err_msg = bad->NP_minorString();
        if(err_msg == nullptr)
        {
            ::strcat(error_msg, "ORB has returned NULL pointer !");
        }
        else
        {
            ::strcat(error_msg, err_msg);
        }
    }
    else if((mem = CORBA::NO_MEMORY::_downcast(e)) != nullptr)
    {
        ::strcpy(error_msg, "NO_MEMORY CORBA system exception: ");
        const char *err_msg = mem->NP_minorString();
        if(err_msg == nullptr)
        {
            ::strcat(error_msg, "ORB has returned NULL pointer !");
        }
        else
        {
            ::strcat(error_msg, err_msg);
        }
    }
    else if((lim = CORBA::IMP_LIMIT::_downcast(e)) != nullptr)
    {
        ::strcpy(error_msg, "IMP_LIMIT CORBA system exception: ");
        const char *tmp = lim->NP_minorString();
        if(tmp == nullptr)
        {
            ::strcat(error_msg, "Unknown minor code: ");
            TangoSys_MemStream st;
            st << std::hex << lim->minor() << std::dec << std::ends;
            std::string s = st.str();
            ::strcat(error_msg, s.c_str());
        }
        else
        {
            ::strcat(error_msg, tmp);
        }
    }
    else if((comm = CORBA::COMM_FAILURE::_downcast(e)) != nullptr)
    {
        ::strcpy(error_msg, "COMM_FAILURE CORBA system exception: ");
        const char *tmp = comm->NP_minorString();
        if(tmp == nullptr)
        {
            ::strcat(error_msg, "Unknown minor code: ");
            TangoSys_MemStream st;
            st << std::hex << comm->minor() << std::dec << std::ends;

            std::string s = st.str();
            ::strcat(error_msg, s.c_str());
        }
        else
        {
            ::strcat(error_msg, tmp);
        }
    }
    else if((inv = CORBA::INV_OBJREF::_downcast(e)) != nullptr)
    {
        ::strcpy(error_msg, "INV_OBJREF CORBA system exception: ");
        const char *err_msg = inv->NP_minorString();
        if(err_msg == nullptr)
        {
            ::strcat(error_msg, "ORB has returned NULL pointer !");
        }
        else
        {
            ::strcat(error_msg, err_msg);
        }
    }
    else if((perm = CORBA::NO_PERMISSION::_downcast(e)) != nullptr)
    {
        ::strcpy(error_msg, "NO_PERMISSION CORBA system exception: ");
        const char *err_msg = perm->NP_minorString();
        if(err_msg == nullptr)
        {
            ::strcat(error_msg, "ORB has returned NULL pointer !");
        }
        else
        {
            ::strcat(error_msg, err_msg);
        }
    }
    else if((inter = CORBA::INTERNAL::_downcast(e)) != nullptr)
    {
        ::strcpy(error_msg, "INTERNAL CORBA system exception: ");
        const char *err_msg = inter->NP_minorString();
        if(err_msg == nullptr)
        {
            ::strcat(error_msg, "ORB has returned NULL pointer !");
        }
        else
        {
            ::strcat(error_msg, err_msg);
        }
    }
    else if((mar = CORBA::MARSHAL::_downcast(e)) != nullptr)
    {
        ::strcpy(error_msg, "MARSHAL CORBA system exception: ");
        const char *err_msg = mar->NP_minorString();
        if(err_msg == nullptr)
        {
            ::strcat(error_msg, "ORB has returned NULL pointer !");
        }
        else
        {
            ::strcat(error_msg, err_msg);
        }
    }
    else if((ini = CORBA::INITIALIZE::_downcast(e)) != nullptr)
    {
        ::strcpy(error_msg, "INITIALIZE CORBA system exception: ");
        const char *err_msg = ini->NP_minorString();
        if(err_msg == nullptr)
        {
            ::strcat(error_msg, "ORB has returned NULL pointer !");
        }
        else
        {
            ::strcat(error_msg, err_msg);
        }
    }
    else if((impl = CORBA::NO_IMPLEMENT::_downcast(e)) != nullptr)
    {
        ::strcpy(error_msg, "NO_IMPLEMENT CORBA system exception: ");
        const char *err_msg = impl->NP_minorString();
        if(err_msg == nullptr)
        {
            ::strcat(error_msg, "ORB has returned NULL pointer !");
        }
        else
        {
            ::strcat(error_msg, err_msg);
        }
    }
    else if((type = CORBA::BAD_TYPECODE::_downcast(e)) != nullptr)
    {
        ::strcpy(error_msg, "BAD_TYPECODE CORBA system exception: ");
        const char *err_msg = type->NP_minorString();
        if(err_msg == nullptr)
        {
            ::strcat(error_msg, "ORB has returned NULL pointer !");
        }
        else
        {
            ::strcat(error_msg, err_msg);
        }
    }
    else if((op = CORBA::BAD_OPERATION::_downcast(e)) != nullptr)
    {
        ::strcpy(error_msg, "BAD_OPERATION CORBA system exception: ");
        const char *err_msg = op->NP_minorString();
        if(err_msg == nullptr)
        {
            ::strcat(error_msg, "ORB has returned NULL pointer !");
        }
        else
        {
            ::strcat(error_msg, err_msg);
        }
    }
    else if((res = CORBA::NO_RESOURCES::_downcast(e)) != nullptr)
    {
        ::strcpy(error_msg, "NO_RESOURCES CORBA system exception: ");
        const char *err_msg = res->NP_minorString();
        if(err_msg == nullptr)
        {
            ::strcat(error_msg, "ORB has returned NULL pointer !");
        }
        else
        {
            ::strcat(error_msg, err_msg);
        }
    }
    else if((resp = CORBA::NO_RESPONSE::_downcast(e)) != nullptr)
    {
        ::strcpy(error_msg, "NO_RESPONSE CORBA system exception: ");
        const char *err_msg = resp->NP_minorString();
        if(err_msg == nullptr)
        {
            ::strcat(error_msg, "ORB has returned NULL pointer !");
        }
        else
        {
            ::strcat(error_msg, err_msg);
        }
    }
    else if((inv_ord = CORBA::BAD_INV_ORDER::_downcast(e)) != nullptr)
    {
        ::strcpy(error_msg, "BAD_INV_ORDER CORBA system exception: ");
        const char *err_msg = inv_ord->NP_minorString();
        if(err_msg == nullptr)
        {
            ::strcat(error_msg, "ORB has returned NULL pointer !");
        }
        else
        {
            ::strcat(error_msg, err_msg);
        }
    }
    else if((tra = CORBA::TRANSIENT::_downcast(e)) != nullptr)
    {
        ::strcpy(error_msg, "TRANSIENT CORBA system exception: ");
        const char *tmp = tra->NP_minorString();
        if(tmp == nullptr)
        {
            ::strcat(error_msg, "Unknown minor code: ");
            TangoSys_MemStream st;
            st << std::hex << tra->minor() << std::dec << std::ends;

            std::string s = st.str();
            ::strcat(error_msg, s.c_str());
        }
        else
        {
            ::strcat(error_msg, tmp);
        }
    }
    else if((adap = CORBA::OBJ_ADAPTER::_downcast(e)) != nullptr)
    {
        ::strcpy(error_msg, "OBJ_ADAPTER CORBA system exception: ");
        const char *err_msg = adap->NP_minorString();
        if(err_msg == nullptr)
        {
            ::strcat(error_msg, "ORB has returned NULL pointer !");
        }
        else
        {
            ::strcat(error_msg, err_msg);
        }
    }
    else if((not_ex = CORBA::OBJECT_NOT_EXIST::_downcast(e)) != nullptr)
    {
        ::strcpy(error_msg, "OBJECT_NOT_EXIST CORBA system exception: ");
        const char *err_msg = not_ex->NP_minorString();
        if(err_msg == nullptr)
        {
            ::strcat(error_msg, "ORB has returned NULL pointer !");
        }
        else
        {
            ::strcat(error_msg, err_msg);
        }
    }
    else if((pol = CORBA::INV_POLICY::_downcast(e)) != nullptr)
    {
        ::strcpy(error_msg, "INV_POLICY CORBA system exception: ");
        const char *err_msg = pol->NP_minorString();
        if(err_msg == nullptr)
        {
            ::strcat(error_msg, "ORB has returned NULL pointer !");
        }
        else
        {
            ::strcat(error_msg, err_msg);
        }
    }
    else
    {
        ::strcpy(error_msg, "CORBA unknown system exception !!!!!!!!");
    }

    return error_msg;
}

void Except::print_error_stack(const Tango::DevErrorList &e)
{
    print_error_stack(e, std::cerr);
}

//+----------------------------------------------------------------------------
//
// method :         print_error_stack
//
// description :     This method prints the a Tango error stack
//
// in :            e : Reference to the error stack
//
//-----------------------------------------------------------------------------
void Except::print_error_stack(const Tango::DevErrorList &e, std::ostream &os)
{
    for(unsigned long i = 0; i < e.length(); i++)
    {
        os << "Tango error stack" << std::endl;
        os << "Severity = " << e[i].severity << std::endl;
        os << "Error reason = " << e[i].reason.in() << std::endl;
        os << "Desc : " << e[i].desc.in() << std::endl;
        os << "Origin : " << e[i].origin.in() << std::endl;
        os << std::endl;
    }
}

//+----------------------------------------------------------------------------
//
// method :         throw_exception
//
// description :     These methods throws a Tango DevFailed exception from
//            a CORBA system exception.
//
// in :            e : Pointer to the exception object
//
//-----------------------------------------------------------------------------

void Except::throw_exception(const CORBA::SystemException &c_ex, const char *origin)
{
    Tango::DevErrorList errors(1);

    errors.length(1);
    errors[0].severity = Tango::ERR;
    errors[0].origin = Tango::string_dup(origin);
    errors[0].reason = Tango::string_dup(API_CorbaSysException);
    Tango::Except::the_mutex.lock();
    char *tmp = print_CORBA_SystemException(&c_ex);
    errors[0].desc = Tango::string_dup(tmp);
    Tango::Except::the_mutex.unlock();

    throw Tango::DevFailed(errors);
}

void Except::throw_exception(const CORBA::SystemException &c_ex, char *origin)
{
    Tango::DevErrorList errors(1);

    errors.length(1);
    errors[0].severity = Tango::ERR;
    errors[0].origin = Tango::string_dup(origin);
    delete[] origin;
    errors[0].reason = Tango::string_dup(API_CorbaSysException);
    Tango::Except::the_mutex.lock();
    char *tmp = print_CORBA_SystemException(&c_ex);
    errors[0].desc = Tango::string_dup(tmp);
    Tango::Except::the_mutex.unlock();

    throw Tango::DevFailed(errors);
}

void Except::throw_exception(const CORBA::SystemException &c_ex, const std::string &origin)
{
    Tango::DevErrorList errors(1);

    errors.length(1);
    errors[0].severity = Tango::ERR;
    errors[0].origin = Tango::string_dup(origin.c_str());
    errors[0].reason = Tango::string_dup(API_CorbaSysException);
    Tango::Except::the_mutex.lock();
    char *tmp = print_CORBA_SystemException(&c_ex);
    errors[0].desc = Tango::string_dup(tmp);
    Tango::Except::the_mutex.unlock();

    throw Tango::DevFailed(errors);
}

void Except::throw_named_exception(
    Tango::DeviceImpl *d, long ind, const char *reason, const char *desc, const char *origin, Tango::ErrSeverity sever)
{
    throw_named_exception(d->get_device_attr()->get_attr_by_ind(ind).get_name().c_str(), reason, desc, origin, sever);
}

void Except::throw_named_exception(Tango::DeviceImpl *d,
                                   std::vector<long> &ind_atts,
                                   const char *reason,
                                   const char *desc,
                                   const char *origin,
                                   Tango::ErrSeverity sever)
{
    std::vector<std::string> vs;

    std::vector<long>::iterator ite;
    for(ite = ind_atts.begin(); ite != ind_atts.end(); ++ite)
    {
        vs.push_back(d->get_device_attr()->get_attr_by_ind(*ite).get_name());
    }

    throw_named_exception(vs, reason, desc, origin, sever);
}

//+----------------------------------------------------------------------------
//
// method :         Compare two Tango DevFailed exceptions for equality
//
// description :     The two DevFailed exceptions are verified by comparing the
// reason, origin, description and severity of all exceptions in the error stack.
// The strings reason, origin and description are compared literally.
//
// in :            ex1 The first DevFailed exception
//             ex1 The first DevFailed exception
//
// return:     a boolean set to true if the two exceptions are equal
//-----------------------------------------------------------------------------

bool Except::compare_exception(Tango::DevFailed &ex1, Tango::DevFailed &ex2)
{
    // check the length of the exception stack

    unsigned long nb_err = ex1.errors.length();
    if(nb_err != ex2.errors.length())
    {
        return false;
    }

    // check all exceptions in the stack

    for(unsigned long i = 0; i < nb_err; i++)
    {
        // check the severity
        if(ex1.errors[i].severity != ex2.errors[i].severity)
        {
            return false;
        }

        // check the origin
        std::string org1 = ex1.errors[i].origin.in();
        std::string org2 = ex2.errors[i].origin.in();
        if(org1 != org2)
        {
            return false;
        }

        // check the reason
        std::string re1 = ex1.errors[i].reason.in();
        std::string re2 = ex2.errors[i].reason.in();
        if(re1 != re2)
        {
            return false;
        }

        // check the description
        std::string desc1 = ex1.errors[i].desc.in();
        std::string desc2 = ex2.errors[i].desc.in();
        if(desc1 != desc2)
        {
            return false;
        }
    }

    return true;
}

} // namespace Tango
