face-monitor: added a generic face notification subscriber.

refs #1331

Change-Id: I7fee01949ae5392aba3fc452fe12e5d6bfbcdffc
diff --git a/src/face-monitor.cpp b/src/face-monitor.cpp
new file mode 100644
index 0000000..f4143a9
--- /dev/null
+++ b/src/face-monitor.cpp
@@ -0,0 +1,150 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/**
+ * Copyright (C) 2014 Regents of the University of California.
+ * See COPYING for copyright and distribution information.
+ */
+
+#include "common.hpp"
+#include "face-monitor.hpp"
+#include <ndn-cpp-dev/management/nfd-face-event-notification.hpp>
+
+
+namespace ndn {
+
+using namespace nfd;
+
+FaceMonitor::FaceMonitor(Face& face)
+  : m_face(face)
+  , m_isStopped(true)
+{
+}
+
+FaceMonitor::~FaceMonitor()
+{
+}
+
+void
+FaceMonitor::removeAllSubscribers()
+{
+  m_notificationCallbacks.clear();
+  m_timeoutCallbacks.clear();
+  stopNotifications();
+}
+
+void
+FaceMonitor::stopNotifications()
+{
+  if (static_cast<bool>(m_lastInterestId))
+    m_face.removePendingInterest(m_lastInterestId);
+  m_isStopped = true;
+}
+
+void
+FaceMonitor::startNotifications()
+{
+  if (m_isStopped == false)
+    return; // Notifications cycle has been started.
+  m_isStopped = false;
+
+  Interest interest("/localhost/nfd/faces/events");
+  interest
+    .setMustBeFresh(true)
+    .setChildSelector(1)
+    .setInterestLifetime(time::seconds(60))
+  ;
+
+  //todo: add logging support.
+  std::cout << "startNotification: Interest Sent: " << interest << std::endl;
+
+  m_lastInterestId = m_face.expressInterest(interest,
+                                            bind(&FaceMonitor::onNotification, this, _2),
+                                            bind(&FaceMonitor::onTimeout, this));
+}
+
+void
+FaceMonitor::addSubscriber(const NotificationCallback& notificationCallback)
+{
+  addSubscriber(notificationCallback, TimeoutCallback());
+}
+
+void
+FaceMonitor::addSubscriber(const NotificationCallback& notificationCallback,
+                           const TimeoutCallback&  timeoutCallback)
+{
+  if (static_cast<bool>(notificationCallback))
+    m_notificationCallbacks.push_back(notificationCallback);
+
+  if (static_cast<bool>(timeoutCallback))
+    m_timeoutCallbacks.push_back(timeoutCallback);
+}
+
+void
+FaceMonitor::onTimeout()
+{
+  if (m_isStopped)
+    return;
+
+  std::vector<TimeoutCallback>::iterator it;
+  for (it = m_timeoutCallbacks.begin();
+       it != m_timeoutCallbacks.end(); ++it) {
+    (*it)();
+    //One of the registered callbacks has cleared the vector,
+    //return now as the iterator has been invalidated and
+    //the vector is empty.
+    if (m_timeoutCallbacks.empty()) {
+       return;
+    }
+  }
+
+  Interest newInterest("/localhost/nfd/faces/events");
+  newInterest
+    .setMustBeFresh(true)
+    .setChildSelector(1)
+    .setInterestLifetime(time::seconds(60))
+    ;
+
+  //todo: add logging support.
+  std::cout << "In onTimeout, sending interest: " << newInterest << std::endl;
+
+  m_lastInterestId = m_face.expressInterest(newInterest,
+                                            bind(&FaceMonitor::onNotification, this, _2),
+                                            bind(&FaceMonitor::onTimeout, this));
+}
+
+void
+FaceMonitor::onNotification(const Data& data)
+{
+  if (m_isStopped)
+    return;
+
+  m_lastSequence = data.getName().get(-1).toSegment();
+  ndn::nfd::FaceEventNotification notification(data.getContent().blockFromValue());
+
+  std::vector<NotificationCallback>::iterator it;
+  for (it = m_notificationCallbacks.begin();
+       it != m_notificationCallbacks.end(); ++it) {
+    (*it)(notification);
+    if (m_notificationCallbacks.empty()) {
+      //One of the registered callbacks has cleared the vector.
+      //return back, as no one is interested in notifications anymore.
+      return;
+    }
+  }
+
+  //Setting up next notification
+  Name nextNotification("/localhost/nfd/faces/events");
+  nextNotification.appendSegment(m_lastSequence + 1);
+
+  Interest interest(nextNotification);
+  interest.setInterestLifetime(time::seconds(60));
+
+  //todo: add logging support.
+  std::cout << "onNotification: Interest sent: " <<  interest << std::endl;
+
+  m_lastInterestId = m_face.expressInterest(interest,
+                                            bind(&FaceMonitor::onNotification, this, _2),
+                                            bind(&FaceMonitor::onTimeout, this));
+}
+
+}//namespace ndn
+