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

#ifndef TANGO_CLIENT_GROUPELEMENT_H
#define TANGO_CLIENT_GROUPELEMENT_H

#include <tango/client/DeviceProxy.h>
#include <tango/client/GroupAttrReplyList.h>
#include <tango/client/GroupCmdReplyList.h>
#include <tango/client/GroupReply.h>
#include <tango/client/GroupReplyList.h>

#include <vector>

namespace Tango
{

typedef std::vector<std::string> TokenList;

//=============================================================================
// class GroupElement: base class for all tango group element
//=============================================================================
// NOLINTNEXTLINE(cppcoreguidelines-virtual-class-destructor)
class GroupElement
{
    friend class Group;

  public:
    //---------------------------------------------
    //- Group management methods
    //---------------------------------------------
    //-
    virtual bool contains(const std::string &n, bool fwd = true);
    //-
    virtual DeviceProxy *get_device(const std::string &n) = 0;
    //-
    virtual DeviceProxy *get_device(long idx) = 0;
    //-
    virtual DeviceProxy *operator[](long idx) = 0;

    //---------------------------------------------
    //- a la DeviceProxy interface
    //---------------------------------------------
    //-
    virtual bool ping(bool fwd = true) = 0;
    //-
    virtual void set_timeout_millis(int tmo_ms) = 0;

    //---------------------------------------------
    //- Misc.
    //---------------------------------------------
    //-
    const std::string &get_name() const;

    //-
    std::string get_fully_qualified_name() const;

    //-
    void enable();

    //-
    void disable();

    //-
    bool is_enabled() const;

    bool name_equals(const std::string &n);
    //-
    bool name_matches(const std::string &n);
    //-
    virtual void dump(int indent_level = 0) = 0;
    //-
    virtual void dump(TangoSys_OMemStream &oms, int indent_level = 0) = 0;
    //-
    virtual bool is_connected();

  protected:
    //- ctor: creates an GroupElement named <name>
    GroupElement(const std::string &name, GroupElement *parent = nullptr);
    //- dtor
    virtual ~GroupElement();

  private:
    //- element name
    std::string name;
    //- parent element
    GroupElement *parent;
    //- enabled: true is this group member is enabled, false otherwise
    bool enabled;

    //- forbidden methods
    GroupElement();
    GroupElement(const GroupElement &);
    GroupElement &operator=(const GroupElement &);

    //- element name tokenizer
    TokenList tokenize_i(const std::string &p);

    //- element name pattern matching
    bool match_i(const std::string &p, const TokenList &tokens);

    //- element identification
    virtual bool is_device_i() = 0;
    virtual bool is_group_i() = 0;

    //- group interface
    virtual long get_size_i(bool fwd = true) = 0;

    //- element searching
    virtual GroupElement *find_i(const std::string &n, bool fwd = true);

    //- private part of the asynch command exec. impl.
    virtual long command_inout_asynch_i(const std::string &c, bool fgt, bool fwd, long ari) = 0;
    virtual long command_inout_asynch_i(const std::string &c, const DeviceData &d, bool fgt, bool fwd, long ari) = 0;
    virtual GroupCmdReplyList command_inout_reply_i(long req_id, long tmo_ms) = 0;

    //- private part of the asynch attribute(s) reading impl.
    virtual long read_attribute_asynch_i(const std::string &a, bool fwd, long ari) = 0;
    virtual GroupAttrReplyList read_attribute_reply_i(long req_id, long tmo_ms) = 0;
    virtual long read_attributes_asynch_i(const std::vector<std::string> &al, bool fwd, long ari) = 0;
    virtual GroupAttrReplyList read_attributes_reply_i(long req_id, long tmo_ms) = 0;

    //- private part of the asynch attribute writting impl.
    virtual long write_attribute_asynch_i(const DeviceAttribute &d, bool fwd, long ari) = 0;
    virtual GroupReplyList write_attribute_reply_i(long req_id, long tmo_ms) = 0;

    //- set the parent element, returns previous parent or 0 (null) if none
    GroupElement *set_parent(GroupElement *_parent);
};

//=============================================================================
// Misc. Typedefs
//=============================================================================
typedef std::vector<GroupElement *> GroupElements;
typedef GroupElements::iterator GroupElementsIterator;

} // namespace Tango

#endif /* TANGO_CLIENT_GROUPELEMENT_H */
