/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
/**
 * Copyright (C) 2013 Regents of the University of California.
 * See COPYING for copyright and distribution information.
 */

#ifndef NDN_MANAGEMENT_NDND_FACE_INSTANCE_HPP
#define NDN_MANAGEMENT_NDND_FACE_INSTANCE_HPP

#include "../encoding/tlv-ndnd.hpp"
#include "../encoding/block.hpp"
#include "../name.hpp"

namespace ndn {
namespace ndnd {

/**
 * An FaceInstance holds an action and  Name prefix and other fields for an forwarding entry.
 */
class FaceInstance {
public:    
  FaceInstance(const std::string &action,
               int64_t     faceId,
               uint32_t    ipProto,
               const std::string &host,
               const std::string &port,
               const std::string &multicastInterface,
               uint32_t    multicastTtl,
               Milliseconds freshnessPeriod) 
    : action_(action)
    , faceId_(faceId)
    , ipProto_(ipProto)
    , host_(host)
    , port_(port)
    , multicastInterface_(multicastInterface)
    , multicastTtl_(multicastTtl)
    , freshnessPeriod_(freshnessPeriod)
  {
  }

  FaceInstance()
    : faceId_(-1)
    , ipProto_(-1)
    , multicastTtl_(-1)
    , freshnessPeriod_(-1)
  {
  }

  // Action
  const std::string& 
  getAction() const { return action_; }

  void 
  setAction(const std::string& action) { action_ = action; wire_.reset(); }

  // FaceID
  int64_t
  getFaceId() const { return faceId_; }

  void 
  setFaceId(int64_t faceId) { faceId_ = faceId; wire_.reset(); }

  // IPProto
  int32_t 
  getIpProto() const { return ipProto_; }

  void 
  setIpProto(int32_t ipProto) { ipProto_ = ipProto; wire_.reset(); }

  // Host
  const std::string& 
  getHost() const { return host_; }

  void 
  setHost(const std::string& host) { host_ = host; wire_.reset(); }

  // Port
  const std::string&
  getPort() const { return port_; }

  void 
  setPort(const std::string &port) { port_ = port; wire_.reset(); }

  // MulticastInterface
  const std::string& 
  getMulticastInterface() const { return multicastInterface_; }

  void 
  setMulticastInterface(const std::string& multicastInterface) { multicastInterface_ = multicastInterface; wire_.reset(); }

  // MulticastTTL
  int32_t
  getMulticastTtl() const { return multicastTtl_; }

  void 
  setMulticastTtl(int32_t multicastTtl) { multicastTtl_ = multicastTtl; wire_.reset(); }

  // Freshness
  int 
  getFreshnessPeriod() const { return freshnessPeriod_; }

  void 
  setFreshnessPeriod(int freshnessPeriod) { freshnessPeriod_ = freshnessPeriod; wire_.reset(); }

  // Wire
  inline const Block&
  wireEncode() const;
  
  inline void 
  wireDecode(const Block &wire);
  
private:
  std::string action_;
  int64_t     faceId_;
  int32_t     ipProto_;
  std::string host_;
  std::string port_;
  std::string multicastInterface_;
  int32_t     multicastTtl_;
  Milliseconds freshnessPeriod_;
  
  mutable Block wire_;
};

inline const Block&
FaceInstance::wireEncode() const
{
  if (wire_.hasWire())
    return wire_;

  // FaceInstance ::= FACE-INSTANCE-TYPE TLV-LENGTH
  //                  Action?
  //                  FaceID?
  //                  IPProto?
  //                  Host?
  //                  Port?
  //                  MulticastInterface?
  //                  MulticastTTL?
  //                  FreshnessPeriod?
  
  wire_ = Block(tlv::ndnd::FaceInstance);

  // Action
  if (!action_.empty())
    {
      wire_.push_back
        (dataBlock(tlv::ndnd::Action, action_.c_str(), action_.size()));
    }

  // FaceID
  if (faceId_ >= 0)
    {
      wire_.push_back
        (nonNegativeIntegerBlock(tlv::ndnd::FaceID, faceId_));
    }

  // IPProto
  if (ipProto_ >= 0)
    {
      wire_.push_back
        (nonNegativeIntegerBlock(tlv::ndnd::IPProto, ipProto_));
    }
  
  // Host
  if (!host_.empty())
    {
      wire_.push_back
        (dataBlock(tlv::ndnd::Host, host_.c_str(), host_.size()));
    }

  // Port
  if (!port_.empty())
    {
      wire_.push_back
        (dataBlock(tlv::ndnd::Port, port_.c_str(), port_.size()));
    }

  // MulticastInterface
  if (!multicastInterface_.empty())
    {
      wire_.push_back
        (dataBlock(tlv::ndnd::MulticastInterface, multicastInterface_.c_str(), multicastInterface_.size()));
    }

  // MulticastTTL
  if (multicastTtl_ >= 0)
    {
      wire_.push_back
        (nonNegativeIntegerBlock(tlv::ndnd::MulticastTTL, multicastTtl_));
    }

  // FreshnessPeriod
  if (freshnessPeriod_ >= 0)
    {
      wire_.push_back
        (nonNegativeIntegerBlock(Tlv::FreshnessPeriod, freshnessPeriod_));
    }
  
  wire_.encode();
  return wire_;    
}
  
inline void 
FaceInstance::wireDecode(const Block &wire)
{
  action_.clear();
  faceId_ = -1;
  ipProto_ = -1;
  host_.clear();
  port_.clear();
  multicastInterface_.clear();
  multicastTtl_ = -1;
  freshnessPeriod_ = -1;

  wire_ = wire;
  wire_.parse();

  // FaceInstance ::= FACE-INSTANCE-TYPE TLV-LENGTH
  //                  Action?
  //                  FaceID?
  //                  IPProto?
  //                  Host?
  //                  Port?
  //                  MulticastInterface?
  //                  MulticastTTL?
  //                  FreshnessPeriod?

  // Action
  Block::element_const_iterator val = wire_.find(tlv::ndnd::Action);
  if (val != wire_.elements_end())
    {
      action_ = std::string(reinterpret_cast<const char*>(val->value()), val->value_size());
    }

  // FaceID
  val = wire_.find(tlv::ndnd::FaceID);
  if (val != wire_.elements_end())
    {
      faceId_ = readNonNegativeInteger(*val);
    }

  // IPProto
  val = wire_.find(tlv::ndnd::IPProto);
  if (val != wire_.elements_end())
    {
      ipProto_ = readNonNegativeInteger(*val);
    }

  // Host
  val = wire_.find(tlv::ndnd::Host);
  if (val != wire_.elements_end())
    {
      host_ = std::string(reinterpret_cast<const char*>(val->value()), val->value_size());
    }

  // Port
  val = wire_.find(tlv::ndnd::Port);
  if (val != wire_.elements_end())
    {
      port_ = std::string(reinterpret_cast<const char*>(val->value()), val->value_size());
    }

  // MulticastInterface
  val = wire_.find(tlv::ndnd::MulticastInterface);
  if (val != wire_.elements_end())
    {
      multicastInterface_ = std::string(reinterpret_cast<const char*>(val->value()), val->value_size());
    }

  // MulticastTTL
  val = wire_.find(tlv::ndnd::MulticastTTL);
  if (val != wire_.elements_end())
    {
      multicastTtl_ = readNonNegativeInteger(*val);
    }

  // FreshnessPeriod
  val = wire_.find(Tlv::FreshnessPeriod);
  if (val != wire_.elements_end())
    {
      freshnessPeriod_ = readNonNegativeInteger(*val);
    }
}

inline std::ostream&
operator << (std::ostream &os, const FaceInstance &entry)
{
  os << "FaceInstance(";
  
  // Action
  if (!entry.getAction().empty())
    {
      os << "Action:" << entry.getAction() << ", ";
    }

  // FaceID
  if (entry.getFaceId() >= 0)
    {
      os << "FaceID:" << entry.getFaceId() << ", ";
    }

  // IPProto
  if (entry.getIpProto() >= 0)
    {
      os << "IPProto:" << entry.getIpProto() << ", ";
    }

  // Host
  if (!entry.getHost().empty())
    {
      os << "Host:" << entry.getHost() << ", ";
    }

  // Port
  if (!entry.getPort().empty())
    {
      os << "Port:" << entry.getPort() << ", ";
    }

  // MulticastInterface
  if (!entry.getMulticastInterface().empty())
    {
      os << "MulticastInterface:" << entry.getMulticastInterface() << ", ";
    }

  // MulticastTTL
  if (entry.getMulticastTtl() >= 0)
    {
      os << "MulticastTTL:" << entry.getMulticastTtl() << ", ";
    }

  // FreshnessPeriod
  if (entry.getFreshnessPeriod() >= 0)
    {
      os << "FreshnessPeriod:" << entry.getFreshnessPeriod() << ", ";
    }

  os << ")";
  return os;
}

} // namespace ndnd
} // namespace ndn

#endif // NDN_MANAGEMENT_NDND_FACE_INSTANCE_HPP

