/*
 * Copyright (c) 2010 Universita' di Firenze, Italy
 *
 * SPDX-License-Identifier: GPL-2.0-only
 *
 * Author: Tommaso Pecorella (tommaso.pecorella@unifi.it)
 * Author: Valerio Sartini (valesar@gmail.com)
 */

#ifndef TOPOLOGY_READER_H
#define TOPOLOGY_READER_H

#include "ns3/node.h"
#include "ns3/object.h"

#include <list>
#include <map>
#include <string>

/**
 * @file
 * @ingroup topology
 * ns3::TopologyReader declaration.
 */

namespace ns3
{

class NodeContainer;

/**
 * @ingroup topology
 *
 * @brief Interface for input file readers management.
 *
 * This interface perform the shared tasks among all possible input file readers.
 * Each different file format is handled by its own topology reader.
 */
class TopologyReader : public Object
{
  public:
    /**
     * @brief Inner class holding the details about a link between two nodes.
     *
     * The link is not described in terms of technology. Rather it is only stating
     * an association between two nodes. The nodes are characterized also with names
     * reflecting how the nodes are called in the original topology file.
     */
    class Link
    {
      public:
        /**
         * @brief Constant iterator to scan the map of link attributes.
         */
        typedef std::map<std::string, std::string>::const_iterator ConstAttributesIterator;

        /**
         * @brief Constructor.
         * @param [in] fromPtr Ptr to the node the link is originating from.
         * @param [in] fromName Name of the node the link is originating from.
         * @param [in] toPtr Ptr to the node the link is directed to.
         * @param [in] toName Name of the node the link is directed to.
         */
        Link(Ptr<Node> fromPtr,
             const std::string& fromName,
             Ptr<Node> toPtr,
             const std::string& toName);

        /**
         * @brief Returns a Ptr<Node> to the "from" node of the link.
         * @return A Ptr<Node> to the "from" node of the link.
         */
        Ptr<Node> GetFromNode() const;
        /**
         * @brief Returns the name of the "from" node of the link.
         * @return The name of the "from" node of the link.
         */
        std::string GetFromNodeName() const;
        /**
         * @brief Returns a Ptr<Node> to the "to" node of the link.
         * @return A Ptr<Node> to the "to" node of the link.
         */
        Ptr<Node> GetToNode() const;
        /**
         * @brief Returns the name of the "to" node of the link.
         * @return The name of the "to" node of the link.
         */
        std::string GetToNodeName() const;
        /**
         * @brief Returns the value of a link attribute. The attribute must exist.
         * @param [in] name the name of the attribute.
         * @return The value of the attribute.
         */
        std::string GetAttribute(const std::string& name) const;
        /**
         * @brief Returns the value of a link attribute.
         * @param [in] name The name of the attribute.
         * @param [out] value The value of the attribute.
         *
         * @return True if the attribute was defined, false otherwise.
         */
        bool GetAttributeFailSafe(const std::string& name, std::string& value) const;
        /**
         * @brief Sets an arbitrary link attribute.
         * @param [in] name The name of the attribute.
         * @param [in] value The value of the attribute.
         */
        void SetAttribute(const std::string& name, const std::string& value);
        /**
         * @brief Returns an iterator to the begin of the attributes.
         * @return A const iterator to the first attribute of a link.
         */
        ConstAttributesIterator AttributesBegin() const;
        /**
         * @brief Returns an iterator to the end of the attributes.
         * @return A const iterator to the last attribute of a link.
         */
        ConstAttributesIterator AttributesEnd() const;

      private:
        Link();
        std::string m_fromName; //!< Name of the node the links originates from.
        Ptr<Node> m_fromPtr;    //!< The node the links originates from.
        std::string m_toName;   //!< Name of the node the links is directed to.
        Ptr<Node> m_toPtr;      //!< The node the links is directed to.
        std::map<std::string, std::string>
            m_linkAttr; //!< Container of the link attributes (if any).
    };

    /**
     * @brief Constant iterator to the list of the links.
     */
    typedef std::list<Link>::const_iterator ConstLinksIterator;

    /**
     * @brief Get the type ID.
     * @return The object TypeId.
     */
    static TypeId GetTypeId();

    TopologyReader();
    ~TopologyReader() override;

    // Delete copy constructor and assignment operator to avoid misuse
    TopologyReader(const TopologyReader&) = delete;
    TopologyReader& operator=(const TopologyReader&) = delete;

    /**
     * @brief Main topology reading function.
     *
     * The data is parsed and the results are returned in the passed lists.
     * The rationale behind this choice is to allow non-progressive node IDs
     * in the topology files, as well as to separate the topology
     * reader from the choices about actual IP number assignment and
     * kind of links between nodes.
     *
     * @return The container of the nodes created (or null if there was an error).
     */
    virtual NodeContainer Read() = 0;

    /**
     * @brief Sets the input file name.
     * @param [in] fileName The input file name.
     */
    void SetFileName(const std::string& fileName);

    /**
     * @brief Returns the input file name.
     * @return The input file name.
     */
    std::string GetFileName() const;

    /**
     * @brief Returns an iterator to the the first link in this block.
     * @return A const iterator to the first link in this block.
     */
    ConstLinksIterator LinksBegin() const;

    /**
     * @brief Returns an iterator to the the last link in this block.
     * @return A const iterator to the last link in this block.
     */
    ConstLinksIterator LinksEnd() const;

    /**
     * @brief Returns the number of links in this block.
     * @return The number of links in this block.
     */
    int LinksSize() const;

    /**
     * @brief Checks if the block contains any links.
     * @return True if there are no links in this block, false otherwise.
     */
    bool LinksEmpty() const;

    /**
     * @brief Adds a link to the topology.
     * @param link [in] The link to be added.
     */
    void AddLink(Link link);

  private:
    /**
     * The name of the input file.
     */
    std::string m_fileName;

    /**
     * The container of the links between the nodes.
     */
    std::list<Link> m_linksList;

    // end class TopologyReader
};

// end namespace ns3
}; // namespace ns3

#endif /* TOPOLOGY_READER_H */
