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

#include <tango/internal/client/devapi_macros.h>

#include <tango/client/AttributeInfo.h>
#include <tango/client/AttributeInfoEx.h>
#include <tango/client/PipeInfo.h>
#include <tango/common/idl_wrapper.h>
#include <tango/common/utils/assert.h>

#include <ostream>

namespace Tango
{

//+-----------------------------------------------------------------------------------------------------------------
//
// function
//         operator overloading :     <<
//
// description :
//        Friend function to ease printing instance of the AttributeInfo class
//
//-----------------------------------------------------------------------------------------------------------------

std::ostream &operator<<(std::ostream &o_str, const AttributeInfo &p)
{
    //
    // Print all these properties
    //

    o_str << "Attribute name = " << p.name << std::endl;
    o_str << "Attribute data_type = " << (CmdArgType) p.data_type << std::endl;

    o_str << "Attribute data_format = ";
    switch(p.data_format)
    {
    case Tango::FMT_UNKNOWN:
        break;

    case Tango::SCALAR:
        o_str << "scalar" << std::endl;
        break;

    case Tango::SPECTRUM:
        o_str << "spectrum, max_dim_x = " << p.max_dim_x << std::endl;
        break;

    case Tango::IMAGE:
        o_str << "image, max_dim_x = " << p.max_dim_x << ", max_dim_y = " << p.max_dim_y << std::endl;
        break;
    }

    if((p.writable == Tango::WRITE) || (p.writable == Tango::READ_WRITE))
    {
        o_str << "Attribute is writable" << std::endl;
    }
    else
    {
        o_str << "Attribute is not writable" << std::endl;
    }
    o_str << "Attribute label = " << p.label << std::endl;
    o_str << "Attribute description = " << p.description << std::endl;
    o_str << "Attribute unit = " << p.unit;
    o_str << ", standard unit = " << p.standard_unit;
    o_str << ", display unit = " << p.display_unit << std::endl;
    o_str << "Attribute format = " << p.format << std::endl;
    o_str << "Attribute min alarm = " << p.min_alarm << std::endl;
    o_str << "Attribute max alarm = " << p.max_alarm << std::endl;
    o_str << "Attribute min value = " << p.min_value << std::endl;
    o_str << "Attribute max value = " << p.max_value << std::endl;
    o_str << "Attribute writable_attr_name = " << p.writable_attr_name;

    return o_str;
}

//+----------------------------------------------------------------------------------------------------------------
//
// function :
//         operator overloading :     =
//
// description :
//        Assignement operator for the AttributeInfoEx class from a AttributeConfig_2 pointer
//
//----------------------------------------------------------------------------------------------------------------

AttributeInfoEx &AttributeInfoEx::operator=(const AttributeConfig_2 *att_2)
{
    name = att_2->name;
    writable = att_2->writable;
    data_format = att_2->data_format;
    data_type = att_2->data_type;
    max_dim_x = att_2->max_dim_x;
    max_dim_y = att_2->max_dim_y;
    description = att_2->description;
    label = att_2->label;
    unit = att_2->unit;
    standard_unit = att_2->standard_unit;
    display_unit = att_2->display_unit;
    format = att_2->format;
    min_value = att_2->min_value;
    max_value = att_2->max_value;
    min_alarm = att_2->min_alarm;
    max_alarm = att_2->max_alarm;
    writable_attr_name = att_2->writable_attr_name;
    extensions.resize(att_2->extensions.length());
    for(unsigned int j = 0; j < att_2->extensions.length(); j++)
    {
        extensions[j] = att_2->extensions[j];
    }
    disp_level = att_2->level;

    return *this;
}

//+---------------------------------------------------------------------------------------------------------------
//
// function :
//         operator overloading :     =
//
// description :
//        Assignement operator for the AttributeInfoEx class from a AttributeConfig_3 pointer
//
//-----------------------------------------------------------------------------------------------------------------

AttributeInfoEx &AttributeInfoEx::operator=(const AttributeConfig_3 *att_3)
{
    name = att_3->name;
    writable = att_3->writable;
    data_format = att_3->data_format;
    data_type = att_3->data_type;
    max_dim_x = att_3->max_dim_x;
    max_dim_y = att_3->max_dim_y;
    description = att_3->description;
    label = att_3->label;
    unit = att_3->unit;
    standard_unit = att_3->standard_unit;
    display_unit = att_3->display_unit;
    format = att_3->format;
    min_value = att_3->min_value;
    max_value = att_3->max_value;
    min_alarm = att_3->att_alarm.min_alarm;
    max_alarm = att_3->att_alarm.max_alarm;
    writable_attr_name = att_3->writable_attr_name;
    extensions.resize(att_3->sys_extensions.length());
    for(unsigned int j = 0; j < att_3->sys_extensions.length(); j++)
    {
        extensions[j] = att_3->sys_extensions[j];
    }
    disp_level = att_3->level;

    alarms.min_alarm = att_3->att_alarm.min_alarm;
    alarms.max_alarm = att_3->att_alarm.max_alarm;
    alarms.min_warning = att_3->att_alarm.min_warning;
    alarms.max_warning = att_3->att_alarm.max_warning;
    alarms.delta_t = att_3->att_alarm.delta_t;
    alarms.delta_val = att_3->att_alarm.delta_val;
    alarms.extensions.resize(att_3->att_alarm.extensions.length());
    for(unsigned int j = 0; j < att_3->att_alarm.extensions.length(); j++)
    {
        alarms.extensions[j] = att_3->att_alarm.extensions[j];
    }

    events.ch_event.abs_change = att_3->event_prop.ch_event.abs_change;
    events.ch_event.rel_change = att_3->event_prop.ch_event.rel_change;
    events.ch_event.extensions.resize(att_3->event_prop.ch_event.extensions.length());
    for(unsigned int j = 0; j < att_3->event_prop.ch_event.extensions.length(); j++)
    {
        events.ch_event.extensions[j] = att_3->event_prop.ch_event.extensions[j];
    }

    events.per_event.period = att_3->event_prop.per_event.period;
    events.per_event.extensions.resize(att_3->event_prop.per_event.extensions.length());
    for(unsigned int j = 0; j < att_3->event_prop.per_event.extensions.length(); j++)
    {
        events.per_event.extensions[j] = att_3->event_prop.per_event.extensions[j];
    }

    events.arch_event.archive_abs_change = att_3->event_prop.arch_event.abs_change;
    events.arch_event.archive_rel_change = att_3->event_prop.arch_event.rel_change;
    events.arch_event.archive_period = att_3->event_prop.arch_event.period;
    events.arch_event.extensions.resize(att_3->event_prop.arch_event.extensions.length());
    for(unsigned int j = 0; j < att_3->event_prop.arch_event.extensions.length(); j++)
    {
        events.arch_event.extensions[j] = att_3->event_prop.arch_event.extensions[j];
    }

    return *this;
}

//+---------------------------------------------------------------------------------------------------------------
//
// function :
//         operator overloading :     =
//
// description :
//        Assignement operator for the AttributeInfoEx class from a AttributeConfig_5 pointer
//
//-----------------------------------------------------------------------------------------------------------------

AttributeInfoEx &AttributeInfoEx::operator=(const AttributeConfig_5 *att_5)
{
    name = att_5->name;
    writable = att_5->writable;
    data_format = att_5->data_format;
    data_type = att_5->data_type;
    max_dim_x = att_5->max_dim_x;
    max_dim_y = att_5->max_dim_y;
    description = att_5->description;
    label = att_5->label;
    unit = att_5->unit;
    standard_unit = att_5->standard_unit;
    display_unit = att_5->display_unit;
    format = att_5->format;
    min_value = att_5->min_value;
    max_value = att_5->max_value;
    min_alarm = att_5->att_alarm.min_alarm;
    max_alarm = att_5->att_alarm.max_alarm;
    writable_attr_name = att_5->writable_attr_name;
    extensions.resize(att_5->sys_extensions.length());
    for(unsigned int j = 0; j < att_5->sys_extensions.length(); j++)
    {
        extensions[j] = att_5->sys_extensions[j];
    }
    disp_level = att_5->level;
    root_attr_name = att_5->root_attr_name;
    if(!att_5->memorized)
    {
        memorized = NONE;
    }
    else
    {
        if(!att_5->mem_init)
        {
            memorized = MEMORIZED;
        }
        else
        {
            memorized = MEMORIZED_WRITE_INIT;
        }
    }
    enum_labels.clear();
    for(unsigned int j = 0; j < att_5->enum_labels.length(); j++)
    {
        enum_labels.emplace_back(att_5->enum_labels[j].in());
    }

    alarms.min_alarm = att_5->att_alarm.min_alarm;
    alarms.max_alarm = att_5->att_alarm.max_alarm;
    alarms.min_warning = att_5->att_alarm.min_warning;
    alarms.max_warning = att_5->att_alarm.max_warning;
    alarms.delta_t = att_5->att_alarm.delta_t;
    alarms.delta_val = att_5->att_alarm.delta_val;
    alarms.extensions.resize(att_5->att_alarm.extensions.length());
    for(unsigned int j = 0; j < att_5->att_alarm.extensions.length(); j++)
    {
        alarms.extensions[j] = att_5->att_alarm.extensions[j];
    }

    events.ch_event.abs_change = att_5->event_prop.ch_event.abs_change;
    events.ch_event.rel_change = att_5->event_prop.ch_event.rel_change;
    events.ch_event.extensions.resize(att_5->event_prop.ch_event.extensions.length());
    for(unsigned int j = 0; j < att_5->event_prop.ch_event.extensions.length(); j++)
    {
        events.ch_event.extensions[j] = att_5->event_prop.ch_event.extensions[j];
    }

    events.per_event.period = att_5->event_prop.per_event.period;
    events.per_event.extensions.resize(att_5->event_prop.per_event.extensions.length());
    for(unsigned int j = 0; j < att_5->event_prop.per_event.extensions.length(); j++)
    {
        events.per_event.extensions[j] = att_5->event_prop.per_event.extensions[j];
    }

    events.arch_event.archive_abs_change = att_5->event_prop.arch_event.abs_change;
    events.arch_event.archive_rel_change = att_5->event_prop.arch_event.rel_change;
    events.arch_event.archive_period = att_5->event_prop.arch_event.period;
    events.arch_event.extensions.resize(att_5->event_prop.arch_event.extensions.length());
    for(unsigned int j = 0; j < att_5->event_prop.arch_event.extensions.length(); j++)
    {
        events.arch_event.extensions[j] = att_5->event_prop.arch_event.extensions[j];
    }

    return *this;
}

//+----------------------------------------------------------------------------------------------------------------
//
// function :
//         operator overloading :     <<
//
// description :
//        Friend function to ease printing instance of the AttributeInfo class
//
//-----------------------------------------------------------------------------------------------------------------

std::ostream &operator<<(std::ostream &o_str, const AttributeInfoEx &p)
{
    //
    // Print all these properties
    //

    o_str << "Attribute name = " << p.name << std::endl;
    o_str << "Attribute data_type = " << (CmdArgType) p.data_type << std::endl;

    if(p.data_type == Tango::DEV_ENUM)
    {
        for(size_t loop = 0; loop < p.enum_labels.size(); loop++)
        {
            o_str << "\tEnumeration label = " << p.enum_labels[loop] << std::endl;
        }
    }

    o_str << "Attribute data_format = " << p.data_format;
    switch(p.data_format)
    {
    case Tango::SPECTRUM:
        o_str << ", max_dim_x = " << p.max_dim_x << std::endl;
        break;

    case Tango::IMAGE:
        o_str << ", max_dim_x = " << p.max_dim_x << ", max_dim_y = " << p.max_dim_y << std::endl;
        break;
    case Tango::SCALAR:
        // do nothing
        break;
    default:
        TANGO_ASSERT_ON_DEFAULT(p.data_format);
    }

    o_str << "Attribute writable type = " << p.writable << std::endl;

    if((p.writable == Tango::WRITE) || (p.writable == Tango::READ_WRITE))
    {
        switch(p.memorized)
        {
        case NOT_KNOWN:
            o_str << "Device/Appli too old to send/receive attribute memorisation data" << std::endl;
            break;

        case NONE:
            o_str << "Attribute is not memorized" << std::endl;
            break;

        case MEMORIZED:
            o_str << "Attribute is memorized" << std::endl;
            break;

        case MEMORIZED_WRITE_INIT:
            o_str << "Attribute is memorized and the memorized value is written at initialisation" << std::endl;
            break;

        default:
            TANGO_ASSERT_ON_DEFAULT(p.memorized);
        }
    }

    o_str << "Attribute display level = " << p.disp_level << std::endl;

    o_str << "Attribute writable_attr_name = " << p.writable_attr_name << std::endl;
    if(!p.root_attr_name.empty())
    {
        o_str << "Root attribute name = " << p.root_attr_name << std::endl;
    }
    o_str << "Attribute label = " << p.label << std::endl;
    o_str << "Attribute description = " << p.description << std::endl;
    o_str << "Attribute unit = " << p.unit;
    o_str << ", standard unit = " << p.standard_unit;
    o_str << ", display unit = " << p.display_unit << std::endl;
    o_str << "Attribute format = " << p.format << std::endl;
    o_str << "Attribute min value = " << p.min_value << std::endl;
    o_str << "Attribute max value = " << p.max_value << std::endl;

    unsigned int i;
    for(i = 0; i < p.extensions.size(); i++)
    {
        o_str << "Attribute extensions " << i + 1 << " = " << p.extensions[i] << std::endl;
    }

    o_str << "Attribute alarm : min alarm = ";
    p.alarms.min_alarm.empty() ? o_str << "Not specified" : o_str << p.alarms.min_alarm;
    o_str << std::endl;

    o_str << "Attribute alarm : max alarm = ";
    p.alarms.max_alarm.empty() ? o_str << "Not specified" : o_str << p.alarms.max_alarm;
    o_str << std::endl;

    o_str << "Attribute warning alarm : min warning = ";
    p.alarms.min_warning.empty() ? o_str << "Not specified" : o_str << p.alarms.min_warning;
    o_str << std::endl;

    o_str << "Attribute warning alarm : max warning = ";
    p.alarms.max_warning.empty() ? o_str << "Not specified" : o_str << p.alarms.max_warning;
    o_str << std::endl;

    o_str << "Attribute rds alarm : delta time = ";
    p.alarms.delta_t.empty() ? o_str << "Not specified" : o_str << p.alarms.delta_t;
    o_str << std::endl;

    o_str << "Attribute rds alarm : delta value = ";
    p.alarms.delta_val.empty() ? o_str << "Not specified" : o_str << p.alarms.delta_val;
    o_str << std::endl;

    for(i = 0; i < p.alarms.extensions.size(); i++)
    {
        o_str << "Attribute alarm extensions " << i + 1 << " = " << p.alarms.extensions[i] << std::endl;
    }

    o_str << "Attribute event : change event absolute change = ";
    p.events.ch_event.abs_change.empty() ? o_str << "Not specified" : o_str << p.events.ch_event.abs_change;
    o_str << std::endl;

    o_str << "Attribute event : change event relative change = ";
    p.events.ch_event.rel_change.empty() ? o_str << "Not specified" : o_str << p.events.ch_event.rel_change;
    o_str << std::endl;

    for(i = 0; i < p.events.ch_event.extensions.size(); i++)
    {
        o_str << "Attribute alarm : change event extensions " << i + 1 << " = " << p.events.ch_event.extensions[i]
              << std::endl;
    }

    o_str << "Attribute event : periodic event period = ";
    p.events.per_event.period.empty() ? o_str << "Not specified" : o_str << p.events.per_event.period;
    o_str << std::endl;

    for(i = 0; i < p.events.per_event.extensions.size(); i++)
    {
        o_str << "Attribute alarm : periodic event extensions " << i + 1 << " = " << p.events.per_event.extensions[i]
              << std::endl;
    }

    o_str << "Attribute event : archive event absolute change = ";
    p.events.arch_event.archive_abs_change.empty() ? o_str << "Not specified"
                                                   : o_str << p.events.arch_event.archive_abs_change;
    o_str << std::endl;

    o_str << "Attribute event : archive event relative change = ";
    p.events.arch_event.archive_rel_change.empty() ? o_str << "Not specified"
                                                   : o_str << p.events.arch_event.archive_rel_change;
    o_str << std::endl;

    o_str << "Attribute event : archive event period = ";
    p.events.arch_event.archive_period.empty() ? o_str << "Not specified" : o_str << p.events.arch_event.archive_period;
    o_str << std::endl;

    for(i = 0; i < p.events.arch_event.extensions.size(); i++)
    {
        if(i == 0)
        {
            o_str << std::endl;
        }
        o_str << "Attribute alarm : archive event extensions " << i + 1 << " = " << p.events.arch_event.extensions[i];
        if(i != p.events.arch_event.extensions.size() - 1)
        {
            o_str << std::endl;
        }
    }

    return o_str;
}

//+----------------------------------------------------------------------------------------------------------------
//
// function :
//         operator overloading :     <<
//
// description :
//        Friend function to ease printing instance of the PipeInfo class
//
//-----------------------------------------------------------------------------------------------------------------

std::ostream &operator<<(std::ostream &o_str, const PipeInfo &p)
{
    //
    // Print all these properties
    //

    o_str << "Pipe name = " << p.name << std::endl;
    o_str << "Pipe label = " << p.label << std::endl;
    o_str << "Pipe description = " << p.description << std::endl;

    o_str << "Pipe writable type = ";
    if(p.writable == PIPE_READ)
    {
        o_str << "READ" << std::endl;
    }
    else
    {
        o_str << "READ_WRITE" << std::endl;
    }

    o_str << "Pipe display level = " << p.disp_level << std::endl;

    unsigned int i;
    for(i = 0; i < p.extensions.size(); i++)
    {
        if(i == 0)
        {
            o_str << std::endl;
        }
        o_str << "Pipe extensions " << i + 1 << " = " << p.extensions[i] << std::endl;
    }

    return o_str;
}

} // namespace Tango
