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

#include <tango/server/TemplCommand.h>

#include <new>

namespace Tango
{

//+-------------------------------------------------------------------------
//
// method :         TemplCommand class constructors
//
// description :     instance constructor
//
//--------------------------------------------------------------------------

TemplCommand::TemplCommand(const std::string &s, void (DeviceImpl::*f)(), Tango::DispLevel level) :
    Command(s, Tango::DEV_VOID, Tango::DEV_VOID, level),
    exe_ptr(f),
    ext(nullptr)
{
    allowed_ptr = nullptr;
}

TemplCommand::TemplCommand(const std::string &s,
                           void (DeviceImpl::*f)(),
                           bool (DeviceImpl::*a)(const CORBA::Any &),
                           Tango::DispLevel level) :
    Command(s, Tango::DEV_VOID, Tango::DEV_VOID, level),
    exe_ptr(f),
    ext(nullptr),
    allowed_ptr(a)
{
}

TemplCommand::TemplCommand(const std::string &s,
                           void (DeviceImpl::*f)(),
                           bool (DeviceImpl::*a)(const CORBA::Any &),
                           const std::string &in_desc,
                           const std::string &out_desc,
                           Tango::DispLevel level) :
    Command(s, Tango::DEV_VOID, Tango::DEV_VOID, in_desc, out_desc, level),
    exe_ptr(f),
    ext(nullptr),
    allowed_ptr(a)
{
}

TemplCommand::TemplCommand(const std::string &s,
                           void (DeviceImpl::*f)(),
                           const std::string &in_desc,
                           const std::string &out_desc,
                           Tango::DispLevel level) :
    Command(s, Tango::DEV_VOID, Tango::DEV_VOID, in_desc, out_desc, level),
    exe_ptr(f),
    ext(nullptr)
{
    allowed_ptr = nullptr;
}

TemplCommand::TemplCommand(const std::string &s, Tango::DispLevel level) :
    Command(s, Tango::DEV_VOID, Tango::DEV_VOID, level)
{
}

TemplCommand::TemplCommand(const std::string &s,
                           const std::string &in_desc,
                           const std::string &out_desc,
                           DispLevel level) :
    Command(s, Tango::DEV_VOID, Tango::DEV_VOID, in_desc, out_desc, level)
{
}

//+-------------------------------------------------------------------------
//
// method :         set_type
//
// description :     Set the Command class type data according to the type
//            of the object passed as parameters
//
// input : - data_type : reference to the type_info object of the parameter
//       - type : reference to the Command class type data
//
//--------------------------------------------------------------------------

void TemplCommand::set_type(const std::type_info &data_type, Tango::CmdArgType &type)
{
    if(data_type == typeid(void))
    {
        TANGO_LOG_DEBUG << "Command : " << name << ", Type is void" << std::endl;
        type = Tango::DEV_VOID;
    }
    else if(data_type == typeid(Tango::DevBoolean))
    {
        TANGO_LOG_DEBUG << "Command : " << name << ", Type is a boolean" << std::endl;
        type = Tango::DEV_BOOLEAN;
    }
    else if(data_type == typeid(Tango::DevShort))
    {
        TANGO_LOG_DEBUG << "Command : " << name << ", Type is a short" << std::endl;
        type = Tango::DEV_SHORT;
    }
    else if(data_type == typeid(Tango::DevLong))
    {
        TANGO_LOG_DEBUG << "Command : " << name << ", Type is a long" << std::endl;
        type = Tango::DEV_LONG;
    }
    else if(data_type == typeid(Tango::DevLong64))
    {
        TANGO_LOG_DEBUG << "Command : " << name << ", Type is a long64" << std::endl;
        type = Tango::DEV_LONG64;
    }
    else if(data_type == typeid(Tango::DevFloat))
    {
        TANGO_LOG_DEBUG << "Command : " << name << ", Type is a float" << std::endl;
        type = Tango::DEV_FLOAT;
    }
    else if(data_type == typeid(Tango::DevDouble))
    {
        TANGO_LOG_DEBUG << "Command : " << name << ", Type is a double" << std::endl;
        type = Tango::DEV_DOUBLE;
    }
    else if(data_type == typeid(Tango::DevUShort))
    {
        TANGO_LOG_DEBUG << "Command : " << name << ", Type is an unsigned short" << std::endl;
        type = Tango::DEV_USHORT;
    }
    else if(data_type == typeid(Tango::DevULong))
    {
        TANGO_LOG_DEBUG << "Command : " << name << ", Type is an unsigned long" << std::endl;
        type = Tango::DEV_ULONG;
    }
    else if(data_type == typeid(Tango::DevULong64))
    {
        TANGO_LOG_DEBUG << "Command : " << name << ", Type is an unsigned long64" << std::endl;
        type = Tango::DEV_ULONG64;
    }
    else if(data_type == typeid(Tango::DevString))
    {
        TANGO_LOG_DEBUG << "Command : " << name << ", Type is a string" << std::endl;
        type = Tango::DEV_STRING;
    }
    else if((data_type == typeid(Tango::DevVarCharArray)) || (data_type == typeid(const Tango::DevVarCharArray *)) ||
            (data_type == typeid(Tango::DevVarCharArray *)))
    {
        TANGO_LOG_DEBUG << "Command : " << name << ", Type is a char array" << std::endl;
        type = Tango::DEVVAR_CHARARRAY;
    }
    else if((data_type == typeid(Tango::DevVarShortArray)) || (data_type == typeid(const Tango::DevVarShortArray *)) ||
            (data_type == typeid(Tango::DevVarShortArray *)))
    {
        TANGO_LOG_DEBUG << "Command : " << name << ", Type is a short array" << std::endl;
        type = Tango::DEVVAR_SHORTARRAY;
    }
    else if((data_type == typeid(Tango::DevVarLongArray)) || (data_type == typeid(const Tango::DevVarLongArray *)) ||
            (data_type == typeid(Tango::DevVarLongArray *)))
    {
        TANGO_LOG_DEBUG << "Command : " << name << ", Type is a long array" << std::endl;
        type = Tango::DEVVAR_LONGARRAY;
    }
    else if((data_type == typeid(Tango::DevVarLong64Array)) ||
            (data_type == typeid(const Tango::DevVarLong64Array *)) ||
            (data_type == typeid(Tango::DevVarLong64Array *)))
    {
        TANGO_LOG_DEBUG << "Command : " << name << ", Type is a long64 array" << std::endl;
        type = Tango::DEVVAR_LONG64ARRAY;
    }
    else if((data_type == typeid(Tango::DevVarFloatArray)) || (data_type == typeid(const Tango::DevVarFloatArray *)) ||
            (data_type == typeid(Tango::DevVarFloatArray *)))
    {
        TANGO_LOG_DEBUG << "Command : " << name << ", Type is a float array" << std::endl;
        type = Tango::DEVVAR_FLOATARRAY;
    }
    else if((data_type == typeid(Tango::DevVarDoubleArray)) ||
            (data_type == typeid(const Tango::DevVarDoubleArray *)) ||
            (data_type == typeid(Tango::DevVarDoubleArray *)))
    {
        TANGO_LOG_DEBUG << "Command : " << name << ", Type is a double array" << std::endl;
        type = Tango::DEVVAR_DOUBLEARRAY;
    }
    else if((data_type == typeid(Tango::DevVarUShortArray)) ||
            (data_type == typeid(const Tango::DevVarUShortArray *)) ||
            (data_type == typeid(Tango::DevVarUShortArray *)))
    {
        TANGO_LOG_DEBUG << "Command : " << name << ", Type is a unsigned short array" << std::endl;
        type = Tango::DEVVAR_USHORTARRAY;
    }
    else if((data_type == typeid(Tango::DevVarULongArray)) || (data_type == typeid(const Tango::DevVarULongArray *)) ||
            (data_type == typeid(Tango::DevVarULongArray *)))
    {
        TANGO_LOG_DEBUG << "Command : " << name << ", Type is a unsigned long array" << std::endl;
        type = Tango::DEVVAR_ULONGARRAY;
    }
    else if((data_type == typeid(Tango::DevVarULong64Array)) ||
            (data_type == typeid(const Tango::DevVarULong64Array *)) ||
            (data_type == typeid(Tango::DevVarULong64Array *)))
    {
        TANGO_LOG_DEBUG << "Command : " << name << ", Type is a unsigned long64 array" << std::endl;
        type = Tango::DEVVAR_ULONG64ARRAY;
    }
    else if((data_type == typeid(Tango::DevVarStringArray)) ||
            (data_type == typeid(const Tango::DevVarStringArray *)) ||
            (data_type == typeid(Tango::DevVarStringArray *)))
    {
        TANGO_LOG_DEBUG << "Command : " << name << ", Type is a string array" << std::endl;
        type = Tango::DEVVAR_STRINGARRAY;
    }
    else if((data_type == typeid(Tango::DevVarLongStringArray)) ||
            (data_type == typeid(const Tango::DevVarLongStringArray *)) ||
            (data_type == typeid(Tango::DevVarLongStringArray *)))
    {
        TANGO_LOG_DEBUG << "Command : " << name << ", Type is a long + string array" << std::endl;
        type = Tango::DEVVAR_LONGSTRINGARRAY;
    }
    else if((data_type == typeid(Tango::DevVarDoubleStringArray)) ||
            (data_type == typeid(const Tango::DevVarDoubleStringArray *)) ||
            (data_type == typeid(Tango::DevVarDoubleStringArray *)))
    {
        TANGO_LOG_DEBUG << "Command : " << name << ", Type is a double + string array" << std::endl;
        type = Tango::DEVVAR_DOUBLESTRINGARRAY;
    }
    else if(data_type == typeid(Tango::DevState))
    {
        TANGO_LOG_DEBUG << "Command : " << name << ", Type is a DevState" << std::endl;
        type = Tango::DEV_STATE;
    }
    else
    {
        TANGO_LOG_DEBUG << "Command : " << name << ", Unknown type" << std::endl;
        TangoSys_OMemStream o;

        o << "Command " << name << " defined with an unsupported type" << std::ends;
        TANGO_THROW_EXCEPTION(API_CmdArgumentTypeNotSupported, o.str());
    }
}

//+-------------------------------------------------------------------------
//
// method :         is_allowed
//
// description :     Check if the command is allowed. If the pointer to
//            DeviceImpl class method "allowed_ptr" is null, the
//            default mode id used (command always executed).
//            Otherwise, the method is executed
//
// input : - dev_ptr : pointer to the device on which the command must be
//               executed
//       - in_any : Incoming command data
//
// This method returns a boolean set to true if the command is allowed
//
//--------------------------------------------------------------------------

bool TemplCommand::is_allowed(DeviceImpl *dev_ptr, const CORBA::Any &in_any)
{
    if(allowed_ptr == nullptr)
    {
        return true;
    }
    else
    {
        return ((dev_ptr->*allowed_ptr)(in_any));
    }
}

//+-------------------------------------------------------------------------
//
// method :         execute
//
// description :     Execute the method associated with the command
//            (stored in the exe_ptr data)
//
// input : - dev_ptr : pointer to the device on which the command must be
//               executed
//       - in_any : Incoming command data
//
// This method returns a pointer to an CORBA::Any object with the command outing
// data.
//
//--------------------------------------------------------------------------

CORBA::Any *TemplCommand::execute(DeviceImpl *dev_ptr, TANGO_UNUSED(const CORBA::Any &in_any))
{
    //
    // Execute the command associated method
    //

    (dev_ptr->*exe_ptr)();
    return insert();
}

} // namespace Tango
