/*
 * SPDX-FileCopyrightText: 2025 Copyright contributors to the cppTango project
 *
 * SPDX-License-Identifier: LGPL-3.0-or-later
 */
#ifndef TANGO_CLIENT_HELPERS_ATTRIBUTEHELPER_H
#define TANGO_CLIENT_HELPERS_ATTRIBUTEHELPER_H

#include <tango/client/helpers/HelperBase.h>

namespace Tango
{
//=============================================================================
// CLASS: AttributeHelper
//=============================================================================
class AttributeHelper : public virtual HelperBase
{
  public:
    //---------------------------------------------------------------------------
    //  AttributeHelper::AttributeHelper  (ctor)
    //  device_name : name of the target device
    //  client_device : reference to the client device (for logging purpose)
    //---------------------------------------------------------------------------
    AttributeHelper(const std::string &device_name, Tango::DeviceImpl *client_device = 0) :
        HelperBase(device_name, client_device)
    {
        da_out_.exceptions(Tango::DeviceAttribute::isempty_flag | Tango::DeviceAttribute::wrongtype_flag);
    }

    //---------------------------------------------------------------------------
    //  AttributeHelper::~AttributeHelper (dtor)
    //---------------------------------------------------------------------------
    virtual ~AttributeHelper()
    {
        //- noop dtor
    }

    //---------------------------------------------------------------------------
    //  AttributeHelper::get_device_attribute
    //---------------------------------------------------------------------------
    Tango::DeviceAttribute get_device_attribute()
    {
        return da_out_;
    }

    //---------------------------------------------------------------------------
    //  AttributeHelper::write_attribute
    //  writes the specified attribute
    //  attr_name : name of the TANGO attribute to be written
    //  attr_value : the attribute value
    //---------------------------------------------------------------------------
    //  template arg _VAL must be supported by DeviceAttribute::operator<<
    //---------------------------------------------------------------------------
    template <class _VAL>
    void internal_write_attribute(const std::string &attr_name, const _VAL &attr_value, std::string file, int line)
    {
        if(device_proxy_)
        {
            DeviceAttribute da;
            da.set_name(const_cast<std::string &>(attr_name));
            da << const_cast<_VAL &>(attr_value);
            _DEV_TRY_FILE_LINE(
                //- try
                (device_proxy_->write_attribute)(da),
                //- what do we tried
                std::string("write_attribute on ") + FULL_ATTR_NAME(attr_name),
                //- origin
                "AttributeHelper::write_attribute",
                file,
                line);
        }
    }

    //---------------------------------------------------------------------------
    //  AttributeHelper::read_attribute
    //  reads the specified attribute
    //  attr_name : the name of the TANGO attribute to be read
    //  attr_value : the attribute value
    //---------------------------------------------------------------------------
    //  template arg _VAL must be supported by DeviceAttribute::operator>>
    //---------------------------------------------------------------------------
    template <class _VAL>
    void internal_read_attribute(const std::string &attr_name, _VAL &attr_value, std::string file, int line)
    {
        if(device_proxy_)
        {
            _DEV_TRY_FILE_LINE(
                //- try
                da_out_ = (device_proxy_->read_attribute)(const_cast<std::string &>(attr_name)),
                //- what do we tried
                std::string("read_attribute on ") + FULL_ATTR_NAME(attr_name),
                //- origin
                "AttributeHelper::read_attribute",
                file,
                line);
            _DEV_TRY_FILE_LINE(
                //- try
                da_out_ >> attr_value,
                //- what do we tried
                std::string("DeviceAttribute::operator>> on data returned by ") + FULL_ATTR_NAME(attr_name),
                //- origin
                "AttributeHelper::read_attribute",
                file,
                line);
        }
    }

    //---------------------------------------------------------------------------
    //  AttributeHelper::read_attribute_w
    //  reads the specified attribute and get its write value
    //  attr_name : the name of the TANGO attribute to be read
    //  w_attr_value : the write attribute value
    //---------------------------------------------------------------------------
    //  template arg _VAL must be supported by DeviceAttribute::operator>>
    //---------------------------------------------------------------------------
    template <class _VAL>
    void internal_read_attribute_w(const std::string &attr_name, _VAL &w_attr_value, std::string file, int line)
    {
        if(device_proxy_)
        {
            _DEV_TRY_FILE_LINE(
                //- try
                da_out_ = (device_proxy_->read_attribute)(const_cast<std::string &>(attr_name)),
                //- what do we tried
                std::string("read_attribute on ") + FULL_ATTR_NAME(attr_name),
                //- origin
                "AttributeHelper::read_attribute_w",
                file,
                line);

            //===========================================================================
            //==
            //==    TEST BY FL
            //==
            //===========================================================================

            //- Switch on attribute type
            try
            {
                switch(da_out_.get_type())
                {
                case Tango::DEV_BOOLEAN:
                {
                    w_attr_value = da_out_.BooleanSeq[1];
                    break;
                }
                case Tango::DEV_SHORT:
                case Tango::DEV_ENUM:
                {
                    w_attr_value = da_out_.ShortSeq[1];
                    break;
                }
                case Tango::DEV_LONG:
                {
                    w_attr_value = da_out_.LongSeq[1];
                    break;
                }
                case Tango::DEV_FLOAT:
                {
                    w_attr_value = da_out_.FloatSeq[1];
                    break;
                }
                case Tango::DEV_DOUBLE:
                {
                    w_attr_value = da_out_.DoubleSeq[1];
                    break;
                }
                default:
                {
                    TANGO_THROW_EXCEPTION("TANGO_NON_SUPPORTED_FEATURE_ERROR", "This type is not supported");
                    break;
                }
                }
                // INFO_STREAM << "w_attr_value = " << w_attr_value << ENDLOG;
            }

            _HANDLE_DEV_EXCEPTION("get_type()", "AttributeHelper::read_attribute_w");

            //===========================================================================
            //==
            //==    END TEST BY FL
            //==
            //===========================================================================
        }
    }

  private:
    //- placed here as a workaround due to CORBA::any_var limitations
    Tango::DeviceAttribute da_out_;
};
} // namespace Tango
#endif
