management: nfd::ControlParameters

refs #1397

Change-Id: I8d18fb2af799631bb9b94fad72f44c496e154a07
diff --git a/src/encoding/tlv-nfd.hpp b/src/encoding/tlv-nfd.hpp
index 3e3c512..e2aee99 100644
--- a/src/encoding/tlv-nfd.hpp
+++ b/src/encoding/tlv-nfd.hpp
@@ -17,28 +17,28 @@
 namespace nfd {
 
 enum {
+  // ControlParameters
+  ControlParameters   = 104,
+  FaceId              = 105,
+  Uri                 = 114,
+  LocalControlFeature = 110,
+  Cost                = 106,
+  Strategy            = 107,
+
+  // (deprecated)
+  FibManagementOptions  = ControlParameters,
+  FaceManagementOptions = ControlParameters,
+  StrategyChoiceOptions = ControlParameters,
+
   // ControlResponse
   ControlResponse = 101,
   StatusCode      = 102,
   StatusText      = 103,
 
-  // FIB Management Protocol
-  FibManagementOptions = 104,
-  FaceId          = 105,
-  Cost            = 106,
-
   // FIB Enumeration Protocol
   FibEntry        = 128,
   NextHopRecord   = 129,
 
-  // Face Management Protocol
-  FaceManagementOptions = 108,
-  Uri                   = 114,
-
-  // Strategy Choice Protocol
-  StrategyChoiceOptions = 115,
-  Strategy              = 107,
-
   // Face Status Protocol
   FaceStatus                   = 128,
   TotalIncomingInterestCounter = 145,
diff --git a/src/management/nfd-control-parameters.hpp b/src/management/nfd-control-parameters.hpp
new file mode 100644
index 0000000..b9e1d7b
--- /dev/null
+++ b/src/management/nfd-control-parameters.hpp
@@ -0,0 +1,409 @@
+/* -*- 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_NFD_CONTROL_PARAMETERS_HPP
+#define NDN_MANAGEMENT_NFD_CONTROL_PARAMETERS_HPP
+
+#include "../name.hpp"
+#include "../encoding/tlv-nfd.hpp"
+
+namespace ndn {
+namespace nfd {
+
+class ControlParameters;
+typedef ControlParameters FaceManagementOptions;
+typedef ControlParameters FibManagementOptions;
+typedef ControlParameters StrategyChoiceOptions;
+
+enum LocalControlFeature {
+  LOCAL_CONTROL_FEATURE_INCOMING_FACE_ID = 1,
+  LOCAL_CONTROL_FEATURE_NEXT_HOP_FACE_ID = 2
+};
+
+class ControlParameters {
+public:
+  class Error : public Tlv::Error
+  {
+  public:
+    explicit
+    Error(const std::string& what)
+      : Tlv::Error(what)
+    {
+    }
+  };
+
+  ControlParameters();
+
+  explicit
+  ControlParameters(const Block& block)
+  {
+    wireDecode(block);
+  }
+
+  template<bool T>
+  size_t
+  wireEncode(EncodingImpl<T>& encoder) const;
+
+  const Block&
+  wireEncode() const;
+
+  void
+  wireDecode(const Block& wire);
+
+public: // getters & setters
+  bool
+  hasName() const
+  {
+    return m_hasName;
+  }
+
+  const Name&
+  getName() const
+  {
+    BOOST_ASSERT(m_hasName);
+    return m_name;
+  }
+
+  ControlParameters&
+  setName(const Name& name)
+  {
+    m_wire.reset();
+    m_name = name;
+    m_hasName = true;
+    return *this;
+  }
+
+  ControlParameters&
+  unsetName()
+  {
+    m_wire.reset();
+    m_hasName = false;
+    return *this;
+  }
+
+  bool
+  hasFaceId() const
+  {
+    return m_hasFaceId;
+  }
+
+  uint64_t
+  getFaceId() const
+  {
+    BOOST_ASSERT(m_hasFaceId);
+    return m_faceId;
+  }
+
+  ControlParameters&
+  setFaceId(uint64_t faceId)
+  {
+    m_wire.reset();
+    m_faceId = faceId;
+    m_hasFaceId = true;
+    return *this;
+  }
+
+  ControlParameters&
+  unsetFaceId()
+  {
+    m_wire.reset();
+    m_hasFaceId = false;
+    return *this;
+  }
+
+  bool
+  hasUri() const
+  {
+    return m_hasUri;
+  }
+
+  const std::string&
+  getUri() const
+  {
+    BOOST_ASSERT(m_hasUri);
+    return m_uri;
+  }
+
+  ControlParameters&
+  setUri(const std::string& uri)
+  {
+    m_wire.reset();
+    m_uri = uri;
+    m_hasUri = true;
+    return *this;
+  }
+
+  ControlParameters&
+  unsetUri()
+  {
+    m_wire.reset();
+    m_hasUri = false;
+    return *this;
+  }
+
+  bool
+  hasLocalControlFeature() const
+  {
+    return m_hasLocalControlFeature;
+  }
+
+  LocalControlFeature
+  getLocalControlFeature() const
+  {
+    BOOST_ASSERT(m_hasLocalControlFeature);
+    return m_localControlFeature;
+  }
+
+  ControlParameters&
+  setLocalControlFeature(LocalControlFeature localControlFeature)
+  {
+    m_wire.reset();
+    m_localControlFeature = localControlFeature;
+    m_hasLocalControlFeature = true;
+    return *this;
+  }
+
+  ControlParameters&
+  unsetLocalControlFeature()
+  {
+    m_wire.reset();
+    m_hasLocalControlFeature = false;
+    return *this;
+  }
+
+  bool
+  hasCost() const
+  {
+    return m_hasCost;
+  }
+
+  uint64_t
+  getCost() const
+  {
+    BOOST_ASSERT(m_hasCost);
+    return m_cost;
+  }
+
+  ControlParameters&
+  setCost(uint64_t cost)
+  {
+    m_wire.reset();
+    m_cost = cost;
+    m_hasCost = true;
+    return *this;
+  }
+
+  ControlParameters&
+  unsetCost()
+  {
+    m_wire.reset();
+    m_hasCost = false;
+    return *this;
+  }
+
+  bool
+  hasStrategy() const
+  {
+    return m_hasStrategy;
+  }
+
+  const Name&
+  getStrategy() const
+  {
+    BOOST_ASSERT(m_hasStrategy);
+    return m_strategy;
+  }
+
+  ControlParameters&
+  setStrategy(const Name& strategy)
+  {
+    m_wire.reset();
+    m_strategy = strategy;
+    m_hasStrategy = true;
+    return *this;
+  }
+
+  ControlParameters&
+  unsetStrategy()
+  {
+    m_wire.reset();
+    m_hasStrategy = false;
+    return *this;
+  }
+
+private: // fields
+  Name                m_name;
+  uint64_t            m_faceId;
+  std::string         m_uri;
+  LocalControlFeature m_localControlFeature;
+  uint64_t            m_cost;
+  Name                m_strategy;
+
+  bool m_hasName;
+  bool m_hasFaceId;
+  bool m_hasUri;
+  bool m_hasLocalControlFeature;
+  bool m_hasCost;
+  bool m_hasStrategy;
+
+private:
+  mutable Block m_wire;
+};
+
+
+inline
+ControlParameters::ControlParameters()
+  : m_hasName(false)
+  , m_hasFaceId(false)
+  , m_hasUri(false)
+  , m_hasLocalControlFeature(false)
+  , m_hasCost(false)
+  , m_hasStrategy(false)
+{
+}
+
+template<bool T>
+inline size_t
+ControlParameters::wireEncode(EncodingImpl<T>& encoder) const
+{
+  size_t totalLength = 0;
+
+  if (m_hasStrategy) {
+    totalLength += prependNestedBlock(encoder, tlv::nfd::Strategy, m_strategy);
+  }
+  if (m_hasCost) {
+    totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::Cost, m_cost);
+  }
+  if (m_hasLocalControlFeature) {
+    totalLength += prependNonNegativeIntegerBlock(encoder,
+                   tlv::nfd::LocalControlFeature, m_localControlFeature);
+  }
+  if (m_hasUri) {
+    size_t valLength = encoder.prependByteArray(
+                       reinterpret_cast<const uint8_t*>(m_uri.c_str()), m_uri.size());
+    totalLength += valLength;
+    totalLength += encoder.prependVarNumber(valLength);
+    totalLength += encoder.prependVarNumber(tlv::nfd::Uri);
+  }
+  if (m_hasFaceId) {
+    totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::FaceId, m_faceId);
+  }
+  if (m_hasName) {
+    totalLength += m_name.wireEncode(encoder);
+  }
+
+  totalLength += encoder.prependVarNumber(totalLength);
+  totalLength += encoder.prependVarNumber(tlv::nfd::ControlParameters);
+  return totalLength;
+}
+
+inline const Block&
+ControlParameters::wireEncode() const
+{
+  if (m_wire.hasWire())
+    return m_wire;
+
+  EncodingEstimator estimator;
+  size_t estimatedSize = wireEncode(estimator);
+
+  EncodingBuffer buffer(estimatedSize, 0);
+  wireEncode(buffer);
+
+  m_wire = buffer.block();
+  return m_wire;
+}
+
+inline void
+ControlParameters::wireDecode(const Block& block)
+{
+  if (block.type() != tlv::nfd::ControlParameters) {
+    throw Error("expecting TLV-TYPE ControlParameters");
+  }
+  m_wire = block;
+  m_wire.parse();
+  Block::element_const_iterator val;
+
+  val = m_wire.find(Tlv::Name);
+  m_hasName = val != m_wire.elements_end();
+  if (m_hasName) {
+    m_name.wireDecode(*val);
+  }
+
+  val = m_wire.find(tlv::nfd::FaceId);
+  m_hasFaceId = val != m_wire.elements_end();
+  if (m_hasFaceId) {
+    m_faceId = static_cast<uint64_t>(readNonNegativeInteger(*val));
+  }
+
+  val = m_wire.find(tlv::nfd::Uri);
+  m_hasUri = val != m_wire.elements_end();
+  if (m_hasUri) {
+    m_uri.assign(reinterpret_cast<const char*>(val->value()), val->value_size());
+  }
+
+  val = m_wire.find(tlv::nfd::LocalControlFeature);
+  m_hasLocalControlFeature = val != m_wire.elements_end();
+  if (m_hasLocalControlFeature) {
+    m_localControlFeature = static_cast<LocalControlFeature>(readNonNegativeInteger(*val));
+  }
+
+  val = m_wire.find(tlv::nfd::Cost);
+  m_hasCost = val != m_wire.elements_end();
+  if (m_hasCost) {
+    m_cost = static_cast<uint64_t>(readNonNegativeInteger(*val));
+  }
+
+  val = m_wire.find(tlv::nfd::Strategy);
+  m_hasStrategy = val != m_wire.elements_end();
+  if (m_hasStrategy) {
+    val->parse();
+    if (val->elements().empty()) {
+      throw Error("expecting Strategy/Name");
+    }
+    else {
+      m_strategy.wireDecode(*val->elements_begin());
+    }
+  }
+}
+
+inline std::ostream&
+operator<<(std::ostream& os, const ControlParameters& parameters)
+{
+  os << "ControlParameters(";
+
+  if (parameters.hasName()) {
+    os << "Name: " << parameters.getName() << ", ";
+  }
+
+  if (parameters.hasFaceId()) {
+    os << "FaceId: " << parameters.getFaceId() << ", ";
+  }
+
+  if (parameters.hasUri()) {
+    os << "Uri: " << parameters.getUri() << ", ";
+  }
+
+  if (parameters.hasLocalControlFeature()) {
+    os << "LocalControlFeature: " << parameters.getLocalControlFeature() << ", ";
+  }
+
+  if (parameters.hasCost()) {
+    os << "Cost: " << parameters.getCost() << ", ";
+  }
+
+  if (parameters.hasStrategy()) {
+    os << "Strategy: " << parameters.getStrategy() << ", ";
+  }
+
+  os << ")";
+  return os;
+}
+
+
+} // namespace nfd
+} // namespace ndn
+
+#endif // NDN_MANAGEMENT_NFD_CONTROL_PARAMETERS_HPP
diff --git a/src/management/nfd-controller.hpp b/src/management/nfd-controller.hpp
index 99f8a62..f3ab116 100644
--- a/src/management/nfd-controller.hpp
+++ b/src/management/nfd-controller.hpp
@@ -8,23 +8,20 @@
 #define NDN_MANAGEMENT_NFD_CONTROLLER_HPP
 
 #include "controller.hpp"
+#include "nfd-control-parameters.hpp"
 #include "../util/command-interest-generator.hpp"
 
 namespace ndn {
 
 namespace nfd {
 
-class FibManagementOptions;
-class FaceManagementOptions;
-class StrategyChoiceOptions;
-  
 class Controller : public ndn::Controller
 {
 public:
   typedef function<void(const FibManagementOptions&)> FibCommandSucceedCallback;
   typedef function<void(const FaceManagementOptions&)> FaceCommandSucceedCallback;
   typedef function<void(const StrategyChoiceOptions&)> StrategyChoiceCommandSucceedCallback;
-  
+
   /**
    * @brief Construct ndnd::Control object
    */
@@ -95,7 +92,7 @@
                              const StrategyChoiceOptions& options,
                              const StrategyChoiceCommandSucceedCallback& onSuccess,
                              const FailCallback& onFailure);
-  
+
 private:
   void
   processFibCommandResponse(Data& data,
diff --git a/src/management/nfd-face-management-options.hpp b/src/management/nfd-face-management-options.hpp
index 802cde0..5efc4f8 100644
--- a/src/management/nfd-face-management-options.hpp
+++ b/src/management/nfd-face-management-options.hpp
@@ -7,159 +7,6 @@
 #ifndef NDN_MANAGEMENT_NFD_FACE_MANAGEMENT_OPTIONS_HPP
 #define NDN_MANAGEMENT_NFD_FACE_MANAGEMENT_OPTIONS_HPP
 
-#include "../encoding/encoding-buffer.hpp"
-#include "../encoding/tlv-nfd.hpp"
-
-namespace ndn {
-namespace nfd {
-
-class FaceManagementOptions {
-public:
-  struct Error : public Tlv::Error { Error(const std::string &what) : Tlv::Error(what) {} };
-
-  FaceManagementOptions ()
-    : m_faceId (INVALID_FACE_ID)
-  {
-  }
-
-  FaceManagementOptions(const Block& block)
-  {
-    wireDecode(block);
-  }
-  
-  uint64_t 
-  getFaceId () const
-  {
-    return m_faceId;
-  }
-  
-  FaceManagementOptions&
-  setFaceId (uint64_t faceId)
-  {
-    m_faceId = faceId;
-    wire_.reset ();
-    return *this;
-  }
-
-  const std::string&
-  getUri () const
-  {
-    return m_uri;
-  }
-
-  FaceManagementOptions&
-  setUri (const std::string& uri)
-  {
-    m_uri = uri;
-    wire_.reset ();
-    return *this;
-  }
-
-  template<bool T>
-  size_t
-  wireEncode(EncodingImpl<T> &block) const;
-  
-  const Block&
-  wireEncode () const;
-  
-  void 
-  wireDecode (const Block &wire);
-  
-private:
-  uint64_t m_faceId;
-  std::string m_uri;
-
-  mutable Block wire_;
-};
-
-
-template<bool T>
-inline size_t
-FaceManagementOptions::wireEncode(EncodingImpl<T>& blk) const
-{
-  size_t total_len = 0;
-
-  if (!m_uri.empty())
-    {
-      size_t var_len = blk.prependByteArray (reinterpret_cast<const uint8_t*>(m_uri.c_str()), m_uri.size());
-      total_len += var_len;
-      total_len += blk.prependVarNumber (var_len);
-      total_len += blk.prependVarNumber (tlv::nfd::Uri);
-    }
-
-  if (m_faceId != INVALID_FACE_ID)
-    {
-      size_t var_len = blk.prependNonNegativeInteger (m_faceId);
-      total_len += var_len;
-      total_len += blk.prependVarNumber (var_len);
-      total_len += blk.prependVarNumber (tlv::nfd::FaceId);
-    }
-
-  total_len += blk.prependVarNumber (total_len);
-  total_len += blk.prependVarNumber (tlv::nfd::FaceManagementOptions);
-  return total_len;
-}
-
-inline const Block&
-FaceManagementOptions::wireEncode () const
-{
-  if (wire_.hasWire ())
-    return wire_;
-
-  EncodingEstimator estimator;
-  size_t estimatedSize = wireEncode(estimator);
-  
-  EncodingBuffer buffer(estimatedSize, 0);
-  wireEncode(buffer);
-
-  wire_ = buffer.block();
-  return wire_;
-}
-
-inline void 
-FaceManagementOptions::wireDecode (const Block &wire)
-{
-  m_uri.clear ();
-  m_faceId = INVALID_FACE_ID;
-
-  wire_ = wire;
-
-  if (wire_.type() != tlv::nfd::FaceManagementOptions)
-    throw Error("Requested decoding of FaceManagementOptions, but Block is of different type");
-  
-  wire_.parse ();
-
-  // FaceID
-  Block::element_const_iterator val = wire_.find(tlv::nfd::FaceId);
-  if (val != wire_.elements_end())
-    {
-      m_faceId = readNonNegativeInteger(*val);
-    }
-
-  // Uri
-  val = wire_.find(tlv::nfd::Uri);
-  if (val != wire_.elements_end())
-    {
-      m_uri.append(reinterpret_cast<const char*>(val->value()), val->value_size());
-    }
-}
-
-inline std::ostream&
-operator << (std::ostream &os, const FaceManagementOptions &option)
-{
-  os << "ForwardingEntry(";
-  
-  // FaceID
-  os << "FaceID: " << option.getFaceId () << ", ";
-
-  // Uri
-  os << "Uri: " << option.getUri ();
-
-  os << ")";
-  return os;
-}
-
-} // namespace nfd
-} // namespace ndn
+#include "nfd-control-parameters.hpp"
 
 #endif // NDN_MANAGEMENT_NFD_FACE_MANAGEMENT_OPTIONS_HPP
diff --git a/src/management/nfd-fib-management-options.hpp b/src/management/nfd-fib-management-options.hpp
index b2f8485..d1270c3 100644
--- a/src/management/nfd-fib-management-options.hpp
+++ b/src/management/nfd-fib-management-options.hpp
@@ -10,216 +10,6 @@
 #ifndef NDN_MANAGEMENT_NFD_FIB_MANAGEMENT_OPTIONS_HPP
 #define NDN_MANAGEMENT_NFD_FIB_MANAGEMENT_OPTIONS_HPP
 
-#include "../encoding/block.hpp"
-#include "../encoding/encoding-buffer.hpp"
-#include "../encoding/tlv-nfd.hpp"
-#include "../name.hpp"
-
-namespace ndn {
-namespace nfd {
-
-class FibManagementOptions {
-public:
-  struct Error : public Tlv::Error { Error(const std::string &what) : Tlv::Error(what) {} };
-
-  FibManagementOptions ()
-    : m_faceId (std::numeric_limits<uint64_t>::max())
-    , m_cost (0)
-  {
-  }
-
-  FibManagementOptions(const Block& block)
-  {
-    wireDecode(block);
-  }
-
-  const Name&
-  getName () const
-  {
-    return m_name;
-  }
-
-  FibManagementOptions&
-  setName (const Name &name)
-  {
-    m_name = name;
-    m_wire.reset ();
-    return *this;
-  }
-
-  uint64_t
-  getFaceId () const
-  {
-    return m_faceId;
-  }
-
-  FibManagementOptions&
-  setFaceId (uint64_t faceId)
-  {
-    m_faceId = faceId;
-    m_wire.reset ();
-    return *this;
-  }
-
-  uint64_t
-  getCost () const
-  {
-    return m_cost;
-  }
-
-  FibManagementOptions&
-  setCost (uint64_t cost)
-  {
-    m_cost = cost;
-    m_wire.reset ();
-    return *this;
-  }
-
-  const Name&
-  getStrategy () const
-  {
-    return m_strategy;
-  }
-
-  FibManagementOptions&
-  setStrategy (const Name& strategy)
-  {
-    m_strategy = strategy;
-    m_wire.reset ();
-    return *this;
-  }
-
-  template<bool T>
-  size_t
-  wireEncode(EncodingImpl<T> &block) const;
-
-  const Block&
-  wireEncode () const;
-
-  void
-  wireDecode (const Block &wire);
-
-private:
-  Name m_name;
-  uint64_t m_faceId;
-  uint64_t m_cost;
-  Name m_strategy;
-
-  mutable Block m_wire;
-};
-
-template<bool T>
-inline size_t
-FibManagementOptions::wireEncode(EncodingImpl<T>& blk) const
-{
-  size_t total_len = 0;
-
-  if (!m_strategy.empty())
-    {
-      total_len += prependNestedBlock(blk, tlv::nfd::Strategy, m_strategy);
-    }
-
-  if (m_cost != 0)
-    {
-      total_len += prependNonNegativeIntegerBlock(blk, tlv::nfd::Cost, m_cost);
-    }
-
-  if (m_faceId != std::numeric_limits<uint64_t>::max())
-    {
-      total_len += prependNonNegativeIntegerBlock(blk, tlv::nfd::FaceId, m_faceId);
-    }
-
-  total_len += m_name.wireEncode(blk);
-
-  total_len += blk.prependVarNumber(total_len);
-  total_len += blk.prependVarNumber(tlv::nfd::FibManagementOptions);
-  return total_len;
-}
-
-inline const Block&
-FibManagementOptions::wireEncode () const
-{
-  if (m_wire.hasWire ())
-    return m_wire;
-
-  EncodingEstimator estimator;
-  size_t estimatedSize = wireEncode(estimator);
-
-  EncodingBuffer buffer(estimatedSize, 0);
-  wireEncode(buffer);
-
-  m_wire = buffer.block();
-  return m_wire;
-}
-
-inline void
-FibManagementOptions::wireDecode (const Block &wire)
-{
-  m_name.clear();
-  m_faceId = std::numeric_limits<uint64_t>::max();
-  m_cost = 0;
-  m_strategy.clear();
-
-  m_wire = wire;
-
-  if (m_wire.type() != tlv::nfd::FibManagementOptions)
-    throw Error("Requested decoding of FibManagementOptions, but Block is of different type");
-
-  m_wire.parse ();
-
-  // Name
-  Block::element_const_iterator val = m_wire.find(Tlv::Name);
-  if (val != m_wire.elements_end())
-    {
-      m_name.wireDecode(*val);
-    }
-
-  // FaceID
-  val = m_wire.find(tlv::nfd::FaceId);
-  if (val != m_wire.elements_end())
-    {
-      m_faceId = readNonNegativeInteger(*val);
-    }
-
-  // Cost
-  val = m_wire.find(tlv::nfd::Cost);
-  if (val != m_wire.elements_end())
-    {
-      m_cost = readNonNegativeInteger(*val);
-    }
-
-  // Strategy
-  val = m_wire.find(tlv::nfd::Strategy);
-  if (val != m_wire.elements_end())
-    {
-      val->parse();
-      if (!val->elements().empty())
-        m_strategy.wireDecode(*val->elements_begin());
-    }
-}
-
-inline std::ostream&
-operator << (std::ostream &os, const FibManagementOptions &option)
-{
-  os << "ForwardingEntry(";
-
-  // Name
-  os << "Prefix: " << option.getName() << ", ";
-
-  // FaceID
-  os << "FaceID: " << option.getFaceId() << ", ";
-
-  // Cost
-  os << "Cost: " << option.getCost() << ", ";
-
-  // Strategy
-  os << "Strategy: " << option.getStrategy() << ", ";
-
-  os << ")";
-  return os;
-}
-
-} // namespace nfd
-} // namespace ndn
+#include "nfd-control-parameters.hpp"
 
 #endif // NDN_MANAGEMENT_NFD_FIB_MANAGEMENT_OPTIONS_HPP
diff --git a/src/management/nfd-strategy-choice-options.hpp b/src/management/nfd-strategy-choice-options.hpp
index 60d846d..99889c7 100644
--- a/src/management/nfd-strategy-choice-options.hpp
+++ b/src/management/nfd-strategy-choice-options.hpp
@@ -7,157 +7,6 @@
 #ifndef NDN_MANAGEMENT_NFD_STRATEGY_CHOICE_OPTIONS_HPP
 #define NDN_MANAGEMENT_NFD_STRATEGY_CHOICE_OPTIONS_HPP
 
-#include "../encoding/block.hpp"
-#include "../encoding/encoding-buffer.hpp"
-#include "../encoding/tlv-nfd.hpp"
-#include "../name.hpp"
-
-namespace ndn {
-namespace nfd {
-
-class StrategyChoiceOptions{
-public:
-  struct Error : public Tlv::Error
-  {
-    Error(const std::string& what) : Tlv::Error(what)
-    {
-    }
-  };
-  
-  StrategyChoiceOptions()
-  {
-  }
-  
-  StrategyChoiceOptions(const Block& block)
-  {
-    wireDecode(block);
-  }
-  
-  const Name&
-  getName() const
-  {
-    return m_name;
-  }
-  
-  StrategyChoiceOptions&
-  setName(const Name& name)
-  {
-    m_name = name;
-    m_wire.reset();
-    return *this;
-  }
-  
-  const Name&
-  getStrategy() const
-  {
-    return m_strategy;
-  }
-  
-  StrategyChoiceOptions&
-  setStrategy(const Name& strategy)
-  {
-    m_strategy = strategy;
-    m_wire.reset();
-    return *this;
-  }
-  
-  template<bool T>
-  size_t
-  wireEncode(EncodingImpl<T>& block) const;
-  
-  const Block&
-  wireEncode() const;
-  
-  void
-  wireDecode(const Block& wire);
-  
-private:
-  Name m_name;
-  Name m_strategy;
-  
-  mutable Block m_wire;
-};
-
-template<bool T>
-inline size_t
-StrategyChoiceOptions::wireEncode(EncodingImpl<T>& block) const
-{
-  size_t totalLength = 0;
-  
-  if (!m_strategy.empty())
-  {
-    totalLength += prependNestedBlock(block, tlv::nfd::Strategy, m_strategy);
-  }
-  
-  totalLength += m_name.wireEncode(block);
-  
-  totalLength += block.prependVarNumber(totalLength);
-  totalLength += block.prependVarNumber(tlv::nfd::StrategyChoiceOptions);
-  return totalLength;
-}
-
-inline const Block&
-StrategyChoiceOptions::wireEncode() const
-{
-  if (m_wire.hasWire())
-    return m_wire;
-  
-  EncodingEstimator estimator;
-  size_t estimatedSize = wireEncode(estimator);
-  
-  EncodingBuffer buffer(estimatedSize, 0);
-  wireEncode(buffer);
-  
-  m_wire = buffer.block();
-  return m_wire;
-}
-
-inline void
-StrategyChoiceOptions::wireDecode(const Block& wire)
-{
-  m_name.clear();
-  m_strategy.clear();
-  
-  m_wire = wire;
-  
-  if (m_wire.type() != tlv::nfd::StrategyChoiceOptions)
-    throw Error("Requested decoding of StrategyChoiceOptions, but Block is of different type");
-  
-  m_wire.parse();
-  
-  // Name
-  Block::element_const_iterator val = m_wire.find(Tlv::Name);
-  if (val != m_wire.elements_end())
-  {
-    m_name.wireDecode(*val);
-  }
-  
-  // Strategy
-  val = m_wire.find(tlv::nfd::Strategy);
-  if (val != m_wire.elements_end())
-  {
-    val->parse();
-    if (!val->elements().empty())
-      m_strategy.wireDecode(*val->elements_begin());
-  }
-}
-
-inline std::ostream&
-operator << (std::ostream& os, const StrategyChoiceOptions& option)
-{
-  os << "StrategyChoiceOptions(";
-  
-  // Name
-  os << "Name: " << option.getName() << ", ";
-  
-  // Strategy
-  os << "Strategy: " << option.getStrategy() << ", ";
-  
-  os << ")";
-  return os;
-}
-
-} // namespace nfd
-} // namespace ndn
+#include "nfd-control-parameters.hpp"
 
 #endif // NDN_MANAGEMENT_NFD_STRATEGY_CHOICE_MANAGEMENT_OPTIONS_HPP
diff --git a/tests/management/nfd-control-parameters.cpp b/tests/management/nfd-control-parameters.cpp
new file mode 100644
index 0000000..d5320b1
--- /dev/null
+++ b/tests/management/nfd-control-parameters.cpp
@@ -0,0 +1,87 @@
+/* -*- 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.
+ */
+
+#include "management/nfd-control-parameters.hpp"
+// Having a separate compilation unit is necessary to ensure .hpp can compile on its own.
+
+#include <boost/test/unit_test.hpp>
+
+namespace ndn {
+namespace nfd {
+
+BOOST_AUTO_TEST_SUITE(NfdControlParameters)
+
+BOOST_AUTO_TEST_CASE(FaceOptions)
+{
+  ControlParameters parameters;
+  parameters.setUri("tcp4://192.0.2.1:6363");
+
+  Block wire = parameters.wireEncode();
+
+  ControlParameters decoded(wire);
+  BOOST_CHECK_EQUAL(decoded.getUri(), "tcp4://192.0.2.1:6363");
+  BOOST_CHECK_EQUAL(decoded.hasName(), false);
+  BOOST_CHECK_EQUAL(decoded.hasFaceId(), false);
+  BOOST_CHECK_EQUAL(decoded.hasLocalControlFeature(), false);
+  BOOST_CHECK_EQUAL(decoded.hasCost(), false);
+  BOOST_CHECK_EQUAL(decoded.hasStrategy(), false);
+}
+
+BOOST_AUTO_TEST_CASE(FaceLocalControlOptions)
+{
+  ControlParameters parameters;
+  parameters.setLocalControlFeature(LOCAL_CONTROL_FEATURE_INCOMING_FACE_ID);
+
+  Block wire = parameters.wireEncode();
+
+  ControlParameters decoded(wire);
+  BOOST_CHECK_EQUAL(decoded.getLocalControlFeature(), LOCAL_CONTROL_FEATURE_INCOMING_FACE_ID);
+  BOOST_CHECK_EQUAL(decoded.hasName(), false);
+  BOOST_CHECK_EQUAL(decoded.hasFaceId(), false);
+  BOOST_CHECK_EQUAL(decoded.hasCost(), false);
+  BOOST_CHECK_EQUAL(decoded.hasUri(), false);
+  BOOST_CHECK_EQUAL(decoded.hasStrategy(), false);
+}
+
+BOOST_AUTO_TEST_CASE(FibOptions)
+{
+  ControlParameters parameters;
+  parameters.setName("ndn:/example")
+            .setFaceId(4)
+            .setCost(555);
+
+  Block wire = parameters.wireEncode();
+
+  ControlParameters decoded(wire);
+  BOOST_CHECK_EQUAL(decoded.getName(), Name("ndn:/example"));
+  BOOST_CHECK_EQUAL(decoded.getFaceId(), 4);
+  BOOST_CHECK_EQUAL(decoded.getCost(), 555);
+  BOOST_CHECK_EQUAL(decoded.hasLocalControlFeature(), false);
+  BOOST_CHECK_EQUAL(decoded.hasUri(), false);
+  BOOST_CHECK_EQUAL(decoded.hasStrategy(), false);
+}
+
+BOOST_AUTO_TEST_CASE(StrategyChoiceOptions)
+{
+  ControlParameters parameters;
+  parameters.setName("ndn:/")
+            .setStrategy("ndn:/strategy/A");
+
+  Block wire = parameters.wireEncode();
+
+  ControlParameters decoded(wire);
+  BOOST_CHECK_EQUAL(decoded.getName(), Name("ndn:/"));
+  BOOST_CHECK_EQUAL(decoded.getStrategy(), Name("ndn:/strategy/A"));
+  BOOST_CHECK_EQUAL(decoded.hasFaceId(), false);
+  BOOST_CHECK_EQUAL(decoded.hasUri(), false);
+  BOOST_CHECK_EQUAL(decoded.hasLocalControlFeature(), false);
+  BOOST_CHECK_EQUAL(decoded.hasCost(), false);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace nfd
+} // namespace ndn
diff --git a/tests/management/test-nfd-control.cpp b/tests/management/test-nfd-control.cpp
index a3ca371..de9a1bb 100644
--- a/tests/management/test-nfd-control.cpp
+++ b/tests/management/test-nfd-control.cpp
@@ -38,7 +38,7 @@
 };
 
 const uint8_t TestFaceManagementOptions[] = {
-  0x6c, 0x1e, 0x69, 0x01, 0x0a, 0x72, 0x19, 0x74, 0x63, 0x70, 0x3a, 0x2f,
+  0x68, 0x1e, 0x69, 0x01, 0x0a, 0x72, 0x19, 0x74, 0x63, 0x70, 0x3a, 0x2f,
   0x2f, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x2f, 0x68, 0x65, 0x6c,
   0x6c, 0x6f, 0x2f, 0x77, 0x6f, 0x72, 0x6c, 0x64
 };