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

#include <tango/client/GroupElement.h>

#include <algorithm>

namespace Tango
{

//=============================================================================
// class GroupElement
//=============================================================================
GroupElement::GroupElement(const std::string &_name, GroupElement *_parent) :
    name(_name),
    parent(_parent),
    enabled(true)
{
    //- noop ctor
}

//-----------------------------------------------------------------------------
GroupElement::~GroupElement()
{
    //- noop dtor
}

//-----------------------------------------------------------------------------
bool GroupElement::contains(const std::string &n, TANGO_UNUSED(bool fwd))
{
    std::string::size_type pos = n.find('*', 0);
    return (pos == std::string::npos) ? name_equals(n) : name_matches(n);
}

//-----------------------------------------------------------------------------
GroupElement *GroupElement::find_i(const std::string &n, TANGO_UNUSED(bool fwd))
{
    return name_equals(n) ? this : nullptr;
}

//-----------------------------------------------------------------------------
TokenList GroupElement::tokenize_i(const std::string &p)
{
#ifdef _LOCAL_DEBUGGING
    TANGO_LOG << "\t|- Group::tokenize::pattern [" << p << "]" << std::endl;
#endif
    int done = 0;
    std::string token;
    std::string::size_type pos;
    std::string::size_type last_pos = 0;
    std::vector<std::string> tokens(0);
    do
    {
        pos = p.find('*', last_pos);
        if(pos != 0)
        {
            if(pos == std::string::npos)
            {
                if(last_pos >= p.size())
                {
                    break;
                }
                pos = p.size();
                done = 1;
            }
            token.assign(p.begin() + last_pos, p.begin() + pos);
            tokens.push_back(token);
        }
        last_pos = pos + 1;
    } while(done == 0);
#ifdef _LOCAL_DEBUGGING
    TANGO_LOG << "\t\t|- tokens: [";
    for(int t = 0; t < tokens.size(); t++)
    {
        TANGO_LOG << tokens[t];
        TANGO_LOG << ((t == tokens.size() - 1) ? "]" : ";");
    }
    TANGO_LOG << std::endl;
#endif
    return tokens;
}

//-----------------------------------------------------------------------------
bool GroupElement::match_i(const std::string &_p, const TokenList &tokens)
{
    unsigned int t;
    std::string p(_p);
    std::transform(p.begin(), p.end(), p.begin(), ::tolower);
#ifdef _LOCAL_DEBUGGING
    TANGO_LOG << "\t|- Group::match::pattern " << _p << std::endl;
#endif
    bool result = false;
    std::string::size_type pos;
    for(t = 0, pos = 0; t < tokens.size(); t++)
    {
        std::string token(tokens[t]);
        std::transform(token.begin(), token.end(), token.begin(), ::tolower);
        pos = p.find(token, pos);
        if(pos == std::string::npos)
        {
            break;
        }
    }
    if(t == tokens.size())
    {
        result = true;
    }
#ifdef _LOCAL_DEBUGGING
    if(result == true)
    {
        TANGO_LOG << "\t\t|- Group::match::pattern matches tokens" << std::endl;
    }
    else
    {
        TANGO_LOG << "\t\t|- Group::match::pattern does NOT match tokens" << std::endl;
    }
#endif
    return result;
}

//-----------------------------------------------------------------------------
bool GroupElement::name_matches(const std::string &n)
{
    TokenList tokens = tokenize_i(n);
    return match_i(name, tokens) || match_i(get_fully_qualified_name(), tokens);
}

//-----------------------------------------------------------------------------
bool GroupElement::name_equals(const std::string &in_name)
{
    std::string lin(in_name);
    std::transform(lin.begin(), lin.end(), lin.begin(), ::tolower);

    std::string lfqn(get_fully_qualified_name());
    std::transform(lfqn.begin(), lfqn.end(), lfqn.begin(), ::tolower);

    std::string ln(name);
    std::transform(ln.begin(), ln.end(), ln.begin(), ::tolower);

    return lin == ln || lin == lfqn;
}

//-----------------------------------------------------------------------------
GroupElement *GroupElement::set_parent(GroupElement *_parent)
{
    GroupElement *previous_parent = parent;
    parent = _parent;
    return previous_parent;
}

//-----------------------------------------------------------------------------
bool GroupElement::is_connected()
{
    return true;
}

const std::string &GroupElement::get_name() const
{
    return name;
}

//-
std::string GroupElement::get_fully_qualified_name() const
{
    if(parent != nullptr)
    {
        return parent->get_fully_qualified_name() + "." + name;
    }
    return name;
}

//-
void GroupElement::enable()
{
    enabled = true;
}

//-
void GroupElement::disable()
{
    enabled = false;
}

//-
bool GroupElement::is_enabled() const
{
    return enabled;
}

} // namespace Tango
