ndn.cxx: Expressing interests and publishing data use event scheduling, instead of directly calling the callback

Also in this commit is extension, allowing expression of multiple
interests for the same name with different callbacks.  For example, if
user expresses two exactly the same interests, when data arrives or
interest times out, callbacks from the individual call will be invoked.

Another small change is that if interest is "collapsed" in ApiFace, it
is not further propagated to the NDN stack.
diff --git a/ndn.cxx/detail/pending-interests-container.h b/ndn.cxx/detail/pending-interests-container.h
index 4d96ed4..78ab10d 100644
--- a/ndn.cxx/detail/pending-interests-container.h
+++ b/ndn.cxx/detail/pending-interests-container.h
@@ -24,19 +24,19 @@
   PendingInterestEntry (Ptr<const Interest> interest)
     : m_interest (interest)
   { }
-  
+
   void
   AddCallbacks (ApiFace::DataCallback onData, ApiFace::TimeoutCallback onTimeout)
   { 
-    m_dataCallback = onData;
-    m_timeoutCallback = onTimeout;
+    m_dataCallbacks.push_back (onData);
+    m_timeoutCallbacks.push_back (onTimeout);
   }
 
   void
   ClearCallbacks ()
   {
-    m_dataCallback = ApiFace::DataCallback ();
-    m_timeoutCallback = ApiFace::TimeoutCallback ();
+    m_dataCallbacks.clear ();
+    m_timeoutCallbacks.clear ();
   }
 
   Ptr<const Interest>
@@ -44,10 +44,32 @@
   {
     return m_interest;
   }
+
+  void
+  ProcessOnData (Ptr<const Interest> interest, Ptr<const Data> data)
+  {
+    for (std::list<ApiFace::DataCallback>::iterator i = m_dataCallbacks.begin ();
+         i != m_dataCallbacks.end ();
+         i++)
+      {
+        (*i) (interest, data);
+      }
+  }
+
+  void
+  ProcessOnTimeout (Ptr<const Interest> interest)
+  {
+    for (std::list<ApiFace::TimeoutCallback>::iterator i = m_timeoutCallbacks.begin ();
+         i != m_timeoutCallbacks.end ();
+         i++)
+      {
+        (*i) (interest);
+      }
+  }
   
-public:
-  ApiFace::DataCallback m_dataCallback;
-  ApiFace::TimeoutCallback m_timeoutCallback;
+private:
+  std::list<ApiFace::DataCallback> m_dataCallbacks;
+  std::list<ApiFace::TimeoutCallback> m_timeoutCallbacks;
   Ptr<const Interest> m_interest;
 };
 
diff --git a/ndn.cxx/detail/timeouts-policy.h b/ndn.cxx/detail/timeouts-policy.h
index 3a52aa2..7d94be1 100644
--- a/ndn.cxx/detail/timeouts-policy.h
+++ b/ndn.cxx/detail/timeouts-policy.h
@@ -147,8 +147,7 @@
       inline void
       ProcessTimeoutEntry (typename parent_trie::iterator item)
       {
-        if (!item->payload ()->m_timeoutCallback.IsNull ())
-          item->payload ()->m_timeoutCallback (item->payload ()->GetInterest ());
+        item->payload ()->ProcessOnTimeout (item->payload ()->GetInterest ());
 
         m_base.erase (item);
       }
diff --git a/ndn.cxx/ndn-api-face.cc b/ndn.cxx/ndn-api-face.cc
index 4be4162..4d522fa 100644
--- a/ndn.cxx/ndn-api-face.cc
+++ b/ndn.cxx/ndn-api-face.cc
@@ -107,6 +107,7 @@
     }
   
   // Record the callback
+  bool needToActuallyExpressInterest = false;
   PendingInterestContainer::iterator entry = m_this->m_pendingInterests.find_exact (interest->GetName ());
   if (entry == m_this->m_pendingInterests.end ())
     {
@@ -114,10 +115,15 @@
         m_this->m_pendingInterests.insert (interest->GetName (), Create <PendingInterestEntry> (interest));
 
       entry = status.first;
+
+      needToActuallyExpressInterest = true;
     }
   entry->payload ()->AddCallbacks (onData, onTimeout);
 
-  ReceiveInterest (interest);
+  if (needToActuallyExpressInterest)
+    {
+      Simulator::ScheduleNow (&Face::ReceiveInterest, this, interest);
+    }
 }
 
 void
@@ -158,12 +164,10 @@
 {
   NS_LOG_INFO (">> D " << data->GetName ());
   
-  ReceiveData (data);
+  Simulator::ScheduleNow (&Face::ReceiveData, this, data);
 }
 
 
-
-
 ///////////////////////////////////////////////
 // private stuff
 
@@ -197,8 +201,7 @@
 {
   // data has been send out from NDN stack towards the application
   NS_LOG_DEBUG ("<< D " << data->GetName ());
-
-  NS_LOG_FUNCTION (this << data);
+  // NS_LOG_FUNCTION (this << data);
 
   if (!IsUp ())
     {
@@ -213,8 +216,7 @@
 
   while (entry != m_this->m_pendingInterests.end ())
     {
-      if (!entry->payload ()->m_dataCallback.IsNull ())
-        entry->payload ()->m_dataCallback (entry->payload ()->GetInterest (), data);
+      entry->payload ()->ProcessOnData (entry->payload ()->GetInterest (), data);
       m_this->m_pendingInterests.erase (entry);
 
       entry = m_this->m_pendingInterests.longest_prefix_match (data->GetName ());