/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
 * Copyright (c) 2004 Francisco J. Ros
 * Copyright (c) 2007 INESC Porto
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation;
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * Authors: Francisco J. Ros  <fjrm@dif.um.es>
 *          Gustavo J. A. M. Carneiro <gjc@inescporto.pt>
 */


#ifndef OLSR_STATE_H
#define OLSR_STATE_H

#include "olsr-repositories.h"

namespace ns3 {
namespace olsr {

/// \ingroup olsr
/// This class encapsulates all data structures needed for maintaining internal state of an OLSR node.
class OlsrState
{
  //  friend class Olsr;

protected:
  LinkSet m_linkSet;    //!< Link Set (\RFC{3626}, section 4.2.1).
  NeighborSet m_neighborSet;            //!< Neighbor Set (\RFC{3626}, section 4.3.1).
  TwoHopNeighborSet m_twoHopNeighborSet;        //!< 2-hop Neighbor Set (\RFC{3626}, section 4.3.2).
  TopologySet m_topologySet;    //!< Topology Set (\RFC{3626}, section 4.4).
  MprSet m_mprSet;      //!< MPR Set (\RFC{3626}, section 4.3.3).
  MprSelectorSet m_mprSelectorSet;      //!< MPR Selector Set (\RFC{3626}, section 4.3.4).
  DuplicateSet m_duplicateSet;  //!< Duplicate Set (\RFC{3626}, section 3.4).
  IfaceAssocSet m_ifaceAssocSet;        //!< Interface Association Set (\RFC{3626}, section 4.1).
  AssociationSet m_associationSet; //!<	Association Set (\RFC{3626}, section12.2). Associations obtained from HNA messages generated by other nodes.
  Associations m_associations;  //!< The node's local Host Network Associations that will be advertised using HNA messages.

public:
  OlsrState ()
  {
  }

  // MPR selector

  /**
   * Gets the MPR selectors.
   * \returns The MPR selectors.
   */
  const MprSelectorSet & GetMprSelectors () const
  {
    return m_mprSelectorSet;
  }

  /**
   * Finds a MPR selector tuple.
   * \param mainAddr The MPR selector main address.
   * \returns The MPR selector, if found. Else it returns a null pointer.
   */
  MprSelectorTuple* FindMprSelectorTuple (const Ipv4Address &mainAddr);

  /**
   * Erases a MPR selector tuple.
   * \param tuple The MPR selector tuple.
   */
  void EraseMprSelectorTuple (const MprSelectorTuple &tuple);

  /**
   * Erases all MPR selector tuples belonging to the same address.
   * \param mainAddr The MPR selector main address.
   */
  void EraseMprSelectorTuples (const Ipv4Address &mainAddr);

  /**
   * Inserts a MPR selector tuple
   * \param tuple The MPR selector tuple.
   */
  void InsertMprSelectorTuple (const MprSelectorTuple &tuple);

  /**
   * Prints the MPR selector sets.
   * \return a string with the output data.
   */
  std::string PrintMprSelectorSet () const;

  // Neighbor

  /**
   * Gets the neighbor set.
   * \returns The neighbor set.
   */
  const NeighborSet & GetNeighbors () const
  {
    return m_neighborSet;
  }
  /**
   * Gets the neighbor set.
   * \returns The neighbor set.
   */
  NeighborSet & GetNeighbors ()
  {
    return m_neighborSet;
  }

  /**
   * Finds a neighbor tuple.
   * \param mainAddr The neighbor tuple main address.
   * \returns The neighbor tuple, if found. Else it returns a null pointer.
   */
  NeighborTuple* FindNeighborTuple (const Ipv4Address &mainAddr);

  /**
   * Finds a symmetrical neighbor tuple.
   * \param mainAddr The neighbor tuple main address.
   * \returns The neighbor tuple, if found. Else it returns a null pointer.
   */
  const NeighborTuple* FindSymNeighborTuple (const Ipv4Address &mainAddr) const;

  /**
   * Finds a neighbor tuple.
   * \param mainAddr The neighbor tuple main address.
   * \param willingness The neighbor willingness.
   * \returns The neighbor tuple, if found. Else it returns a null pointer.
   */
  NeighborTuple* FindNeighborTuple (const Ipv4Address &mainAddr,
                                    uint8_t willingness);

  /**
   * Erases a neighbor tuple.
   * \param neighborTuple The neighbor tuple.
   */
  void EraseNeighborTuple (const NeighborTuple &neighborTuple);
  /**
   * Erases a neighbor tuple.
   * \param mainAddr The neighbor tuple main address.
   */
  void EraseNeighborTuple (const Ipv4Address &mainAddr);

  /**
   * Inserts a neighbor tuple.
   * \param tuple The neighbor tuple.
   */
  void InsertNeighborTuple (const NeighborTuple &tuple);

  // Two-hop neighbor

  /**
   * Gets the 2-hop neighbor set.
   * \returns The 2-hop neighbor set.
   */
  const TwoHopNeighborSet & GetTwoHopNeighbors () const
  {
    return m_twoHopNeighborSet;
  }
  /**
   * Gets the 2-hop neighbor set.
   * \returns The 2-hop neighbor set.
   */
  TwoHopNeighborSet & GetTwoHopNeighbors ()
  {
    return m_twoHopNeighborSet;
  }

  /**
   * Finds a 2-hop neighbor tuple.
   * \param neighbor The neighbor main address.
   * \param twoHopNeighbor The 2-hop neighbor main address.
   * \returns The 2-hop neighbor tuple, if found. Else it returns a null pointer.
   */
  TwoHopNeighborTuple* FindTwoHopNeighborTuple (const Ipv4Address &neighbor,
                                                const Ipv4Address &twoHopNeighbor);

  /**
   * Erases a 2-hop neighbor tuple.
   * \param tuple The 2-hop neighbor tuple.
   */
  void EraseTwoHopNeighborTuple (const TwoHopNeighborTuple &tuple);
  /**
   * Erases the 2-hop neighbor tuples with the same 1-hop neighbor.
   * \param neighbor The neighbor address.
   */
  void EraseTwoHopNeighborTuples (const Ipv4Address &neighbor);
  /**
   * Erases the 2-hop neighbor tuples with matching predicates.
   * \param neighbor The neighbor address.
   * \param twoHopNeighbor The 2-hop neighbor main address.
   */
  void EraseTwoHopNeighborTuples (const Ipv4Address &neighbor,
                                  const Ipv4Address &twoHopNeighbor);
  /**
   * Inserts a 2-hop neighbor tuple.
   * \param tuple The 2-hop neighbor tuple.
   */
  void InsertTwoHopNeighborTuple (const TwoHopNeighborTuple &tuple);

  // MPR

  /**
   * Checks if there's an MPR with a specific address.
   * \param address The address to test.
   * \return True if a MPR with the specified address exists.
   */
  bool FindMprAddress (const Ipv4Address &address);

  /**
   * Sets the MPR set to the one specified.
   * \param mprSet The new MPR set.
   */
  void SetMprSet (MprSet mprSet);

  /**
   * Gets the MPR set.
   * \return The MPR set.
   */
  MprSet GetMprSet () const;

  // Duplicate

  /**
   * Finds a duplicate tuple.
   * \param address The duplicate tuple address.
   * \param sequenceNumber The duplicate tuple sequence number.
   * \returns The duplicate tuple, or a null pointer if no match.
   */
  DuplicateTuple* FindDuplicateTuple (const Ipv4Address &address,
                                      uint16_t sequenceNumber);

  /**
   * Erases a duplicate tuple.
   * \param tuple The tuple to erase.
   */
  void EraseDuplicateTuple (const DuplicateTuple &tuple);
  /**
   * Inserts a duplicate tuple.
   * \param tuple The tuple to insert.
   */
  void InsertDuplicateTuple (const DuplicateTuple &tuple);

  // Link

  /**
   * Gets the Link set.
   * \return The Link set.
   */
  const LinkSet & GetLinks () const
  {
    return m_linkSet;
  }
  /**
   * Finds a link tuple.
   * \param ifaceAddr The interface address of the link.
   * \returns The link tuple, or a null pointer if no match.
   */
  LinkTuple* FindLinkTuple (const Ipv4Address &ifaceAddr);
  /**
   * Finds a symmetrical link tuple.
   * \param ifaceAddr The interface address of the link.
   * \param time The time at which the link should be considered symmetrical.
   * \returns The link tuple, or a null pointer if no match.
   */
  LinkTuple* FindSymLinkTuple (const Ipv4Address &ifaceAddr, Time time);
  /**
   * Erases a link tuple.
   * \param tuple The tuple to erase.
   */
  void EraseLinkTuple (const LinkTuple &tuple);
  /**
   * Inserts a link tuple.
   * \param tuple The tuple to insert.
   * \returns A reference to the inserted tuple.
   */
  LinkTuple& InsertLinkTuple (const LinkTuple &tuple);

  // Topology

  /**
   * Gets the topology set.
   * \returns The topology set.
   */
  const TopologySet & GetTopologySet () const
  {
    return m_topologySet;
  }
  /**
   * Finds a topology tuple.
   * \param destAddr The destination address.
   * \param lastAddr The address of the node previous to the destination.
   * \returns The topology tuple, or a null pointer if no match.
   */
  TopologyTuple* FindTopologyTuple (const Ipv4Address &destAddr,
                                    const Ipv4Address &lastAddr);
  /**
   * Finds a topology tuple.
   * \param lastAddr The address of the node previous to the destination.
   * \param ansn The Advertised Neighbor Sequence Number.
   * \returns The topology tuple, or a null pointer if no match.
   */
  TopologyTuple* FindNewerTopologyTuple (const Ipv4Address &lastAddr,
                                         uint16_t ansn);
  /**
   * Erases a topology tuple.
   * \param tuple The tuple to erase.
   */
  void EraseTopologyTuple (const TopologyTuple &tuple);
  /**
   * Erases a topology tuple.
   * \param lastAddr The address of the node previous to the destination.
   * \param ansn The Advertised Neighbor Sequence Number.
   */
  void EraseOlderTopologyTuples (const Ipv4Address &lastAddr,
                                 uint16_t ansn);
  /**
   * Inserts a topology tuple.
   * \param tuple The tuple to insert.
   */
  void InsertTopologyTuple (const TopologyTuple &tuple);

  // Interface association

  /**
   * Gets the interface association set.
   * \returns The interface association set.
   */
  const IfaceAssocSet & GetIfaceAssocSet () const
  {
    return m_ifaceAssocSet;
  }
  /**
   * Gets a mutable reference to the interface association set.
   * \returns The interface association set.
   */
  IfaceAssocSet & GetIfaceAssocSetMutable ()
  {
    return m_ifaceAssocSet;
  }

  /**
   * Finds a interface association tuple.
   * \param ifaceAddr The interface address.
   * \returns The interface association  tuple, or a null pointer if no match.
   */
  IfaceAssocTuple* FindIfaceAssocTuple (const Ipv4Address &ifaceAddr);
  /**
   * Finds a interface association tuple.
   * \param ifaceAddr The interface address.
   * \returns The interface association  tuple, or a null pointer if no match.
   */
  const IfaceAssocTuple* FindIfaceAssocTuple (const Ipv4Address &ifaceAddr) const;
  /**
   * Erases a interface association tuple.
   * \param tuple The tuple to erase.
   */
  void EraseIfaceAssocTuple (const IfaceAssocTuple &tuple);
  /**
   * Inserts a interface association tuple.
   * \param tuple The tuple to insert.
   */
  void InsertIfaceAssocTuple (const IfaceAssocTuple &tuple);

  // Host-Network Association
  /**
   * Gets the association set known to the node.
   * \returns The association set known to the node.
   */
  const AssociationSet & GetAssociationSet () const  // Associations known to the node
  {
    return m_associationSet;
  }

  /**
   * Gets the association set the node has.
   * \returns The association set the node has.
   */
  const Associations & GetAssociations () const  // Set of associations that the node has
  {
    return m_associations;
  }

  /**
   * Finds an association tuple.
   * \param gatewayAddr The gateway address.
   * \param networkAddr The network address.
   * \param netmask The network mask.
   * \returns The association  tuple, or a null pointer if no match.
   */
  AssociationTuple* FindAssociationTuple (const Ipv4Address &gatewayAddr, \
                                          const Ipv4Address &networkAddr, \
                                          const Ipv4Mask &netmask);
  /**
   * Erases a known association tuple.
   * \param tuple The tuple to erase.
   */
  void EraseAssociationTuple (const AssociationTuple &tuple);
  /**
   * Inserts a known association tuple.
   * \param tuple The tuple to insert.
   */
  void InsertAssociationTuple (const AssociationTuple &tuple);
  /**
   * Erases an association.
   * \param tuple The tuple to erase.
   */
  void EraseAssociation (const Association &tuple);
  /**
   * Inserts an association tuple.
   * \param tuple The tuple to insert.
   */
  void InsertAssociation (const Association &tuple);

  /**
   * Returns a vector of all interfaces of a given neighbor, with the
   * exception of the "main" one.
   * \param neighborMainAddr The neighbor main address
   * \returns A container of the neighbor addresses (excluding the main one).
   */
  std::vector<Ipv4Address>
  FindNeighborInterfaces (const Ipv4Address &neighborMainAddr) const;

};

}
}  // namespace olsr,ns3

#endif /* OLSR_STATE_H */
