/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
 * Copyright (c) 2007-2009 Strasbourg University
 *
 * 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
 *
 * Author: Sebastien Vincent <vincent@clarinet.u-strasbg.fr>
 */

#ifndef IPV6_INTERFACE_ADDRESS_H
#define IPV6_INTERFACE_ADDRESS_H 

#include <stdint.h>

#include "ns3/ipv6-address.h"

namespace ns3
{

/**
 * \ingroup address
 * \ingroup ipv6
 *
 * \brief IPv6 address associated with an interface.
 */
class Ipv6InterfaceAddress
{
public:
  /**
   * \enum State_e
   * \brief State of an address associated with an interface.
   */
  enum State_e
  {
    TENTATIVE, /**< Address is tentative, no packet can be sent unless DAD finished */
    DEPRECATED, /**< Address is deprecated and should not be used */
    PREFERRED, /**< Preferred address */
    PERMANENT, /**< Permanent address */
    HOMEADDRESS, /**< Address is a HomeAddress */
    TENTATIVE_OPTIMISTIC, /**< Address is tentative but we are optimistic so we can send packet even if DAD is not yet finished */
    INVALID, /**< Invalid state (after a DAD failed) */
  };

  /**
   * \enum Scope_e
   * \brief Address scope.
   */
  enum Scope_e
  {
    HOST, /**< Localhost (::1/128) */
    LINKLOCAL, /**< Link-local address (fe80::/64) */
    GLOBAL, /**< Global address (2000::/3) */
  };

  /**
   * \brief Default constructor.
   */
  Ipv6InterfaceAddress ();

  /**
   * \brief Constructor. Prefix is 64 by default.
   * \param address the IPv6 address to set
   */
  Ipv6InterfaceAddress (Ipv6Address address);

  /**
   * \brief Constructor.
   * \param address IPv6 address to set
   * \param prefix IPv6 prefix
   */
  Ipv6InterfaceAddress (Ipv6Address address, Ipv6Prefix prefix);

  /**
   * \brief Copy constructor.
   * \param o object to copy
   */
  Ipv6InterfaceAddress (const Ipv6InterfaceAddress& o);

  /**
   * \brief Destructor.
   */
  ~Ipv6InterfaceAddress ();

  /**
   * \brief Set IPv6 address (and scope).
   * \param address IPv6 address to set
   */
  void SetAddress (Ipv6Address address);

  /**
   * \brief Get the IPv6 address.
   * \return IPv6 address
   */
  Ipv6Address GetAddress () const;

  /**
   * \brief Get the IPv6 prefix.
   * \return IPv6 prefix
   */
  Ipv6Prefix GetPrefix () const;

  /**
   * \brief Set the state.
   * \param state the state
   */
  void SetState (Ipv6InterfaceAddress::State_e state);

  /**
   * \brief Get the address state.
   * \return address state
   */
  Ipv6InterfaceAddress::State_e GetState () const;

  /**
   * \brief Set the scope.
   * \param scope the scope of address
   */
  void SetScope (Ipv6InterfaceAddress::Scope_e scope);

  /**
   * \brief Get address scope.
   * \return scope
   */
  Ipv6InterfaceAddress::Scope_e GetScope () const;

  /**
   * \brief Checks if the address is in the same subnet.
   * \param b the address to check
   * \return true if the address is in the same subnet.
   */
  bool IsInSameSubnet (Ipv6Address b) const;

  /**
   * \brief Set the latest DAD probe packet UID.
   * \param uid packet uid
   */
  void SetNsDadUid (uint32_t uid);

  /**
   * \brief Get the latest DAD probe packet UID.
   * \return uid
   */
  uint32_t GetNsDadUid () const;

#if 0
  /**
   * \brief Start the DAD timer.
   * \param interface interface
   */
  void StartDadTimer (Ptr<Ipv6Interface> interface);

  /**
   * \brief Stop the DAD timer.
   */
  void StopDadTimer ();
#endif

private:
  /**
   * \brief The IPv6 address.
   */
  Ipv6Address m_address;

  /**
   * \brief The IPv6 prefix.
   */
  Ipv6Prefix m_prefix;

  /**
   * \brief State of the address.
   */
  State_e m_state;

  /**
   * \brief Scope of the address.
   */
  Scope_e m_scope;

  /**
   * \brief Equal to operator.
   *
   * \param a the first operand
   * \param b the first operand
   * \returns true if the operands are equal
   */
  friend bool operator == (Ipv6InterfaceAddress const& a, Ipv6InterfaceAddress const& b);

  /**
   * \brief Not equal to operator.
   *
   * \param a the first operand
   * \param b the first operand
   * \returns true if the operands are not equal
   */
  friend bool operator != (Ipv6InterfaceAddress const& a, Ipv6InterfaceAddress const& b);

  /**
   * \brief Last DAD probe packet UID.
   */
  uint32_t m_nsDadUid;
};

/**
 * \brief Stream insertion operator.
 *
 * \param os the reference to the output stream
 * \param addr the Ipv6InterfaceAddress
 * \returns the reference to the output stream
 */
std::ostream& operator<< (std::ostream& os, const Ipv6InterfaceAddress &addr);

/* follow Ipv4InterfaceAddress way, maybe not inline them */
inline bool operator == (const Ipv6InterfaceAddress& a, const Ipv6InterfaceAddress& b)
{
  return (a.m_address == b.m_address && a.m_prefix == b.m_prefix &&
          a.m_state == b.m_state && a.m_scope == b.m_scope);
}

inline bool operator != (const Ipv6InterfaceAddress& a, const Ipv6InterfaceAddress& b)
{
  return (a.m_address != b.m_address || a.m_prefix != b.m_prefix ||
          a.m_state != b.m_state || a.m_scope != b.m_scope);
}

} /* namespace ns3 */

#endif /* IPV6_INTERFACE_ADDRESS_H */

