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

#include <tango/server/MultiClassPipe.h>

#include <tango/client/Database.h>
#include <tango/server/DeviceClass.h>
#include <tango/server/Pipe.h>
#include <tango/server/Util.h>

namespace Tango
{

//+-------------------------------------------------------------------------------------------------------------------
//
// method :
//        MultiClassPipe::MultiClassPipe
//
// description :
//        Constructor for the MultiClassPipe class
//
//--------------------------------------------------------------------------------------------------------------------

MultiClassPipe::MultiClassPipe()
{
    TANGO_LOG_DEBUG << "Entering MultiClassPipe constructor" << std::endl;
}

MultiClassPipe::~MultiClassPipe() = default;

//+-------------------------------------------------------------------------------------------------------------------
//
// method :
//        MultiClassPipe::init_class_pipe
//
// description :
//        Ask the database for properties defined at class level and build the ClassPipe object for each pipe
//        with defined properties
//
// argument :
//        in :
//            - cl_ptr : The device class object pointer
//
//-------------------------------------------------------------------------------------------------------------------

void MultiClassPipe::init_class_pipe(DeviceClass *cl_ptr)
{
    TANGO_LOG_DEBUG << "Entering MultiClassPipe::init_class_pipe" << std::endl;

    Tango::Util *tg = Tango::Util::instance();

    std::vector<Pipe *> &pi_list = cl_ptr->get_pipe_list();
    size_t nb_pipe = pi_list.size();

    //
    // Get class attribute(s) properties stored in DB. No need to implement a retry here (in case of db server restart)
    // because the db reconnection is forced by the get_property call executed during xxxClass construction
    // before we reach this code.
    //

    if((nb_pipe != 0) && (Tango::Util::instance()->use_db()))
    {
        size_t i;
        Tango::DbData db_list;
        std::string &class_name = cl_ptr->get_name();
        size_t nb_db_requested_pipe = 0;

        //
        // Ask for class default prop in DB only for pipe with label or desc not already set to some user default value
        //

        for(i = 0; i < nb_pipe; i++)
        {
            Pipe *pi_ptr = pi_list[i];
            std::string &pi_name = pi_ptr->get_name();
            if(pi_ptr->get_label() == pi_name || pi_ptr->get_desc() == DescNotSpec)
            {
                db_list.emplace_back(pi_name);
                nb_db_requested_pipe++;
            }
        }

        try
        {
            tg->get_database()->get_class_pipe_property(class_name, db_list, tg->get_db_cache());
        }
        catch(Tango::DevFailed &e)
        {
            std::stringstream ss;
            ss << "Can't get class pipe properties for class " << class_name;

            TANGO_RETHROW_EXCEPTION(e, API_DatabaseAccess, ss.str());
        }

        //
        // Sort property for each pipe
        //

        long ind = 0;
        for(i = 0; i < nb_db_requested_pipe; i++)
        {
            std::vector<PipeProperty> prop_list;

            std::string pipe_name = db_list[ind].name;
            long nb_prop = 0;
            db_list[ind] >> nb_prop;

            ind++;
            for(long j = 0; j < nb_prop; j++)
            {
                if(db_list[ind].size() > 1)
                {
                    std::string tmp(db_list[ind].value_string[0]);
                    long nb = db_list[ind].size();
                    for(int k = 1; k < nb; k++)
                    {
                        tmp = tmp + " ";
                        tmp = tmp + db_list[ind].value_string[k];
                    }
                    prop_list.emplace_back(db_list[ind].name, tmp);
                }
                else
                {
                    prop_list.emplace_back(db_list[ind].name, db_list[ind].value_string[0]);
                }
                ind++;
            }

            if(nb_prop != 0)
            {
                pipe_prop_list.insert({pipe_name, prop_list});
            }
        }
    }

    TANGO_LOG_DEBUG << "Leaving MultiClassPipe::init_class_pipe" << std::endl;
}

//+-------------------------------------------------------------------------------------------------------------------
//
// method :
//        MultiClassPipe::get_prop_list
//
// description :
//        Get list of pipe property (defined at class level) for the pipe specified as input arg
//
// argument :
//         in :
//            - pipe_name : The pipe name
//
// return :
//        Reference to the vector of pipe properties or throw an exception if the pipe is not found
//
//--------------------------------------------------------------------------------------------------------------------

std::vector<Tango::PipeProperty> &MultiClassPipe::get_prop_list(const std::string &pipe_name)
{
    std::map<std::string, std::vector<PipeProperty>>::iterator ite;
    ite = pipe_prop_list.find(pipe_name);
    if(ite == pipe_prop_list.end())
    {
        std::stringstream ss;
        ss << "Pipe " << pipe_name << " not found in class pipe(s) properties" << std::ends;

        TANGO_THROW_EXCEPTION(API_PipeNotFound, ss.str());
    }

    return ite->second;
}

} // namespace Tango
