/*
 * SPDX-FileCopyrightText: 2011 Copyright contributors to the cppTango project
 *
 * SPDX-License-Identifier: LGPL-3.0-or-later
 */
// NOLINTBEGIN(*)

// BUG Report:
// a change of the attribute configuration setting to "Not specified"
// is lost if a DevRestart or ServerRestart is done.
// This test checks this feature for: sys/tg_test/1/double_scalar
// The setting is also lost for events.per_event.period even if a DevRestart is not done.
//
// All data are inquired, so this tests works without using the event mechanism.
//
// This program has a exit code of:
//   0   if test is passed
//   >0  if test is not passed

// tango version: 7.1 cvs head (15.10.2009)
//
// contact: georg.kasper@frm2.tum.de

#include "old_common.h"

const char *const notset = "Not specified";

// redundancy problem with:
// min_alarm, alarms.min_alarm, max_alarm and alarms.max_alarm in Tango::AttributeInfoEx
// if pedantic_test is false: Tango::AttributeInfoEx::mXX_alarm is not checked
// but Tango::AttributeInfoEx::alarms.mXX_alarm
const bool pedantic_test = false;

void setValues(Tango::AttributeInfoEx &ai, const bool doReset);
int compare(Tango::AttributeInfoEx &ai_act, Tango::AttributeInfoEx &ai_expected);
void reset_to_default(Tango::AttributeInfoEx &, string &);

int main(int argc, char **argv)
{
    if(argc != 2)
    {
        TEST_LOG << "usage: att_conf <device>" << endl;
        exit(-1);
    }

    int res = 0;
    int rc = 0;
    // string             dnUrl        = "tango://taco24:10000/sys/tg_test/1";
    string dnUrl = argv[1];
    string devnm = argv[1];
    string an = "Double_attr";
    Tango::DeviceProxy *dev = nullptr;
    Tango::DeviceProxy *adm_dev = nullptr;
    Tango::AttributeInfoListEx ail;
    Tango::AttributeInfoEx ai_orig;
    Tango::AttributeInfoEx ai_act;
    Tango::AttributeInfoEx ai_expected;
    Tango::DeviceData ddOut;
    Tango::DeviceData ddIn;

    try
    {
        dev = new Tango::DeviceProxy(dnUrl);
        adm_dev = new Tango::DeviceProxy(dev->adm_name().c_str());
        //        TEST_LOG << "connected to: " <<  dev->dev_name() << "\t";
        //        TEST_LOG << "with adm_device: " <<  dev->adm_name() << endl;
        //        TEST_LOG << "connected to: " <<  adm_dev->dev_name() << endl;

        ai_orig = dev->attribute_query(an);

        // test 1: change to numerical/string values:
        //        TEST_LOG << endl << "test 1:  change to numerical/string values" << endl;
        ai_expected = ai_orig;
        setValues(ai_expected, false);
        ail.clear();
        ail.push_back(ai_expected);
        dev->set_attribute_config(ail);
        std::this_thread::sleep_for(std::chrono::seconds(1));
        ai_act = dev->attribute_query(an);
        res = compare(ai_act, ai_expected);
        if(res != 0)
        {
            rc = 1;
            //            TEST_LOG << "test 1: FAILED, set and control numerical changes." << endl;

            ail.clear();
            ail.push_back(ai_orig);
            dev->set_attribute_config(ail);

            exit(-1);
        }
        else
        {
            TEST_LOG << "   Set and control numerical changes --> OK" << endl;
        }

        // test 2: change to: Not specified
        //        TEST_LOG << endl << "test 2:  change to Not specified" << endl;
        ai_expected = ai_orig;
        setValues(ai_expected, true);
        ail.clear();
        ail.push_back(ai_expected);
        dev->set_attribute_config(ail);
        std::this_thread::sleep_for(std::chrono::seconds(1));
        ai_act = dev->attribute_query(an);
        reset_to_default(ai_expected, an);
        res = compare(ai_act, ai_expected);
        if(res != 0)
        {
            rc = rc * 10 + 1;
            //            TEST_LOG << "test 2: FAILED, set all to '" << notset << "' control changes"  << endl;

            ail.clear();
            ail.push_back(ai_orig);
            dev->set_attribute_config(ail);

            exit(-1);
        }
        else
        {
            TEST_LOG << "   Set all to 'not specified' --> OK" << endl;
        }

        // test 3: device restart, change to numerical/string values
        //        TEST_LOG << endl << "test 3:  change to numerical/string values with device restart" << endl;
        ai_expected = ai_orig;
        setValues(ai_expected, false);
        ail.clear();
        ail.push_back(ai_expected);
        dev->set_attribute_config(ail);

        //        TEST_LOG << "         make a DevRestart" << endl;
        ddIn << devnm;
        adm_dev->set_timeout_millis(6000);
        ddOut = adm_dev->command_inout("DevRestart", ddIn);
        std::this_thread::sleep_for(std::chrono::seconds(5));
        ai_act = dev->attribute_query(an);
        res = compare(ai_act, ai_expected);
        if(res != 0)
        {
            rc = rc * 10 + 1;
            //            TEST_LOG << "test 3: FAILED, set all to numerical/string values and control changes after a
            //            DevRestart"  << endl;

            ail.clear();
            ail.push_back(ai_orig);
            dev->set_attribute_config(ail);

            exit(-1);
        }
        else
        {
            TEST_LOG << "   Set all to numerical/string values and control changes after a DevRestart --> OK" << endl;
        }

        // test 4: device restart, change to 'Not specified'
        //        TEST_LOG << endl << "test 4:  change to 'Not specified' with device restart" << endl;
        ai_expected = ai_orig;
        setValues(ai_expected, true);
        ail.clear();
        ail.push_back(ai_expected);
        dev->set_attribute_config(ail);
        //        TEST_LOG << "         make a DevRestart" << endl;
        ddIn << devnm;
        ddOut = adm_dev->command_inout("DevRestart", ddIn);
        std::this_thread::sleep_for(std::chrono::seconds(5));

        ai_act = dev->attribute_query(an);
        reset_to_default(ai_expected, an);
        res = compare(ai_act, ai_expected);
        if(res != 0)
        {
            rc = rc * 10 + 1;
            //            TEST_LOG << "test 4: FAILED, set all to '" << notset << "' control changes after a DevRestart"
            //            << endl;
        }
        else
        {
            TEST_LOG << "   Set all to 'Not specified' + control changes after a DevRestart --> OK" << endl;
        }

        // restore original setting:
        ail.clear();
        ail.push_back(ai_orig);
        dev->set_attribute_config(ail);
    }
    catch(Tango::DevFailed &ex)
    {
        rc = 9999;
        Tango::Except::print_exception(ex);
        exit(-1);
    }

    delete adm_dev;
    delete dev;

    return rc;
}

void setValues(Tango::AttributeInfoEx &ai, const bool doReset)
{
    ai.description = doReset ? notset : "description";
    ai.label = doReset ? notset : "label";
    ai.unit = doReset ? notset : "unit";
    ai.standard_unit = doReset ? notset : "11";
    ai.display_unit = doReset ? notset : "22";
    ai.format = doReset ? notset : "myformat";
    ai.min_value = doReset ? notset : "33";
    ai.max_value = doReset ? notset : "44";
    ai.min_alarm = doReset ? notset : "55"; // i have a problem with this: redundancy alarms.min_alarm
    ai.max_alarm = doReset ? notset : "66"; // i have a problem with this: redundancy alarms.max_alarm

    ai.alarms.min_alarm = doReset ? notset : "77";
    ai.alarms.max_alarm = doReset ? notset : "88";
    ai.alarms.min_warning = doReset ? notset : "99";
    ai.alarms.max_warning = doReset ? notset : "111";
    ai.alarms.delta_t = doReset ? notset : "222";
    ai.alarms.delta_val = doReset ? notset : "333";

    ai.events.ch_event.abs_change = doReset ? notset : "444";
    ai.events.ch_event.rel_change = doReset ? notset : "555";
    ai.events.per_event.period = doReset ? notset : "6666";
    ai.events.arch_event.archive_rel_change = doReset ? notset : "777";
    ai.events.arch_event.archive_abs_change = doReset ? notset : "888";
    ai.events.arch_event.archive_period = doReset ? notset : "9999";
}

int compare(Tango::AttributeInfoEx &ai_act, Tango::AttributeInfoEx &ai_expected)
{
    int rc = 0;

#define CMP(x)                                                                                   \
    if((ai_act.x != ai_expected.x))                                                              \
    {                                                                                            \
        rc = 1;                                                                                  \
        TEST_LOG << #x << ":\tBUG got: " << ai_act.x << "\texpected: " << ai_expected.x << endl; \
    }

    CMP(description);
    CMP(label);
    CMP(unit);
    CMP(standard_unit);
    CMP(display_unit);
    CMP(format);
    CMP(min_value);
    CMP(max_value);

    if(::pedantic_test)
    {
        CMP(min_alarm);
    }
    if(::pedantic_test)
    {
        CMP(max_alarm);
    }

    CMP(alarms.min_alarm);
    CMP(alarms.max_alarm);
    CMP(alarms.min_warning);
    CMP(alarms.max_warning);
    CMP(alarms.delta_t);
    CMP(alarms.delta_val);

    CMP(events.ch_event.abs_change);
    CMP(events.ch_event.rel_change);
    CMP(events.per_event.period);
    CMP(events.arch_event.archive_rel_change);
    CMP(events.arch_event.archive_abs_change);
    CMP(events.arch_event.archive_period);

    return rc;
}

void reset_to_default(Tango::AttributeInfoEx &ai, string &att_name)
{
    ai.description = "No description";
    ai.label = att_name.c_str();
    ai.unit = "";
    ai.standard_unit = "No standard unit";
    ai.display_unit = "No display unit";
    ai.format = "%6.2f";
    ai.events.per_event.period = "1000";
}

// eof

// NOLINTEND(*)
