//+============================================================================
//
// file :               PollRing.cpp
//
// description :        C++ source code for the RingElt and PollRing
//            classes. These classes are used to implement the
//            tango polling ring buffer. There is one
//            polling ring for each Tango command or attribute
//            polled.
//
// project :            TANGO
//
// author(s) :          E.Taurel
//
// Copyright (C) :      2004,2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015
//                        European Synchrotron Radiation Facility
//                      BP 220, Grenoble 38043
//                      FRANCE
//
// This file is part of Tango.
//
// Tango is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Tango is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with Tango.  If not, see <http://www.gnu.org/licenses/>.
//
//
//-============================================================================

#include <tango/server/pollring.h>
#include <tango/server/pollring_templ.h>
#include <tango/server/logging.h>
#include <tango/server/except.h>
#include <tango/server/tango_config.h>
#include <tango/server/utils.h>
#include <tango/common/utils/assert.h>

#include <ostream>

#ifdef _TG_WINDOWS_
  #include <sys/types.h>
#endif /* _TG_WINDOWS_ */

namespace
{
//------------------------------------------------------------------------------------------------------------------
//
// method :
//        force_copy_data
//
// description :
//        Since IDL 4, attributes are transferred on the net using a IDL union. In some cases, the sequence within the
//        union simply points to the user data (no copy), therefore, this method force the user data to be copied
//        To do this copy we:
//                    1 - Really copy the data within a temporary sequence
//                    2 - Force memory freeing (if required by user) using the
//                        union sequence replace call
//                    3 - Transfer the data from the temporary sequence within the
//                        union sequence using again the sequence replace call
//                        in order not to trigger a real data copy
//
// argument :
//        in :
//            - attr_value : The attribute value
//
//------------------------------------------------------------------------------------------------------------------

template <typename T>
void force_copy_data(T *attr_value)
{
    for(unsigned long loop = 0; loop < attr_value->length(); loop++)
    {
        switch((*attr_value)[loop].value._d())
        {
        case Tango::ATT_BOOL:
        {
            Tango::DevVarBooleanArray &union_seq = (*attr_value)[loop].value.bool_att_value();
            Tango::DevVarBooleanArray tmp_seq(union_seq);
            union_seq.replace(0, 0, nullptr, true);
            unsigned long len = tmp_seq.length();
            union_seq.replace(len, len, tmp_seq.get_buffer(true), true);
        }
        break;

        case Tango::ATT_SHORT:
        {
            Tango::DevVarShortArray &union_seq = (*attr_value)[loop].value.short_att_value();
            Tango::DevVarShortArray tmp_seq(union_seq);
            union_seq.replace(0, 0, nullptr, true);
            unsigned long len = tmp_seq.length();
            union_seq.replace(len, len, tmp_seq.get_buffer(true), true);
        }
        break;

        case Tango::ATT_LONG:
        {
            Tango::DevVarLongArray &union_seq = (*attr_value)[loop].value.long_att_value();
            Tango::DevVarLongArray tmp_seq(union_seq);
            union_seq.replace(0, 0, nullptr, true);
            unsigned long len = tmp_seq.length();
            union_seq.replace(len, len, tmp_seq.get_buffer(true), true);
        }
        break;

        case Tango::ATT_LONG64:
        {
            Tango::DevVarLong64Array &union_seq = (*attr_value)[loop].value.long64_att_value();
            Tango::DevVarLong64Array tmp_seq(union_seq);
            union_seq.replace(0, 0, nullptr, true);
            unsigned long len = tmp_seq.length();
            union_seq.replace(len, len, tmp_seq.get_buffer(true), true);
        }
        break;

        case Tango::ATT_FLOAT:
        {
            Tango::DevVarFloatArray &union_seq = (*attr_value)[loop].value.float_att_value();
            Tango::DevVarFloatArray tmp_seq(union_seq);
            union_seq.replace(0, 0, nullptr, true);
            unsigned long len = tmp_seq.length();
            union_seq.replace(len, len, tmp_seq.get_buffer(true), true);
        }
        break;

        case Tango::ATT_DOUBLE:
        {
            Tango::DevVarDoubleArray &union_seq = (*attr_value)[loop].value.double_att_value();
            Tango::DevVarDoubleArray tmp_seq(union_seq);
            union_seq.replace(0, 0, nullptr, true);
            unsigned long len = tmp_seq.length();
            union_seq.replace(len, len, tmp_seq.get_buffer(true), true);
        }
        break;

        case Tango::ATT_UCHAR:
        {
            Tango::DevVarCharArray &union_seq = (*attr_value)[loop].value.uchar_att_value();
            Tango::DevVarCharArray tmp_seq(union_seq);
            union_seq.replace(0, 0, nullptr, true);
            unsigned long len = tmp_seq.length();
            union_seq.replace(len, len, tmp_seq.get_buffer(true), true);
        }
        break;

        case Tango::ATT_USHORT:
        {
            Tango::DevVarUShortArray &union_seq = (*attr_value)[loop].value.ushort_att_value();
            Tango::DevVarUShortArray tmp_seq(union_seq);
            union_seq.replace(0, 0, nullptr, true);
            unsigned long len = tmp_seq.length();
            union_seq.replace(len, len, tmp_seq.get_buffer(true), true);
        }
        break;

        case Tango::ATT_ULONG:
        {
            Tango::DevVarULongArray &union_seq = (*attr_value)[loop].value.ulong_att_value();
            Tango::DevVarULongArray tmp_seq(union_seq);
            union_seq.replace(0, 0, nullptr, true);
            unsigned long len = tmp_seq.length();
            union_seq.replace(len, len, tmp_seq.get_buffer(true), true);
        }
        break;

        case Tango::ATT_ULONG64:
        {
            Tango::DevVarULong64Array &union_seq = (*attr_value)[loop].value.ulong64_att_value();
            Tango::DevVarULong64Array tmp_seq(union_seq);
            union_seq.replace(0, 0, nullptr, true);
            unsigned long len = tmp_seq.length();
            union_seq.replace(len, len, tmp_seq.get_buffer(true), true);
        }
        break;

        case Tango::ATT_STRING:
        {
            const Tango::DevVarStringArray &union_seq = (*attr_value)[loop].value.string_att_value();
            Tango::DevVarStringArray tmp_seq = union_seq;
            (const_cast<Tango::DevVarStringArray &>(union_seq)).replace(0, 0, nullptr, true);
            (*attr_value)[loop].value.string_att_value(tmp_seq);
        }
        break;

        case Tango::ATT_STATE:
        {
            Tango::DevVarStateArray &union_seq = (*attr_value)[loop].value.state_att_value();
            Tango::DevVarStateArray tmp_seq(union_seq);
            union_seq.replace(0, 0, nullptr, true);
            unsigned long len = tmp_seq.length();
            union_seq.replace(len, len, tmp_seq.get_buffer(true), true);
        }
        break;

        case Tango::DEVICE_STATE:
        case Tango::ATT_NO_DATA:
            break;

        case Tango::ATT_ENCODED:
        {
            Tango::DevVarEncodedArray &union_seq = (*attr_value)[loop].value.encoded_att_value();
            Tango::DevVarEncodedArray tmp_seq(union_seq);
            union_seq.replace(0, 0, nullptr, true);

            union_seq.length(tmp_seq.length());

            union_seq[0].encoded_format = Tango::string_dup(tmp_seq[0].encoded_format);
            unsigned long nb_data = tmp_seq[0].encoded_data.length();
            union_seq[0].encoded_data.replace(nb_data, nb_data, tmp_seq[0].encoded_data.get_buffer(true), true);

            if(tmp_seq.length() == 2)
            {
                union_seq[1].encoded_format = Tango::string_dup(tmp_seq[1].encoded_format);
                unsigned long nb_data = tmp_seq[1].encoded_data.length();
                union_seq[1].encoded_data.replace(nb_data, nb_data, tmp_seq[1].encoded_data.get_buffer(true), true);
            }
        }
        break;
        }
    }
}
} // namespace

namespace Tango
{

//+-------------------------------------------------------------------------
//
// method :         RingElt::RingElt
//
// description :     Constructor for the RingElt class.
//            This constructor simply set the internal value to their
//            default
//
//--------------------------------------------------------------------------

RingElt::RingElt()
{
    when = {};
    cmd_result = nullptr;
    attr_value = nullptr;
    attr_value_3 = nullptr;
    attr_value_4 = nullptr;
    attr_value_5 = nullptr;
    except = nullptr;
}

//+-------------------------------------------------------------------------
//
// method :         PollRing::PollRing
//
// description :     Two constructors for the PollRing class. The first one
//            does not take any argument and construct a black box
//            with the default depth.
//            The second one create a black box with a depth defined
//            by the argument.
//
// argument : in :     - max_size : The black box depth
//
//--------------------------------------------------------------------------

PollRing::PollRing() :
    ring(DefaultPollRingDepth)
{
    insert_elt = 0;
    nb_elt = 0;
    max_elt = DefaultPollRingDepth;
}

PollRing::PollRing(long max_size) :
    ring(max_size)
{
    insert_elt = 0;
    nb_elt = 0;
    max_elt = max_size;
}

//+-------------------------------------------------------------------------
//
// method :         PollRing::~PollRing
//
// description :     The class destructor. It frees all the memory allocated
//            to store command/attribute result
//
//--------------------------------------------------------------------------

PollRing::~PollRing()
{
    TANGO_LOG_DEBUG << "In PollRing destructor" << std::endl;

    long nb = ring.size();

    for(long i = 0; i < nb; i++)
    {
        delete ring[i].cmd_result;
        delete ring[i].except;
        delete ring[i].attr_value;
        delete ring[i].attr_value_3;
        delete ring[i].attr_value_4;
        delete ring[i].attr_value_5;
    }
}

//+-------------------------------------------------------------------------
//
// method :         PollRing::insert_data
//
// description :     These methods insert a new element in the ring buffer
//            when its real data
//
// argument : in :     - any_ptr : The Any returned by the command
//            - t : The date
//
//--------------------------------------------------------------------------

void PollRing::insert_data(CORBA::Any *any_ptr, PollClock::time_point t)
{
    //
    // Insert data in the ring
    //

    delete(ring[insert_elt].cmd_result);
    delete(ring[insert_elt].except);
    ring[insert_elt].except = nullptr;

    ring[insert_elt].cmd_result = any_ptr;
    ring[insert_elt].when = t;

    //
    // Manage insert and read indexes
    //

    inc_indexes();
}

void PollRing::insert_data(Tango::AttributeValueList *attr_val, PollClock::time_point t)
{
    //
    // Insert data in the ring
    //

    delete(ring[insert_elt].attr_value);
    delete(ring[insert_elt].except);
    ring[insert_elt].except = nullptr;

    ring[insert_elt].attr_value = attr_val;
    ring[insert_elt].when = t;

    //
    // Manage insert and read indexes
    //

    inc_indexes();
}

void PollRing::insert_data(Tango::AttributeValueList_3 *attr_val, PollClock::time_point t)
{
    //
    // Insert data in the ring
    //

    delete(ring[insert_elt].attr_value_3);
    delete(ring[insert_elt].except);
    ring[insert_elt].except = nullptr;

    ring[insert_elt].attr_value_3 = attr_val;
    ring[insert_elt].when = t;

    //
    // Manage insert and read indexes
    //

    inc_indexes();
}

void PollRing::insert_data(Tango::AttributeValueList_4 *attr_val, PollClock::time_point t, bool unlock)
{
    //
    // Insert data in the ring
    //

    delete(ring[insert_elt].attr_value_4);
    delete(ring[insert_elt].except);
    ring[insert_elt].except = nullptr;

    ring[insert_elt].attr_value_4 = attr_val;
    ring[insert_elt].when = t;

    force_copy_data(ring[insert_elt].attr_value_4);

    //
    // Release attribute mutexes because the data are now copied
    //

    if(unlock)
    {
        for(unsigned int loop = 0; loop < attr_val->length(); loop++)
        {
            Tango::AttributeValue_4 *tmp_ptr = &((*attr_val)[loop]);
            (tmp_ptr)->rel_attr_mutex();
        }
    }

    //
    // Manage insert and read indexes
    //

    inc_indexes();
}

void PollRing::insert_data(Tango::AttributeValueList_5 *attr_val, PollClock::time_point t, bool unlock)
{
    //
    // Insert data in the ring
    //

    delete(ring[insert_elt].attr_value_5);
    delete(ring[insert_elt].except);
    ring[insert_elt].except = nullptr;

    ring[insert_elt].attr_value_5 = attr_val;
    ring[insert_elt].when = t;

    force_copy_data(ring[insert_elt].attr_value_5);

    //
    // Release attribute mutexes because the data are now copied
    //

    if(unlock)
    {
        for(unsigned int loop = 0; loop < attr_val->length(); loop++)
        {
            Tango::AttributeValue_5 *tmp_ptr = &((*attr_val)[loop]);
            (tmp_ptr)->rel_attr_mutex();
        }
    }

    //
    // Manage insert and read indexes
    //

    inc_indexes();
}

//-------------------------------------------------------------------------
//
// method :         PollRing::insert_except
//
// description :     This method insert a new element in the ring buffer
//            when this element is an exception
//
// argument : in :     - ex : The exception to be stored
//            - t : The date
//
//--------------------------------------------------------------------------

void PollRing::insert_except(Tango::DevFailed *ex, PollClock::time_point t)
{
    //
    // Insert data in the ring
    //

    delete(ring[insert_elt].except);
    if(ring[insert_elt].attr_value != nullptr)
    {
        delete(ring[insert_elt].attr_value);
        ring[insert_elt].attr_value = nullptr;
    }
    if(ring[insert_elt].cmd_result != nullptr)
    {
        delete(ring[insert_elt].cmd_result);
        ring[insert_elt].cmd_result = nullptr;
    }

    ring[insert_elt].except = ex;
    ring[insert_elt].when = t;

    //
    // Manage insert and read indexes
    //

    inc_indexes();
}

//+-------------------------------------------------------------------------
//
// method :         PollRing::inc_indexes
//
// description :     This private method increment the indexes used to acces
//            the box itself. This is necessary because the box must
//            be managed as a circular buffer
//
//--------------------------------------------------------------------------

void PollRing::inc_indexes()
{
    insert_elt++;
    if(insert_elt == max_elt)
    {
        insert_elt = 0;
    }

    if(nb_elt != max_elt)
    {
        nb_elt++;
    }
}

//+-------------------------------------------------------------------------
//
// method :         PollRing::get_delta_t
//
// description :     This method computes the delta time between records
//            in the ring buffer
//
// argument :     in :    - nb : The number of delta t to be computed
//        out :    - res : A reference to the vector where result should
//                be stored
//
//--------------------------------------------------------------------------

std::vector<PollClock::duration> PollRing::get_delta_t(long nb)
{
    std::vector<PollClock::duration> res{};

    //
    // Throw exception if nothing in ring
    //

    if(nb_elt < 2)
    {
        TANGO_THROW_EXCEPTION(API_PollRingBufferEmpty, "Not enough data stored yet in polling ring buffer");
    }

    //
    // Get the buffer starting point
    //

    long read_index, prev_read;
    if(insert_elt == 0)
    {
        read_index = max_elt - 1;
        prev_read = read_index - 1;
    }
    else
    {
        read_index = insert_elt - 1;
        if(read_index == 0)
        {
            prev_read = max_elt - 1;
        }
        else
        {
            prev_read = read_index - 1;
        }
    }

    //
    // Compute how many delta can be computed
    //

    if(nb_elt <= nb)
    {
        nb = nb_elt - 1;
    }

    //
    // The delta t computing loop
    //

    long i;
    for(i = 0; i < nb; i++)
    {
        auto t_ref = ring[read_index].when;
        auto t_prev = ring[prev_read].when;

        res.push_back(t_ref - t_prev);
        prev_read--;
        if(prev_read < 0)
        {
            prev_read = max_elt - 1;
        }
        read_index--;
        if(read_index < 0)
        {
            read_index = max_elt - 1;
        }
    }

    return res;
}

//+-------------------------------------------------------------------------
//
// method :         PollRing::get_last_insert_date
//
// description :     This method returns the date of the last insert in the
//            ring buffer
//
//--------------------------------------------------------------------------

PollClock::time_point PollRing::get_last_insert_date()
{
    if(insert_elt == 0)
    {
        return ring[max_elt - 1].when;
    }
    else
    {
        return ring[insert_elt - 1].when;
    }
}

//+-------------------------------------------------------------------------
//
// method :         PollRing::is_last_an_error
//
// description :     This method returns a boolean set to true if the last
//            data recorded into the ring buffer was an exception
//
//--------------------------------------------------------------------------

bool PollRing::is_last_an_error()
{
    if(insert_elt == 0)
    {
        return ring[max_elt - 1].except != nullptr;
    }
    else
    {
        return ring[insert_elt - 1].except != nullptr;
    }
}

bool PollRing::is_last_cmd_an_error()
{
    if(insert_elt == 0)
    {
        return ring[max_elt - 1].except != nullptr;
    }
    else
    {
        return ring[insert_elt - 1].except != nullptr;
    }
}

bool PollRing::is_last_attr_an_error()
{
    if(insert_elt == 0)
    {
        if(ring[max_elt - 1].except != nullptr)
        {
            return true;
        }
        else
        {
            if(ring[max_elt - 1].attr_value_3 != nullptr)
            {
                return (*(ring[max_elt - 1].attr_value_3))[0].err_list.length() != 0;
            }
            else if(ring[max_elt - 1].attr_value_4 != nullptr)
            {
                return (*(ring[max_elt - 1].attr_value_4))[0].err_list.length() != 0;
            }
            else
            {
                return (*(ring[max_elt - 1].attr_value_5))[0].err_list.length() != 0;
            }
        }
    }
    else
    {
        if(ring[insert_elt - 1].except != nullptr)
        {
            return true;
        }
        else
        {
            if(ring[insert_elt - 1].attr_value_3 != nullptr)
            {
                return (*(ring[insert_elt - 1].attr_value_3))[0].err_list.length() != 0;
            }
            else if(ring[insert_elt - 1].attr_value_4 != nullptr)
            {
                return (*(ring[insert_elt - 1].attr_value_4))[0].err_list.length() != 0;
            }
            else
            {
                return (*(ring[insert_elt - 1].attr_value_5))[0].err_list.length() != 0;
            }
        }
    }
}

//+-------------------------------------------------------------------------
//
// method :         PollRing::get_last_except
//
// description :     This method returns the exception recently stored in
//            the ring buffer.
//
//--------------------------------------------------------------------------

Tango::DevFailed *PollRing::get_last_except()
{
    if(insert_elt == 0)
    {
        return ring[max_elt - 1].except;
    }
    else
    {
        return ring[insert_elt - 1].except;
    }
}

//+-------------------------------------------------------------------------
//
// method :         PollRing::get_last_attr_error
//
// description :     This method returns the error stack for polled
//            attribute belonging to device implementing IDL
//            release 3 and more.
//
//--------------------------------------------------------------------------

Tango::DevErrorList &PollRing::get_last_attr_error()
{
    if(insert_elt == 0)
    {
        if(ring[max_elt - 1].attr_value_3 != nullptr)
        {
            return (*(ring[max_elt - 1].attr_value_3))[0].err_list;
        }
        else if(ring[max_elt - 1].attr_value_4 != nullptr)
        {
            return (*(ring[max_elt - 1].attr_value_4))[0].err_list;
        }
        else
        {
            return (*(ring[max_elt - 1].attr_value_5))[0].err_list;
        }
    }
    else
    {
        if(ring[insert_elt - 1].attr_value_3 != nullptr)
        {
            return (*(ring[insert_elt - 1].attr_value_3))[0].err_list;
        }
        else if(ring[insert_elt - 1].attr_value_4 != nullptr)
        {
            return (*(ring[insert_elt - 1].attr_value_4))[0].err_list;
        }
        else
        {
            return (*(ring[insert_elt - 1].attr_value_5))[0].err_list;
        }
    }
}

//+-------------------------------------------------------------------------
//
// method :         PollRing::get_last_cmd_result
//
// description :     This method returns the exception recently stored in
//            the ring buffer.
//
//--------------------------------------------------------------------------

CORBA::Any *PollRing::get_last_cmd_result()
{
    CORBA::Any *tmp_any;

    if(insert_elt == 0)
    {
        if(ring[max_elt - 1].except == nullptr)
        {
            tmp_any = ring[max_elt - 1].cmd_result;
            return new CORBA::Any(tmp_any->type(), const_cast<void *>(tmp_any->value()), false);
        }
        else
        {
            throw Tango::DevFailed(*(ring[max_elt - 1].except));
        }
    }
    else
    {
        if(ring[insert_elt - 1].except == nullptr)
        {
            tmp_any = ring[insert_elt - 1].cmd_result;
            return new CORBA::Any(tmp_any->type(), const_cast<void *>(tmp_any->value()), false);
        }
        else
        {
            throw Tango::DevFailed(*(ring[insert_elt - 1].except));
        }
    }
}

//+-------------------------------------------------------------------------
//
// method :         PollRing::get_last_attr_value
//
// description :     This method returns the exception recently stored in
//            the ring buffer.
//
//--------------------------------------------------------------------------

Tango::AttributeValue &PollRing::get_last_attr_value()
{
    if(insert_elt == 0)
    {
        if(ring[max_elt - 1].except == nullptr)
        {
            return (*(ring[max_elt - 1].attr_value))[0];
        }
        else
        {
            throw Tango::DevFailed(*(ring[max_elt - 1].except));
        }
    }
    else
    {
        if(ring[insert_elt - 1].except == nullptr)
        {
            return (*(ring[insert_elt - 1].attr_value))[0];
        }
        else
        {
            throw Tango::DevFailed(*(ring[insert_elt - 1].except));
        }
    }
}

Tango::AttributeValue_3 &PollRing::get_last_attr_value_3()
{
    if(insert_elt == 0)
    {
        if(ring[max_elt - 1].except == nullptr)
        {
            return (*(ring[max_elt - 1].attr_value_3))[0];
        }
        else
        {
            throw Tango::DevFailed(*(ring[max_elt - 1].except));
        }
    }
    else
    {
        if(ring[insert_elt - 1].except == nullptr)
        {
            return (*(ring[insert_elt - 1].attr_value_3))[0];
        }
        else
        {
            throw Tango::DevFailed(*(ring[insert_elt - 1].except));
        }
    }
}

Tango::AttributeValue_4 &PollRing::get_last_attr_value_4()
{
    if(insert_elt == 0)
    {
        if(ring[max_elt - 1].except == nullptr)
        {
            return (*(ring[max_elt - 1].attr_value_4))[0];
        }
        else
        {
            throw Tango::DevFailed(*(ring[max_elt - 1].except));
        }
    }
    else
    {
        if(ring[insert_elt - 1].except == nullptr)
        {
            return (*(ring[insert_elt - 1].attr_value_4))[0];
        }
        else
        {
            throw Tango::DevFailed(*(ring[insert_elt - 1].except));
        }
    }
}

Tango::AttributeValue_5 &PollRing::get_last_attr_value_5()
{
    if(insert_elt == 0)
    {
        if(ring[max_elt - 1].except == nullptr)
        {
            return (*(ring[max_elt - 1].attr_value_5))[0];
        }
        else
        {
            throw Tango::DevFailed(*(ring[max_elt - 1].except));
        }
    }
    else
    {
        if(ring[insert_elt - 1].except == nullptr)
        {
            return (*(ring[insert_elt - 1].attr_value_5))[0];
        }
        else
        {
            throw Tango::DevFailed(*(ring[insert_elt - 1].except));
        }
    }
}

//-------------------------------------------------------------------------
//
// method :         PollObj::get_cmd_history
//
// description :     This method get command history from the ring buffer
//
// argument : in :    - n : record number
//            - ptr : Pointer to the sequence where command result
//                should be stored
//
//--------------------------------------------------------------------------

void PollRing::get_cmd_history(long n, Tango::DevCmdHistoryList *ptr)
{
    long i;

    //
    // Set index to read ring and to initialised returned sequence
    // In the returned sequence , indice 0 is the oldest data
    //

    long index = insert_elt;
    if(index == 0)
    {
        index = max_elt;
    }
    index--;

    long seq_index = n - 1;

    //
    // Read buffer
    //

    for(i = 0; i < n; i++)
    {
        (*ptr)[seq_index].time = make_TimeVal(ring[index].when);

        if(ring[index].except == nullptr)
        {
            (*ptr)[seq_index].cmd_failed = false;
            (*ptr)[seq_index].value = *(ring[index].cmd_result);
            (*ptr)[seq_index].errors.length(0);
        }
        else
        {
            (*ptr)[seq_index].cmd_failed = true;
            (*ptr)[seq_index].errors = ring[index].except->errors;
        }

        if(index == 0)
        {
            index = max_elt;
        }
        index--;
        seq_index--;
    }
}

void PollRing::get_cmd_history(long n, Tango::DevCmdHistory_4 *ptr, Tango::CmdArgType &cmd_type)
{
    long i;

    //
    // Set index to read ring and to initialised returned sequence
    // In the returned sequence , indice 0 is the oldest data
    //

    long index = insert_elt;
    if(index == 0)
    {
        index = max_elt;
    }
    index--;

    long seq_index = n - 1;

    const Tango::DevVarCharArray *tmp_uch;
    const Tango::DevVarShortArray *tmp_sh;
    const Tango::DevVarLongArray *tmp_lg;
    const Tango::DevVarFloatArray *tmp_fl;
    const Tango::DevVarDoubleArray *tmp_db;
    const Tango::DevVarUShortArray *tmp_ush;
    const Tango::DevVarULongArray *tmp_ulg;
    const Tango::DevVarStringArray *tmp_str;
    const Tango::DevVarBooleanArray *tmp_boo;
    const Tango::DevVarLong64Array *tmp_lg64;
    const Tango::DevVarULong64Array *tmp_ulg64;
    const Tango::DevVarLongStringArray *tmp_lg_str;
    const Tango::DevVarDoubleStringArray *tmp_db_str;

    //
    // Compute the size of the global sequence
    // We have two cases:
    // 1 - For simple types where each record has a constant size
    // 2 - For array types where each record may have different size
    //

    long seq_size = 0;
    long seq_str_size = 0;
    long seq_number_size = 0;
    long error_nb = 0;

    if((cmd_type <= DEV_STRING) || (cmd_type == DEV_STATE) || (cmd_type == CONST_DEV_STRING) ||
       (cmd_type == DEV_UCHAR) || (cmd_type == DEV_LONG64) || (cmd_type == DEV_ULONG64) || (cmd_type == DEV_ENCODED))
    {
        for(i = 0; i < n; i++)
        {
            if(ring[index].except != nullptr)
            {
                error_nb++;
            }

            if(index == 0)
            {
                index = max_elt;
            }
            index--;
        }
        seq_size = n - error_nb;
    }
    else
    {
        for(i = 0; i < n; i++)
        {
            if(ring[index].except == nullptr)
            {
                int data_length = 0;

                switch(cmd_type)
                {
                case DEVVAR_CHARARRAY:
                    (*ring[index].cmd_result) >>= tmp_uch;
                    data_length = tmp_uch->length();
                    break;

                case DEVVAR_SHORTARRAY:
                    (*ring[index].cmd_result) >>= tmp_sh;
                    data_length = tmp_sh->length();
                    break;

                case DEVVAR_LONGARRAY:
                    (*ring[index].cmd_result) >>= tmp_lg;
                    data_length = tmp_lg->length();
                    break;

                case DEVVAR_FLOATARRAY:
                    (*ring[index].cmd_result) >>= tmp_fl;
                    data_length = tmp_fl->length();
                    break;

                case DEVVAR_DOUBLEARRAY:
                    (*ring[index].cmd_result) >>= tmp_db;
                    data_length = tmp_db->length();
                    break;

                case DEVVAR_USHORTARRAY:
                    (*ring[index].cmd_result) >>= tmp_ush;
                    data_length = tmp_ush->length();
                    break;

                case DEVVAR_ULONGARRAY:
                    (*ring[index].cmd_result) >>= tmp_ulg;
                    data_length = tmp_ulg->length();
                    break;

                case DEVVAR_STRINGARRAY:
                    (*ring[index].cmd_result) >>= tmp_str;
                    data_length = tmp_str->length();
                    break;

                case DEVVAR_BOOLEANARRAY:
                    (*ring[index].cmd_result) >>= tmp_boo;
                    data_length = tmp_boo->length();
                    break;

                case DEVVAR_LONG64ARRAY:
                    (*ring[index].cmd_result) >>= tmp_lg64;
                    data_length = tmp_lg64->length();
                    break;

                case DEVVAR_ULONG64ARRAY:
                    (*ring[index].cmd_result) >>= tmp_ulg64;
                    data_length = tmp_ulg64->length();
                    break;

                case DEVVAR_LONGSTRINGARRAY:
                    (*ring[index].cmd_result) >>= tmp_lg_str;
                    seq_str_size = seq_str_size + tmp_lg_str->svalue.length();
                    seq_number_size = seq_number_size + tmp_lg_str->lvalue.length();
                    break;

                case DEVVAR_DOUBLESTRINGARRAY:
                    (*ring[index].cmd_result) >>= tmp_db_str;
                    seq_str_size = seq_str_size + tmp_db_str->svalue.length();
                    seq_number_size = seq_number_size + tmp_db_str->dvalue.length();
                    break;

                case DEV_ENUM:
                    [[fallthrough]];
                case DEV_PIPE_BLOB:
                    [[fallthrough]];
                case DEVVAR_STATEARRAY:
                    [[fallthrough]];
                case DEVVAR_ENCODEDARRAY:
                    [[fallthrough]];
                case DATA_TYPE_UNKNOWN:
                {
                    TangoSys_OMemStream msg;
                    msg << "Unhandled command argument type " << data_type_to_string(cmd_type);
                    TANGO_THROW_EXCEPTION(API_CmdArgumentTypeNotSupported, msg.str().c_str());
                }
                break;

                default:
                    TANGO_ASSERT_ON_DEFAULT(cmd_type);
                }
                seq_size = seq_size + data_length;
            }
            else
            {
                error_nb++;
            }

            if(index == 0)
            {
                index = max_elt;
            }
            index--;
        }
    }

    //
    // First, copy command output data type
    //

    ptr->cmd_type = cmd_type;

    //
    // Read buffer
    //

    Tango::DevVarCharArray *new_tmp_uch = nullptr;
    Tango::DevVarShortArray *new_tmp_sh = nullptr;
    Tango::DevVarLongArray *new_tmp_lg = nullptr;
    Tango::DevVarFloatArray *new_tmp_fl = nullptr;
    Tango::DevVarDoubleArray *new_tmp_db = nullptr;
    Tango::DevVarUShortArray *new_tmp_ush = nullptr;
    Tango::DevVarULongArray *new_tmp_ulg = nullptr;
    Tango::DevVarStringArray *new_tmp_str = nullptr;
    Tango::DevVarBooleanArray *new_tmp_boo = nullptr;
    Tango::DevVarLong64Array *new_tmp_lg64 = nullptr;
    Tango::DevVarULong64Array *new_tmp_ulg64 = nullptr;
    Tango::DevVarLongStringArray *new_tmp_lg_str = nullptr;
    Tango::DevVarDoubleStringArray *new_tmp_db_str = nullptr;
    Tango::DevVarEncodedArray *new_tmp_enc = nullptr;

    Tango::DevShort sh;
    Tango::DevBoolean boo;
    Tango::DevLong lg;
    Tango::DevLong64 lg64;
    Tango::DevFloat fl;
    Tango::DevDouble db;
    Tango::DevUShort ush;
    Tango::DevULong ulg;
    Tango::DevULong64 ulg64;
    Tango::ConstDevString str;
    const Tango::DevEncoded *enc;

    DevErrorList last_err_list;
    int errors_length = 1;
    AttributeDim last_dim;
    int dims_length = 1;
    last_dim.dim_x = -1;
    last_dim.dim_y = -1;

    bool previous_no_data = true;
    bool no_data = true;
    unsigned int ind_in_seq = 0;
    unsigned int ind_str_in_seq = 0;
    unsigned int ind_num_in_seq = 0;

    index = insert_elt;
    if(index == 0)
    {
        index = max_elt;
    }
    index--;

    for(i = 0; i < n; i++)
    {
        previous_no_data = no_data;
        no_data = false;

        //
        // Copy dates
        //

        ptr->dates[seq_index] = make_TimeVal(ring[index].when);

        //
        // Error treatement
        //

        if(ring[index].except != nullptr)
        {
            bool new_err = false;

            if(previous_no_data)
            {
                if(ring[index].except->errors.length() != last_err_list.length())
                {
                    new_err = true;
                }
                else
                {
                    for(unsigned int k = 0; k < last_err_list.length(); k++)
                    {
                        if(::strcmp(ring[index].except->errors[k].reason.in(), last_err_list[k].reason.in()) != 0)
                        {
                            new_err = true;
                            break;
                        }
                        if(::strcmp(ring[index].except->errors[k].desc.in(), last_err_list[k].desc.in()) != 0)
                        {
                            new_err = true;
                            break;
                        }
                        if(::strcmp(ring[index].except->errors[k].origin.in(), last_err_list[k].origin.in()) != 0)
                        {
                            new_err = true;
                            break;
                        }
                        if(ring[index].except->errors[k].severity != last_err_list[k].severity)
                        {
                            new_err = true;
                            break;
                        }
                    }
                }
            }
            else
            {
                new_err = true;
            }

            if(new_err)
            {
                if(ptr->errors.length() == 0)
                {
                    ptr->errors.length(error_nb);
                }
                if(ptr->errors_array.length() == 0)
                {
                    ptr->errors_array.length(error_nb);
                }
                last_err_list = ring[index].except->errors;
                ptr->errors[errors_length - 1] = last_err_list;
                ptr->errors_array[errors_length - 1].start = n - (i + 1);
                ptr->errors_array[errors_length - 1].nb_elt = 1;
                errors_length++;
                previous_no_data = no_data;
                no_data = true;
            }
            else
            {
                ptr->errors_array[errors_length - 2].nb_elt++;
                previous_no_data = no_data;
                no_data = true;
            }

            if((last_dim.dim_x == 0) && (last_dim.dim_y == 0))
            {
                ptr->dims_array[dims_length - 2].nb_elt++;
            }
            else
            {
                last_dim.dim_x = last_dim.dim_y = 0;
                ptr->dims.length(dims_length);
                ptr->dims[dims_length - 1] = last_dim;
                ptr->dims_array.length(dims_length);
                ptr->dims_array[dims_length - 1].start = n - (i + 1);
                ptr->dims_array[dims_length - 1].nb_elt = 1;
                dims_length++;
            }
        }

        //
        // The data
        //

        if(ring[index].except == nullptr)
        {
            switch(cmd_type)
            {
            case DEVVAR_CHARARRAY:
                if(new_tmp_uch == nullptr)
                {
                    new_tmp_uch = new DevVarCharArray();
                    new_tmp_uch->length(seq_size);
                }
                (*ring[index].cmd_result) >>= tmp_uch;
                ADD_ELT_DATA_TO_GLOBAL_SEQ(new_tmp_uch, tmp_uch, ind_in_seq);
                MANAGE_DIM_ARRAY((long) tmp_uch->length());
                break;

            case DEV_SHORT:
                if(new_tmp_sh == nullptr)
                {
                    new_tmp_sh = new DevVarShortArray();
                    new_tmp_sh->length(seq_size);
                }
                (*ring[index].cmd_result) >>= sh;
                ADD_SIMPLE_DATA_TO_GLOBAL_SEQ(new_tmp_sh, sh, ind_in_seq);
                MANAGE_DIM_SIMPLE();
                break;

            case DEVVAR_SHORTARRAY:
                if(new_tmp_sh == nullptr)
                {
                    new_tmp_sh = new DevVarShortArray();
                    new_tmp_sh->length(seq_size);
                }
                (*ring[index].cmd_result) >>= tmp_sh;
                ADD_ELT_DATA_TO_GLOBAL_SEQ(new_tmp_sh, tmp_sh, ind_in_seq);
                MANAGE_DIM_ARRAY((long) tmp_sh->length());
                break;

            case DEV_LONG:
                if(new_tmp_lg == nullptr)
                {
                    new_tmp_lg = new DevVarLongArray();
                    new_tmp_lg->length(seq_size);
                }
                (*ring[index].cmd_result) >>= lg;
                ADD_SIMPLE_DATA_TO_GLOBAL_SEQ(new_tmp_lg, lg, ind_in_seq);
                MANAGE_DIM_SIMPLE();
                break;

            case DEVVAR_LONGARRAY:
                if(new_tmp_lg == nullptr)
                {
                    new_tmp_lg = new DevVarLongArray();
                    new_tmp_lg->length(seq_size);
                }
                (*ring[index].cmd_result) >>= tmp_lg;
                ADD_ELT_DATA_TO_GLOBAL_SEQ(new_tmp_lg, tmp_lg, ind_in_seq);
                MANAGE_DIM_ARRAY((long) tmp_lg->length());
                break;

            case DEV_FLOAT:
                if(new_tmp_fl == nullptr)
                {
                    new_tmp_fl = new DevVarFloatArray();
                    new_tmp_fl->length(seq_size);
                }
                (*ring[index].cmd_result) >>= fl;
                ADD_SIMPLE_DATA_TO_GLOBAL_SEQ(new_tmp_fl, fl, ind_in_seq);
                MANAGE_DIM_SIMPLE();
                break;

            case DEVVAR_FLOATARRAY:
                if(new_tmp_fl == nullptr)
                {
                    new_tmp_fl = new DevVarFloatArray();
                    new_tmp_fl->length(seq_size);
                }
                (*ring[index].cmd_result) >>= tmp_fl;
                ADD_ELT_DATA_TO_GLOBAL_SEQ(new_tmp_fl, tmp_fl, ind_in_seq);
                MANAGE_DIM_ARRAY((long) tmp_fl->length());
                break;

            case DEV_DOUBLE:
                if(new_tmp_db == nullptr)
                {
                    new_tmp_db = new DevVarDoubleArray();
                    new_tmp_db->length(seq_size);
                }
                (*ring[index].cmd_result) >>= db;
                ADD_SIMPLE_DATA_TO_GLOBAL_SEQ(new_tmp_db, db, ind_in_seq);
                MANAGE_DIM_SIMPLE();
                break;

            case DEVVAR_DOUBLEARRAY:
                if(new_tmp_db == nullptr)
                {
                    new_tmp_db = new DevVarDoubleArray();
                    new_tmp_db->length(seq_size);
                }
                (*ring[index].cmd_result) >>= tmp_db;
                ADD_ELT_DATA_TO_GLOBAL_SEQ(new_tmp_db, tmp_db, ind_in_seq);
                MANAGE_DIM_ARRAY((long) tmp_db->length());
                break;

            case DEV_USHORT:
                if(new_tmp_ush == nullptr)
                {
                    new_tmp_ush = new DevVarUShortArray();
                    new_tmp_ush->length(seq_size);
                }
                (*ring[index].cmd_result) >>= ush;
                ADD_SIMPLE_DATA_TO_GLOBAL_SEQ(new_tmp_ush, ush, ind_in_seq);
                MANAGE_DIM_SIMPLE();
                break;

            case DEVVAR_USHORTARRAY:
                if(new_tmp_ush == nullptr)
                {
                    new_tmp_ush = new DevVarUShortArray();
                    new_tmp_ush->length(seq_size);
                }
                (*ring[index].cmd_result) >>= tmp_ush;
                ADD_ELT_DATA_TO_GLOBAL_SEQ(new_tmp_ush, tmp_ush, ind_in_seq);
                MANAGE_DIM_ARRAY((long) tmp_ush->length());
                break;

            case DEV_ULONG:
                if(new_tmp_ulg == nullptr)
                {
                    new_tmp_ulg = new DevVarULongArray();
                    new_tmp_ulg->length(seq_size);
                }
                (*ring[index].cmd_result) >>= ulg;
                ADD_SIMPLE_DATA_TO_GLOBAL_SEQ(new_tmp_ulg, ulg, ind_in_seq);
                MANAGE_DIM_SIMPLE();
                break;

            case DEVVAR_ULONGARRAY:
                if(new_tmp_ulg == nullptr)
                {
                    new_tmp_ulg = new DevVarULongArray();
                    new_tmp_ulg->length(seq_size);
                }
                (*ring[index].cmd_result) >>= tmp_ulg;
                ADD_ELT_DATA_TO_GLOBAL_SEQ(new_tmp_ulg, tmp_ulg, ind_in_seq);
                MANAGE_DIM_ARRAY((long) tmp_ulg->length());
                break;

            case DEV_STRING:
                if(new_tmp_str == nullptr)
                {
                    new_tmp_str = new DevVarStringArray();
                    new_tmp_str->length(seq_size);
                }
                (*ring[index].cmd_result) >>= str;
                ADD_SIMPLE_DATA_TO_GLOBAL_SEQ(new_tmp_str, str, ind_in_seq);
                MANAGE_DIM_SIMPLE();
                break;

            case DEVVAR_STRINGARRAY:
                if(new_tmp_str == nullptr)
                {
                    new_tmp_str = new DevVarStringArray();
                    new_tmp_str->length(seq_size);
                }
                (*ring[index].cmd_result) >>= tmp_str;
                ADD_ELT_DATA_TO_GLOBAL_SEQ(new_tmp_str, tmp_str, ind_in_seq);
                MANAGE_DIM_ARRAY((long) tmp_str->length());
                break;

            case DEV_BOOLEAN:
                if(new_tmp_boo == nullptr)
                {
                    new_tmp_boo = new DevVarBooleanArray();
                    new_tmp_boo->length(seq_size);
                }
                (*ring[index].cmd_result) >>= boo;
                ADD_SIMPLE_DATA_TO_GLOBAL_SEQ(new_tmp_boo, boo, ind_in_seq);
                MANAGE_DIM_SIMPLE();
                break;

            case DEVVAR_BOOLEANARRAY:
                if(new_tmp_boo == nullptr)
                {
                    new_tmp_boo = new DevVarBooleanArray();
                    new_tmp_boo->length(seq_size);
                }
                (*ring[index].cmd_result) >>= tmp_boo;
                ADD_ELT_DATA_TO_GLOBAL_SEQ(new_tmp_boo, tmp_boo, ind_in_seq);
                MANAGE_DIM_ARRAY((long) tmp_boo->length());
                break;

            case DEV_LONG64:
                if(new_tmp_lg64 == nullptr)
                {
                    new_tmp_lg64 = new DevVarLong64Array();
                    new_tmp_lg64->length(seq_size);
                }
                (*ring[index].cmd_result) >>= lg64;
                ADD_SIMPLE_DATA_TO_GLOBAL_SEQ(new_tmp_lg64, lg64, ind_in_seq);
                MANAGE_DIM_SIMPLE();
                break;

            case DEVVAR_LONG64ARRAY:
                if(new_tmp_lg64 == nullptr)
                {
                    new_tmp_lg64 = new DevVarLong64Array();
                    new_tmp_lg64->length(seq_size);
                }
                (*ring[index].cmd_result) >>= tmp_lg64;
                ADD_ELT_DATA_TO_GLOBAL_SEQ(new_tmp_lg64, tmp_lg64, ind_in_seq);
                MANAGE_DIM_ARRAY((long) tmp_lg64->length());
                break;

            case DEV_ULONG64:
                if(new_tmp_ulg64 == nullptr)
                {
                    new_tmp_ulg64 = new DevVarULong64Array();
                    new_tmp_ulg64->length(seq_size);
                }
                (*ring[index].cmd_result) >>= ulg64;
                ADD_SIMPLE_DATA_TO_GLOBAL_SEQ(new_tmp_ulg64, ulg64, ind_in_seq);
                MANAGE_DIM_SIMPLE();
                break;

            case DEVVAR_ULONG64ARRAY:
                if(new_tmp_ulg64 == nullptr)
                {
                    new_tmp_ulg64 = new DevVarULong64Array();
                    new_tmp_ulg64->length(seq_size);
                }
                (*ring[index].cmd_result) >>= tmp_ulg64;
                ADD_ELT_DATA_TO_GLOBAL_SEQ(new_tmp_ulg64, tmp_ulg64, ind_in_seq);
                MANAGE_DIM_ARRAY((long) tmp_ulg64->length());
                break;

            case DEVVAR_LONGSTRINGARRAY:
                if(new_tmp_lg_str == nullptr)
                {
                    new_tmp_lg_str = new DevVarLongStringArray();
                    new_tmp_lg_str->svalue.length(seq_str_size);
                    new_tmp_lg_str->lvalue.length(seq_number_size);
                }
                (*ring[index].cmd_result) >>= tmp_lg_str;
                ADD_ELT_DATA_TO_GLOBAL_SEQ_BY_REF(new_tmp_lg_str->svalue, tmp_lg_str->svalue, ind_str_in_seq);
                ADD_ELT_DATA_TO_GLOBAL_SEQ_BY_REF(new_tmp_lg_str->lvalue, tmp_lg_str->lvalue, ind_num_in_seq);
                MANAGE_DIM_ARRAY_SEQ((long) tmp_lg_str->svalue.length(), (long) tmp_lg_str->lvalue.length());
                break;

            case DEVVAR_DOUBLESTRINGARRAY:
                if(new_tmp_db_str == nullptr)
                {
                    new_tmp_db_str = new DevVarDoubleStringArray();
                    new_tmp_db_str->svalue.length(seq_str_size);
                    new_tmp_db_str->dvalue.length(seq_number_size);
                }
                (*ring[index].cmd_result) >>= tmp_db_str;
                ADD_ELT_DATA_TO_GLOBAL_SEQ_BY_REF(new_tmp_db_str->svalue, tmp_db_str->svalue, ind_str_in_seq);
                ADD_ELT_DATA_TO_GLOBAL_SEQ_BY_REF(new_tmp_db_str->dvalue, tmp_db_str->dvalue, ind_num_in_seq);
                MANAGE_DIM_ARRAY_SEQ((long) tmp_db_str->svalue.length(), (long) tmp_db_str->dvalue.length());
                break;

            case DEV_ENCODED:
                if(new_tmp_enc == nullptr)
                {
                    new_tmp_enc = new DevVarEncodedArray();
                    new_tmp_enc->length(seq_size);
                }
                (*ring[index].cmd_result) >>= enc;

                {
                    unsigned int buffer_data_length = enc->encoded_data.length();
                    Tango::DevVarCharArray &tmp_buffer = (*new_tmp_enc)[ind_in_seq].encoded_data;
                    tmp_buffer.length(buffer_data_length);
                    for(unsigned int k = 0; k < buffer_data_length; k++)
                    {
                        tmp_buffer[k] = enc->encoded_data[k];
                    }
                    (*new_tmp_enc)[ind_in_seq].encoded_format = Tango::string_dup(enc->encoded_format);
                    ind_in_seq = ind_in_seq + 1;
                }
                MANAGE_DIM_SIMPLE();
                break;

            case DEV_UCHAR:
                [[fallthrough]];
            case CONST_DEV_STRING:
                [[fallthrough]];
            case DEV_STATE:
                [[fallthrough]];
            case DEV_VOID:
                [[fallthrough]];
            case DEV_ENUM:
                [[fallthrough]];
            case DEV_PIPE_BLOB:
                [[fallthrough]];
            case DEVVAR_STATEARRAY:
                [[fallthrough]];
            case DEVVAR_ENCODEDARRAY:
                [[fallthrough]];
            case DATA_TYPE_UNKNOWN:
            {
                TangoSys_OMemStream msg;
                msg << "Unhandled command argument type " << data_type_to_string(cmd_type);
                TANGO_THROW_EXCEPTION(API_CmdArgumentTypeNotSupported, msg.str().c_str());
            }
            break;

            default:
                TANGO_ASSERT_ON_DEFAULT(cmd_type);
            }
        }

        //
        // If it is the last point, insert the global sequence into the Any
        //

        if(i == (n - 1))
        {
            if(errors_length != (error_nb + 1))
            {
                ptr->errors.length(errors_length - 1);
                ptr->errors_array.length(errors_length - 1);
            }

            switch(cmd_type)
            {
            case Tango::DEVVAR_CHARARRAY:
                if(new_tmp_uch != nullptr)
                {
                    ptr->value <<= new_tmp_uch;
                }
                break;

            case Tango::DEVVAR_SHORTARRAY:
            case Tango::DEV_SHORT:
                if(new_tmp_sh != nullptr)
                {
                    ptr->value <<= new_tmp_sh;
                }
                break;

            case Tango::DEVVAR_LONGARRAY:
            case Tango::DEV_LONG:
                if(new_tmp_lg != nullptr)
                {
                    ptr->value <<= new_tmp_lg;
                }
                break;

            case Tango::DEVVAR_FLOATARRAY:
            case Tango::DEV_FLOAT:
                if(new_tmp_fl != nullptr)
                {
                    ptr->value <<= new_tmp_fl;
                }
                break;

            case Tango::DEVVAR_DOUBLEARRAY:
            case Tango::DEV_DOUBLE:
                if(new_tmp_db != nullptr)
                {
                    ptr->value <<= new_tmp_db;
                }
                break;

            case Tango::DEVVAR_USHORTARRAY:
            case Tango::DEV_USHORT:
                if(new_tmp_db != nullptr)
                {
                    ptr->value <<= new_tmp_db;
                }
                break;

            case Tango::DEVVAR_ULONGARRAY:
            case Tango::DEV_ULONG:
                if(new_tmp_db != nullptr)
                {
                    ptr->value <<= new_tmp_db;
                }
                break;

            case Tango::DEVVAR_STRINGARRAY:
            case Tango::DEV_STRING:
                if(new_tmp_str != nullptr)
                {
                    ptr->value <<= new_tmp_str;
                }
                break;

            case Tango::DEVVAR_BOOLEANARRAY:
            case Tango::DEV_BOOLEAN:
                if(new_tmp_boo != nullptr)
                {
                    ptr->value <<= new_tmp_boo;
                }
                break;

            case Tango::DEVVAR_LONG64ARRAY:
            case Tango::DEV_LONG64:
                if(new_tmp_lg64 != nullptr)
                {
                    ptr->value <<= new_tmp_lg64;
                }
                break;

            case Tango::DEVVAR_ULONG64ARRAY:
            case Tango::DEV_ULONG64:
                if(new_tmp_ulg64 != nullptr)
                {
                    ptr->value <<= new_tmp_ulg64;
                }
                break;

            case Tango::DEVVAR_LONGSTRINGARRAY:
                if(new_tmp_lg_str != nullptr)
                {
                    ptr->value <<= new_tmp_lg_str;
                }
                break;

            case Tango::DEVVAR_DOUBLESTRINGARRAY:
                if(new_tmp_db_str != nullptr)
                {
                    ptr->value <<= new_tmp_db_str;
                }
                break;

            case Tango::DEV_ENCODED:
                if(new_tmp_enc != nullptr)
                {
                    ptr->value <<= new_tmp_enc;
                }
                break;

            case Tango::DEV_VOID:
                // do nothing
                break;

            case DEV_UCHAR:
                [[fallthrough]];
            case CONST_DEV_STRING:
                [[fallthrough]];
            case DEV_STATE:
                [[fallthrough]];
            case DEV_ENUM:
                [[fallthrough]];
            case DEV_PIPE_BLOB:
                [[fallthrough]];
            case DEVVAR_STATEARRAY:
                [[fallthrough]];
            case DEVVAR_ENCODEDARRAY:
                [[fallthrough]];
            case DATA_TYPE_UNKNOWN:
            {
                TangoSys_OMemStream msg;
                msg << "Unhandled command argument type " << data_type_to_string(cmd_type);
                TANGO_THROW_EXCEPTION(API_CmdArgumentTypeNotSupported, msg.str().c_str());
            }
            break;

            default:
                TANGO_ASSERT_ON_DEFAULT(cmd_type);
            }
        }

        //
        // Manage index in buffer
        //

        if(index == 0)
        {
            index = max_elt;
        }
        index--;
        seq_index--;
    }
}

//-------------------------------------------------------------------------
//
// method :         PollObj::get_attr_history
//
// description :     This method get attribute history from the ring buffer
//
// argument : in :    - n : record number
//            - ptr : Pointer to the sequence where attribute result
//                should be stored
//            - type : The attribute data type
//
//--------------------------------------------------------------------------

void PollRing::get_attr_history(long n, Tango::DevAttrHistoryList *ptr, long type)
{
    long i;

    //
    // Set index to read ring and to initialised returned sequence
    // In the returned sequence , indice 0 is the oldest data
    //

    long index = insert_elt;
    if(index == 0)
    {
        index = max_elt;
    }
    index--;

    long seq_index = n - 1;

    //
    // Read buffer
    //

    for(i = 0; i < n; i++)
    {
        (*ptr)[seq_index].value.time = make_TimeVal(ring[index].when);

        if(ring[index].except == nullptr)
        {
            (*ptr)[seq_index].attr_failed = false;
            (*ptr)[seq_index].value.quality = (*ring[index].attr_value)[0].quality;
            (*ptr)[seq_index].value.dim_x = (*ring[index].attr_value)[0].dim_x;
            (*ptr)[seq_index].value.dim_y = (*ring[index].attr_value)[0].dim_y;
            (*ptr)[seq_index].value.name = Tango::string_dup((*ring[index].attr_value)[0].name);

            if((*ptr)[seq_index].value.quality != Tango::ATTR_INVALID)
            {
                const Tango::DevVarDoubleArray *tmp_db;
                Tango::DevVarDoubleArray *new_tmp_db;
                const Tango::DevVarShortArray *tmp_sh;
                Tango::DevVarShortArray *new_tmp_sh;
                const Tango::DevVarLongArray *tmp_lg;
                Tango::DevVarLongArray *new_tmp_lg;
                const Tango::DevVarLong64Array *tmp_lg64;
                Tango::DevVarLong64Array *new_tmp_lg64;
                const Tango::DevVarStringArray *tmp_str;
                Tango::DevVarStringArray *new_tmp_str;
                const Tango::DevVarFloatArray *tmp_fl;
                Tango::DevVarFloatArray *new_tmp_fl;
                const Tango::DevVarBooleanArray *tmp_boo;
                Tango::DevVarBooleanArray *new_tmp_boo;
                const Tango::DevVarUShortArray *tmp_ush;
                Tango::DevVarUShortArray *new_tmp_ush;
                const Tango::DevVarCharArray *tmp_uch;
                Tango::DevVarCharArray *new_tmp_uch;
                const Tango::DevVarULongArray *tmp_ulg;
                Tango::DevVarULongArray *new_tmp_ulg;
                const Tango::DevVarULong64Array *tmp_ulg64;
                Tango::DevVarULong64Array *new_tmp_ulg64;
                const Tango::DevVarStateArray *tmp_state;
                Tango::DevVarStateArray *new_tmp_state;

                switch(type)
                {
                case Tango::DEV_SHORT:
                case Tango::DEV_ENUM:
                    (*ring[index].attr_value)[0].value >>= tmp_sh;
                    new_tmp_sh = new DevVarShortArray(
                        tmp_sh->length(), tmp_sh->length(), const_cast<short *>(tmp_sh->get_buffer()), false);
                    (*ptr)[seq_index].value.value <<= new_tmp_sh;
                    break;

                case Tango::DEV_DOUBLE:
                    (*ring[index].attr_value)[0].value >>= tmp_db;
                    new_tmp_db = new DevVarDoubleArray(
                        tmp_db->length(), tmp_db->length(), const_cast<double *>(tmp_db->get_buffer()), false);
                    (*ptr)[seq_index].value.value <<= new_tmp_db;
                    break;

                case Tango::DEV_LONG:
                    (*ring[index].attr_value)[0].value >>= tmp_lg;
                    new_tmp_lg = new DevVarLongArray(
                        tmp_lg->length(), tmp_lg->length(), const_cast<DevLong *>(tmp_lg->get_buffer()), false);
                    (*ptr)[seq_index].value.value <<= new_tmp_lg;
                    break;

                case Tango::DEV_LONG64:
                    (*ring[index].attr_value)[0].value >>= tmp_lg64;
                    new_tmp_lg64 = new DevVarLong64Array(
                        tmp_lg64->length(), tmp_lg64->length(), const_cast<DevLong64 *>(tmp_lg64->get_buffer()), false);
                    (*ptr)[seq_index].value.value <<= new_tmp_lg64;
                    break;

                case Tango::DEV_STRING:
                    (*ring[index].attr_value)[0].value >>= tmp_str;
                    new_tmp_str = new DevVarStringArray(
                        tmp_str->length(), tmp_str->length(), const_cast<char **>(tmp_str->get_buffer()), false);
                    (*ptr)[seq_index].value.value <<= new_tmp_str;
                    break;

                case Tango::DEV_FLOAT:
                    (*ring[index].attr_value)[0].value >>= tmp_fl;
                    new_tmp_fl = new DevVarFloatArray(
                        tmp_fl->length(), tmp_fl->length(), const_cast<float *>(tmp_fl->get_buffer()), false);
                    (*ptr)[seq_index].value.value <<= new_tmp_fl;
                    break;

                case Tango::DEV_BOOLEAN:
                    (*ring[index].attr_value)[0].value >>= tmp_boo;
                    new_tmp_boo = new DevVarBooleanArray(
                        tmp_boo->length(), tmp_boo->length(), const_cast<DevBoolean *>(tmp_boo->get_buffer()), false);
                    (*ptr)[seq_index].value.value <<= new_tmp_boo;
                    break;

                case Tango::DEV_USHORT:
                    (*ring[index].attr_value)[0].value >>= tmp_ush;
                    new_tmp_ush = new DevVarUShortArray(
                        tmp_ush->length(), tmp_ush->length(), const_cast<DevUShort *>(tmp_ush->get_buffer()), false);
                    (*ptr)[seq_index].value.value <<= new_tmp_ush;
                    break;

                case Tango::DEV_UCHAR:
                    (*ring[index].attr_value)[0].value >>= tmp_uch;
                    new_tmp_uch = new DevVarCharArray(
                        tmp_uch->length(), tmp_uch->length(), const_cast<DevUChar *>(tmp_uch->get_buffer()), false);
                    (*ptr)[seq_index].value.value <<= new_tmp_uch;
                    break;

                case Tango::DEV_ULONG:
                    (*ring[index].attr_value)[0].value >>= tmp_ulg;
                    new_tmp_ulg = new DevVarULongArray(
                        tmp_ulg->length(), tmp_ulg->length(), const_cast<DevULong *>(tmp_ulg->get_buffer()), false);
                    (*ptr)[seq_index].value.value <<= new_tmp_ulg;
                    break;

                case Tango::DEV_ULONG64:
                    (*ring[index].attr_value)[0].value >>= tmp_ulg64;
                    new_tmp_ulg64 = new DevVarULong64Array(tmp_ulg64->length(),
                                                           tmp_ulg64->length(),
                                                           const_cast<DevULong64 *>(tmp_ulg64->get_buffer()),
                                                           false);
                    (*ptr)[seq_index].value.value <<= new_tmp_ulg64;
                    break;

                case Tango::DEV_STATE:
                    (*ring[index].attr_value)[0].value >>= tmp_state;
                    new_tmp_state = new DevVarStateArray(tmp_state->length(),
                                                         tmp_state->length(),
                                                         const_cast<DevState *>(tmp_state->get_buffer()),
                                                         false);
                    (*ptr)[seq_index].value.value <<= new_tmp_state;
                    break;
                }
            }
            (*ptr)[seq_index].errors.length(0);
        }
        else
        {
            (*ptr)[seq_index].attr_failed = true;
            (*ptr)[seq_index].errors = ring[index].except->errors;

            (*ptr)[seq_index].value.quality = Tango::ATTR_INVALID;
            (*ptr)[seq_index].value.dim_x = 0;
            (*ptr)[seq_index].value.dim_y = 0;
        }

        if(index == 0)
        {
            index = max_elt;
        }
        index--;
        seq_index--;
    }
}

void PollRing::get_attr_history(long n, Tango::DevAttrHistoryList_3 *ptr, long type)
{
    long i;

    //
    // Set index to read ring and to initialised returned sequence
    // In the returned sequence , indice 0 is the oldest data
    //

    long index = insert_elt;
    if(index == 0)
    {
        index = max_elt;
    }
    index--;

    long seq_index = n - 1;

    //
    // Read buffer
    //

    for(i = 0; i < n; i++)
    {
        (*ptr)[seq_index].value.time = make_TimeVal(ring[index].when);

        if(ring[index].except == nullptr)
        {
            (*ptr)[seq_index].value.err_list = (*ring[index].attr_value_3)[0].err_list;
            (*ptr)[seq_index].value.quality = (*ring[index].attr_value_3)[0].quality;
            (*ptr)[seq_index].value.r_dim = (*ring[index].attr_value_3)[0].r_dim;
            (*ptr)[seq_index].value.w_dim = (*ring[index].attr_value_3)[0].w_dim;
            (*ptr)[seq_index].value.name = Tango::string_dup((*ring[index].attr_value_3)[0].name);

            (*ptr)[seq_index].attr_failed = false;

            if((*ptr)[seq_index].value.quality != Tango::ATTR_INVALID)
            {
                const Tango::DevVarDoubleArray *tmp_db;
                Tango::DevVarDoubleArray *new_tmp_db;
                const Tango::DevVarShortArray *tmp_sh;
                Tango::DevVarShortArray *new_tmp_sh;
                const Tango::DevVarLongArray *tmp_lg;
                Tango::DevVarLongArray *new_tmp_lg;
                const Tango::DevVarLong64Array *tmp_lg64;
                Tango::DevVarLong64Array *new_tmp_lg64;
                const Tango::DevVarStringArray *tmp_str;
                Tango::DevVarStringArray *new_tmp_str;
                const Tango::DevVarFloatArray *tmp_fl;
                Tango::DevVarFloatArray *new_tmp_fl;
                const Tango::DevVarBooleanArray *tmp_boo;
                Tango::DevVarBooleanArray *new_tmp_boo;
                const Tango::DevVarUShortArray *tmp_ush;
                Tango::DevVarUShortArray *new_tmp_ush;
                const Tango::DevVarCharArray *tmp_uch;
                Tango::DevVarCharArray *new_tmp_uch;
                const Tango::DevVarULongArray *tmp_ulg;
                Tango::DevVarULongArray *new_tmp_ulg;
                const Tango::DevVarULong64Array *tmp_ulg64;
                Tango::DevVarULong64Array *new_tmp_ulg64;
                const Tango::DevVarStateArray *tmp_state;
                Tango::DevVarStateArray *new_tmp_state;

                switch(type)
                {
                case Tango::DEV_SHORT:
                case Tango::DEV_ENUM:
                    (*ring[index].attr_value_3)[0].value >>= tmp_sh;
                    new_tmp_sh = new DevVarShortArray(
                        tmp_sh->length(), tmp_sh->length(), const_cast<short *>(tmp_sh->get_buffer()), false);
                    (*ptr)[seq_index].value.value <<= new_tmp_sh;
                    break;

                case Tango::DEV_DOUBLE:
                    (*ring[index].attr_value_3)[0].value >>= tmp_db;
                    new_tmp_db = new DevVarDoubleArray(
                        tmp_db->length(), tmp_db->length(), const_cast<double *>(tmp_db->get_buffer()), false);
                    (*ptr)[seq_index].value.value <<= new_tmp_db;
                    break;

                case Tango::DEV_LONG:
                    (*ring[index].attr_value_3)[0].value >>= tmp_lg;
                    new_tmp_lg = new DevVarLongArray(
                        tmp_lg->length(), tmp_lg->length(), const_cast<DevLong *>(tmp_lg->get_buffer()), false);
                    (*ptr)[seq_index].value.value <<= new_tmp_lg;
                    break;

                case Tango::DEV_LONG64:
                    (*ring[index].attr_value_3)[0].value >>= tmp_lg64;
                    new_tmp_lg64 = new DevVarLong64Array(
                        tmp_lg64->length(), tmp_lg64->length(), const_cast<DevLong64 *>(tmp_lg64->get_buffer()), false);
                    (*ptr)[seq_index].value.value <<= new_tmp_lg64;
                    break;

                case Tango::DEV_STRING:
                    (*ring[index].attr_value_3)[0].value >>= tmp_str;
                    new_tmp_str = new DevVarStringArray(
                        tmp_str->length(), tmp_str->length(), const_cast<char **>(tmp_str->get_buffer()), false);
                    (*ptr)[seq_index].value.value <<= new_tmp_str;
                    break;

                case Tango::DEV_FLOAT:
                    (*ring[index].attr_value_3)[0].value >>= tmp_fl;
                    new_tmp_fl = new DevVarFloatArray(
                        tmp_fl->length(), tmp_fl->length(), const_cast<float *>(tmp_fl->get_buffer()), false);
                    (*ptr)[seq_index].value.value <<= new_tmp_fl;
                    break;

                case Tango::DEV_BOOLEAN:
                    (*ring[index].attr_value_3)[0].value >>= tmp_boo;
                    new_tmp_boo = new DevVarBooleanArray(
                        tmp_boo->length(), tmp_boo->length(), const_cast<DevBoolean *>(tmp_boo->get_buffer()), false);
                    (*ptr)[seq_index].value.value <<= new_tmp_boo;
                    break;

                case Tango::DEV_USHORT:
                    (*ring[index].attr_value_3)[0].value >>= tmp_ush;
                    new_tmp_ush = new DevVarUShortArray(
                        tmp_ush->length(), tmp_ush->length(), const_cast<DevUShort *>(tmp_ush->get_buffer()), false);
                    (*ptr)[seq_index].value.value <<= new_tmp_ush;
                    break;

                case Tango::DEV_UCHAR:
                    (*ring[index].attr_value_3)[0].value >>= tmp_uch;
                    new_tmp_uch = new DevVarCharArray(
                        tmp_uch->length(), tmp_uch->length(), const_cast<DevUChar *>(tmp_uch->get_buffer()), false);
                    (*ptr)[seq_index].value.value <<= new_tmp_uch;
                    break;

                case Tango::DEV_ULONG:
                    (*ring[index].attr_value_3)[0].value >>= tmp_ulg;
                    new_tmp_ulg = new DevVarULongArray(
                        tmp_ulg->length(), tmp_ulg->length(), const_cast<DevULong *>(tmp_ulg->get_buffer()), false);
                    (*ptr)[seq_index].value.value <<= new_tmp_ulg;
                    break;

                case Tango::DEV_ULONG64:
                    (*ring[index].attr_value_3)[0].value >>= tmp_ulg64;
                    new_tmp_ulg64 = new DevVarULong64Array(tmp_ulg64->length(),
                                                           tmp_ulg64->length(),
                                                           const_cast<DevULong64 *>(tmp_ulg64->get_buffer()),
                                                           false);
                    (*ptr)[seq_index].value.value <<= new_tmp_ulg64;
                    break;

                case Tango::DEV_STATE:
                {
                    CORBA::TypeCode_var ty;
                    ty = (*ring[index].attr_value_3)[0].value.type();

                    if(ty->kind() == CORBA::tk_enum)
                    {
                        Tango::DevState tmp_ds;
                        (*ring[index].attr_value_3)[0].value >>= tmp_ds;
                        (*ptr)[seq_index].value.value <<= tmp_ds;
                    }
                    else
                    {
                        (*ring[index].attr_value_3)[0].value >>= tmp_state;
                        new_tmp_state = new DevVarStateArray(tmp_state->length(),
                                                             tmp_state->length(),
                                                             const_cast<DevState *>(tmp_state->get_buffer()),
                                                             false);
                        (*ptr)[seq_index].value.value <<= new_tmp_state;
                    }
                    break;
                }
                }
            }
        }
        else
        {
            (*ptr)[seq_index].attr_failed = true;
            (*ptr)[seq_index].value.err_list = ring[index].except->errors;
            (*ptr)[seq_index].value.quality = Tango::ATTR_INVALID;
            clear_att_dim((*ptr)[seq_index].value);
        }

        if(index == 0)
        {
            index = max_elt;
        }
        index--;
        seq_index--;
    }
}

void PollRing::get_attr_history_43(long n, Tango::DevAttrHistoryList_3 *ptr, long type)
{
    long i;

    //
    // Set index to read ring and to initialised returned sequence
    // In the returned sequence , indice 0 is the oldest data
    //

    long index = insert_elt;
    if(index == 0)
    {
        index = max_elt;
    }
    index--;

    long seq_index = n - 1;

    //
    // Read buffer
    //

    for(i = 0; i < n; i++)
    {
        (*ptr)[seq_index].value.time = make_TimeVal(ring[index].when);

        if(ring[index].except == nullptr)
        {
            (*ptr)[seq_index].value.err_list = (*ring[index].attr_value_4)[0].err_list;
            (*ptr)[seq_index].value.quality = (*ring[index].attr_value_4)[0].quality;
            (*ptr)[seq_index].value.r_dim = (*ring[index].attr_value_4)[0].r_dim;
            (*ptr)[seq_index].value.w_dim = (*ring[index].attr_value_4)[0].w_dim;
            (*ptr)[seq_index].value.name = Tango::string_dup((*ring[index].attr_value_4)[0].name);

            (*ptr)[seq_index].attr_failed = false;

            if((*ptr)[seq_index].value.quality != Tango::ATTR_INVALID)
            {
                switch(type)
                {
                case Tango::DEV_SHORT:
                case Tango::DEV_ENUM:
                {
                    const DevVarShortArray &tmp_seq = (*ring[index].attr_value_4)[0].value.short_att_value();
                    (*ptr)[seq_index].value.value <<= tmp_seq;
                }
                break;

                case Tango::DEV_DOUBLE:
                {
                    const DevVarDoubleArray &tmp_seq = (*ring[index].attr_value_4)[0].value.double_att_value();
                    (*ptr)[seq_index].value.value <<= tmp_seq;
                }
                break;

                case Tango::DEV_LONG:
                {
                    const DevVarLongArray &tmp_seq = (*ring[index].attr_value_4)[0].value.long_att_value();
                    (*ptr)[seq_index].value.value <<= tmp_seq;
                }
                break;

                case Tango::DEV_LONG64:
                {
                    const DevVarLong64Array &tmp_seq = (*ring[index].attr_value_4)[0].value.long64_att_value();
                    (*ptr)[seq_index].value.value <<= tmp_seq;
                }
                break;

                case Tango::DEV_STRING:
                {
                    const DevVarStringArray &tmp_seq = (*ring[index].attr_value_4)[0].value.string_att_value();
                    (*ptr)[seq_index].value.value <<= tmp_seq;
                }
                break;

                case Tango::DEV_FLOAT:
                {
                    const DevVarFloatArray &tmp_seq = (*ring[index].attr_value_4)[0].value.float_att_value();
                    (*ptr)[seq_index].value.value <<= tmp_seq;
                }
                break;

                case Tango::DEV_BOOLEAN:
                {
                    const DevVarBooleanArray &tmp_seq = (*ring[index].attr_value_4)[0].value.bool_att_value();
                    (*ptr)[seq_index].value.value <<= tmp_seq;
                }
                break;

                case Tango::DEV_USHORT:
                {
                    const DevVarUShortArray &tmp_seq = (*ring[index].attr_value_4)[0].value.ushort_att_value();
                    (*ptr)[seq_index].value.value <<= tmp_seq;
                }
                break;

                case Tango::DEV_UCHAR:
                {
                    const DevVarCharArray &tmp_seq = (*ring[index].attr_value_4)[0].value.uchar_att_value();
                    (*ptr)[seq_index].value.value <<= tmp_seq;
                }
                break;

                case Tango::DEV_ULONG:
                {
                    const DevVarULongArray &tmp_seq = (*ring[index].attr_value_4)[0].value.ulong_att_value();
                    (*ptr)[seq_index].value.value <<= tmp_seq;
                }
                break;

                case Tango::DEV_ULONG64:
                {
                    const DevVarULong64Array &tmp_seq = (*ring[index].attr_value_4)[0].value.ulong64_att_value();
                    (*ptr)[seq_index].value.value <<= tmp_seq;
                }
                break;

                case Tango::DEV_STATE:
                {
                    if((*ring[index].attr_value_4)[0].value._d() == DEVICE_STATE)
                    {
                        DevState tmp_ds = (*ring[index].attr_value_4)[0].value.dev_state_att();
                        (*ptr)[seq_index].value.value <<= tmp_ds;
                    }
                    else
                    {
                        DevVarStateArray &tmp_seq = (*ring[index].attr_value_4)[0].value.state_att_value();
                        (*ptr)[seq_index].value.value <<= tmp_seq;
                    }
                }
                break;
                }
            }
        }
        else
        {
            (*ptr)[seq_index].attr_failed = true;
            (*ptr)[seq_index].value.err_list = ring[index].except->errors;
            (*ptr)[seq_index].value.quality = Tango::ATTR_INVALID;
            clear_att_dim((*ptr)[seq_index].value);
        }

        if(index == 0)
        {
            index = max_elt;
        }
        index--;
        seq_index--;
    }
}

} // namespace Tango
