src: Refactoring common.hpp and minimizing exposed includes

Face class has relatively large rewrite to hide internals using
Implementor pattern.  As of this commit, <boost/asio.hpp> is not
automatically included whenever ndn-cxx/face.hpp is included.  If it is
needed to directly work with io_service, asio.hpp should be specifically
included.

Change-Id: Ie742b851025b4e3da634eb981319df0f42937855
diff --git a/src/detail/face-impl.hpp b/src/detail/face-impl.hpp
new file mode 100644
index 0000000..52f9dd3
--- /dev/null
+++ b/src/detail/face-impl.hpp
@@ -0,0 +1,319 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/**
+ * Copyright (c) 2013-2014,  Regents of the University of California.
+ * All rights reserved.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ *
+ * This file licensed under New BSD License.  See COPYING for detailed information about
+ * ndn-cxx library copyright, permissions, and redistribution restrictions.
+ */
+
+#ifndef NDN_DETAIL_FACE_IMPL_HPP
+#define NDN_DETAIL_FACE_IMPL_HPP
+
+#include "../common.hpp"
+#include "../face.hpp"
+
+#include "registered-prefix.hpp"
+#include "pending-interest.hpp"
+
+#include "../util/scheduler.hpp"
+#include "../util/config-file.hpp"
+
+#include "transport/transport.hpp"
+#include "transport/unix-transport.hpp"
+#include "transport/tcp-transport.hpp"
+
+#include "management/nfd-controller.hpp"
+
+namespace ndn {
+
+class Face::Impl : noncopyable
+{
+public:
+  typedef std::list<shared_ptr<PendingInterest> > PendingInterestTable;
+  typedef std::list<shared_ptr<InterestFilterRecord> > InterestFilterTable;
+  typedef std::list<shared_ptr<RegisteredPrefix> > RegisteredPrefixTable;
+
+  explicit
+  Impl(Face& face)
+    : m_face(face)
+  {
+  }
+
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+
+  void
+  satisfyPendingInterests(Data& data)
+  {
+    for (PendingInterestTable::iterator i = m_pendingInterestTable.begin();
+         i != m_pendingInterestTable.end();
+         )
+      {
+        if ((*i)->getInterest()->matchesData(data))
+          {
+            // Copy pointers to the objects and remove the PIT entry before calling the callback.
+            OnData onData = (*i)->getOnData();
+            shared_ptr<const Interest> interest = (*i)->getInterest();
+
+            PendingInterestTable::iterator next = i;
+            ++next;
+            m_pendingInterestTable.erase(i);
+            i = next;
+
+            if (static_cast<bool>(onData)) {
+              onData(*interest, data);
+            }
+          }
+        else
+          ++i;
+      }
+  }
+
+  void
+  processInterestFilters(Interest& interest)
+  {
+    for (InterestFilterTable::iterator i = m_interestFilterTable.begin();
+         i != m_interestFilterTable.end();
+         ++i)
+      {
+        if ((*i)->doesMatch(interest.getName()))
+          {
+            (**i)(interest);
+          }
+      }
+  }
+
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+
+  void
+  asyncExpressInterest(const shared_ptr<const Interest>& interest,
+                       const OnData& onData, const OnTimeout& onTimeout)
+  {
+    if (!m_face.m_transport->isExpectingData())
+      m_face.m_transport->resume();
+
+    m_pendingInterestTable.push_back(make_shared<PendingInterest>(interest, onData, onTimeout));
+
+    if (!interest->getLocalControlHeader().empty(false, true))
+      {
+        // encode only NextHopFaceId towards the forwarder
+        m_face.m_transport->send(interest->getLocalControlHeader()
+                                   .wireEncode(*interest, false, true),
+                                 interest->wireEncode());
+      }
+    else
+      {
+        m_face.m_transport->send(interest->wireEncode());
+      }
+
+    if (!m_pitTimeoutCheckTimerActive) {
+      m_pitTimeoutCheckTimerActive = true;
+      m_pitTimeoutCheckTimer->expires_from_now(time::milliseconds(100));
+      m_pitTimeoutCheckTimer->async_wait(bind(&Impl::checkPitExpire, this));
+    }
+  }
+
+  void
+  asyncRemovePendingInterest(const PendingInterestId* pendingInterestId)
+  {
+    m_pendingInterestTable.remove_if(MatchPendingInterestId(pendingInterestId));
+  }
+
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+
+  void
+  asyncSetInterestFilter(const shared_ptr<InterestFilterRecord>& interestFilterRecord)
+  {
+    m_interestFilterTable.push_back(interestFilterRecord);
+  }
+
+  void
+  asyncUnsetInterestFilter(const InterestFilterId* interestFilterId)
+  {
+    InterestFilterTable::iterator i = std::find_if(m_interestFilterTable.begin(),
+                                                   m_interestFilterTable.end(),
+                                                   MatchInterestFilterId(interestFilterId));
+    if (i != m_interestFilterTable.end())
+      {
+        m_interestFilterTable.erase(i);
+      }
+  }
+
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+
+  template<class SignatureGenerator>
+  const RegisteredPrefixId*
+  registerPrefix(const Name& prefix,
+                 const shared_ptr<InterestFilterRecord>& filter,
+                 const RegisterPrefixSuccessCallback& onSuccess,
+                 const RegisterPrefixFailureCallback& onFailure,
+                 const SignatureGenerator& signatureGenerator)
+  {
+    using namespace nfd;
+
+    typedef void (nfd::Controller::*Registrator)
+      (const nfd::ControlParameters&,
+       const nfd::Controller::CommandSucceedCallback&,
+       const nfd::Controller::CommandFailCallback&,
+       const SignatureGenerator&,
+       const time::milliseconds&);
+
+    Registrator registrator, unregistrator;
+    if (!m_face.m_isDirectNfdFibManagementRequested) {
+      registrator = static_cast<Registrator>(&Controller::start<RibRegisterCommand>);
+      unregistrator = static_cast<Registrator>(&Controller::start<RibUnregisterCommand>);
+    }
+    else {
+      registrator = static_cast<Registrator>(&Controller::start<FibAddNextHopCommand>);
+      unregistrator = static_cast<Registrator>(&Controller::start<FibRemoveNextHopCommand>);
+    }
+
+    ControlParameters parameters;
+    parameters.setName(prefix);
+
+    RegisteredPrefix::Unregistrator bindedUnregistrator =
+      bind(unregistrator, m_face.m_nfdController, parameters, _1, _2,
+           signatureGenerator,
+           m_face.m_nfdController->getDefaultCommandTimeout());
+
+    shared_ptr<RegisteredPrefix> prefixToRegister =
+      ndn::make_shared<RegisteredPrefix>(prefix, filter, bindedUnregistrator);
+
+    ((*m_face.m_nfdController).*registrator)(parameters,
+                                             bind(&Impl::afterPrefixRegistered, this,
+                                                  prefixToRegister, onSuccess),
+                                             bind(onFailure, prefixToRegister->getPrefix(), _2),
+                                             signatureGenerator,
+                                             m_face.m_nfdController->getDefaultCommandTimeout());
+
+    return reinterpret_cast<const RegisteredPrefixId*>(prefixToRegister.get());
+  }
+
+  void
+  afterPrefixRegistered(const shared_ptr<RegisteredPrefix>& registeredPrefix,
+                        const RegisterPrefixSuccessCallback& onSuccess)
+  {
+    m_registeredPrefixTable.push_back(registeredPrefix);
+
+    if (static_cast<bool>(registeredPrefix->getFilter())) {
+      // it was a combined operation
+      m_interestFilterTable.push_back(registeredPrefix->getFilter());
+    }
+
+    if (static_cast<bool>(onSuccess)) {
+      onSuccess(registeredPrefix->getPrefix());
+    }
+  }
+
+  void
+  asyncUnregisterPrefix(const RegisteredPrefixId* registeredPrefixId,
+                        const UnregisterPrefixSuccessCallback& onSuccess,
+                        const UnregisterPrefixFailureCallback& onFailure)
+  {
+    RegisteredPrefixTable::iterator i = std::find_if(m_registeredPrefixTable.begin(),
+                                                     m_registeredPrefixTable.end(),
+                                                     MatchRegisteredPrefixId(registeredPrefixId));
+    if (i != m_registeredPrefixTable.end())
+      {
+        const shared_ptr<InterestFilterRecord>& filter = (*i)->getFilter();
+        if (static_cast<bool>(filter))
+          {
+            // it was a combined operation
+            m_interestFilterTable.remove(filter);
+          }
+
+        (*i)->unregister(bind(&Impl::finalizeUnregisterPrefix, this, i, onSuccess),
+                         bind(onFailure, _2));
+      }
+    else
+      onFailure("Unrecognized PrefixId");
+
+    // there cannot be two registered prefixes with the same id
+  }
+
+  void
+  finalizeUnregisterPrefix(RegisteredPrefixTable::iterator item,
+                           const UnregisterPrefixSuccessCallback& onSuccess)
+  {
+    m_registeredPrefixTable.erase(item);
+
+    if (!m_pitTimeoutCheckTimerActive && m_registeredPrefixTable.empty())
+      {
+        m_face.m_transport->pause();
+        if (!m_ioServiceWork) {
+          m_processEventsTimeoutTimer->cancel();
+        }
+      }
+    onSuccess();
+  }
+
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+
+  void
+  checkPitExpire()
+  {
+    // Check for PIT entry timeouts.
+    time::steady_clock::TimePoint now = time::steady_clock::now();
+
+    PendingInterestTable::iterator i = m_pendingInterestTable.begin();
+    while (i != m_pendingInterestTable.end())
+      {
+        if ((*i)->isTimedOut(now))
+          {
+            // Save the PendingInterest and remove it from the PIT.  Then call the callback.
+            shared_ptr<PendingInterest> pendingInterest = *i;
+
+            i = m_pendingInterestTable.erase(i);
+
+            pendingInterest->callTimeout();
+          }
+        else
+          ++i;
+      }
+
+    if (!m_pendingInterestTable.empty()) {
+      m_pitTimeoutCheckTimerActive = true;
+
+      m_pitTimeoutCheckTimer->expires_from_now(time::milliseconds(100));
+      m_pitTimeoutCheckTimer->async_wait(bind(&Impl::checkPitExpire, this));
+    }
+    else {
+      m_pitTimeoutCheckTimerActive = false;
+
+      if (m_registeredPrefixTable.empty()) {
+        m_face.m_transport->pause();
+        if (!m_ioServiceWork) {
+          m_processEventsTimeoutTimer->cancel();
+        }
+      }
+    }
+  }
+
+private:
+  Face& m_face;
+
+  PendingInterestTable m_pendingInterestTable;
+  InterestFilterTable m_interestFilterTable;
+  RegisteredPrefixTable m_registeredPrefixTable;
+
+  ConfigFile m_config;
+
+  shared_ptr<boost::asio::io_service::work> m_ioServiceWork; // if thread needs to be preserved
+  shared_ptr<monotonic_deadline_timer> m_pitTimeoutCheckTimer;
+  bool m_pitTimeoutCheckTimerActive;
+  shared_ptr<monotonic_deadline_timer> m_processEventsTimeoutTimer;
+
+  friend class Face;
+};
+
+} // namespace ndn
+
+#endif // NDN_DETAIL_FACE_IMPL_HPP