Checkpoint. Basic support (and not real success) for interest limits
diff --git a/model/fw/per-fib-limits.cc b/model/fw/per-fib-limits.cc
index 89d4cc4..5c2d3a2 100644
--- a/model/fw/per-fib-limits.cc
+++ b/model/fw/per-fib-limits.cc
@@ -20,6 +20,7 @@
 
 #include "per-fib-limits.h"
 
+#include "ns3/ndn-l3-protocol.h"
 #include "ns3/ndn-interest-header.h"
 #include "ns3/ndn-content-object-header.h"
 #include "ns3/ndn-pit.h"
@@ -32,6 +33,7 @@
 #include "ns3/double.h"
 
 #include <boost/foreach.hpp>
+#include <boost/lexical_cast.hpp>
 #include <boost/lambda/lambda.hpp>
 #include <boost/lambda/bind.hpp>
 namespace ll = boost::lambda;
@@ -62,10 +64,24 @@
 void
 PerFibLimits::DoDispose ()
 {
+  m_announceEvent.Cancel ();
+  
   super::DoDispose ();
 }
 
 void
+PerFibLimits::NotifyNewAggregate ()
+{
+  super::NotifyNewAggregate ();
+
+  if (m_pit != 0 && m_fib != 0)
+    {
+      m_announceEvent = Simulator::Schedule (Seconds (1.0),
+                                             &PerFibLimits::AnnounceLimits, this);
+    }
+}
+
+void
 PerFibLimits::RemoveFace (Ptr<Face> face)
 {  
   for (PitQueueMap::iterator item = m_pitQueues.begin ();
@@ -79,6 +95,16 @@
   super::RemoveFace (face);
 }
 
+void
+PerFibLimits::OnInterest (Ptr<Face> face,
+                          Ptr<const InterestHeader> header,
+                          Ptr<const Packet> origPacket)
+{
+  if (header->GetScope () != 0)
+    super::OnInterest (face, header, origPacket);
+  else
+    ApplyAnnouncedLimit (face, header);
+}
 
 bool
 PerFibLimits::TrySendOutInterest (Ptr<Face> inFace,
@@ -137,21 +163,10 @@
   pitEntry->UpdateLifetime (Seconds (0.10));
 
   // const ndnSIM::LoadStatsFace &stats = GetStatsTree ()[header->GetName ()].incoming ().find (inFace)->second;
-  const ndnSIM::LoadStatsFace &stats = GetStatsTree ()["/"].incoming ().find (inFace)->second;
-  double weight = std::min (1.0, stats.GetSatisfiedRatio ().get<0> ());
-  // if (weight < 0)
-  //   {
-  //     // if stats is unknown, gracefully accept interest with normal priority
-  //     weight = 1.0;
-  //   }
-  
-  bool enqueued = m_pitQueues[outFace].Enqueue (inFace, pitEntry, weight);
+  // const ndnSIM::LoadStatsFace &stats = GetStatsTree ()["/"].incoming ().find (inFace)->second;
+  // double weight = std::min (1.0, stats.GetSatisfiedRatio ().get<0> ());
+  bool enqueued = m_pitQueues[outFace].Enqueue (inFace, pitEntry, 1);
 
-  // if (Simulator::GetContext () == 6)
-  //   {
-  //     // std::cerr << "Attempt to enqueue packet for " << pitEntry->GetPrefix () << ": " << (enqueued?"succeeded":"failed") << std::endl;
-  //   }
-  
   if (enqueued)
     {
       NS_LOG_DEBUG ("PIT entry is enqueued for delayed processing. Telling that we forwarding possible");
@@ -280,36 +295,138 @@
                                    uint32_t nackCode,
                                    Ptr<pit::Entry> pitEntry)
 {
-  super::DidReceiveValidNack (inFace, nackCode, pitEntry);
+//   super::DidReceiveValidNack (inFace, nackCode, pitEntry);
   
-  // NS_LOG_FUNCTION (this << pitEntry->GetPrefix ());
-  PitQueue::Remove (pitEntry);
+//   // NS_LOG_FUNCTION (this << pitEntry->GetPrefix ());
+//   PitQueue::Remove (pitEntry);
  
 
-  Ptr<InterestHeader> nackHeader = Create<InterestHeader> (*pitEntry->GetInterest ());
-  // nackHeader->SetNack (100);
-  Ptr<Packet> pkt = Create<Packet> ();
-  pkt->AddHeader (*nackHeader);
+//   Ptr<InterestHeader> nackHeader = Create<InterestHeader> (*pitEntry->GetInterest ());
+//   // nackHeader->SetNack (100);
+//   Ptr<Packet> pkt = Create<Packet> ();
+//   pkt->AddHeader (*nackHeader);
 
-  for (pit::Entry::in_container::iterator face = pitEntry->GetIncoming ().begin ();
-       face != pitEntry->GetIncoming ().end ();
-       face ++)
-    {
-      face->m_face->Send (pkt->Copy ());
-    }
+//   for (pit::Entry::in_container::iterator face = pitEntry->GetIncoming ().begin ();
+//        face != pitEntry->GetIncoming ().end ();
+//        face ++)
+//     {
+//       face->m_face->Send (pkt->Copy ());
+//     }
 
 
   
-  for (pit::Entry::out_container::iterator face = pitEntry->GetOutgoing ().begin ();
-       face != pitEntry->GetOutgoing ().end ();
-       face ++)
+//   for (pit::Entry::out_container::iterator face = pitEntry->GetOutgoing ().begin ();
+//        face != pitEntry->GetOutgoing ().end ();
+//        face ++)
+//     {
+//       face->m_face->GetLimits ().RemoveOutstanding ();
+//     }
+
+//   m_pit->MarkErased (pitEntry);
+  
+//   ProcessFromQueue ();
+}
+
+void
+PerFibLimits::AnnounceLimits ()
+{
+  Ptr<L3Protocol> l3 = GetObject<L3Protocol> ();
+  NS_ASSERT (l3 != 0);
+
+  if (l3->GetNFaces () < 2)
     {
-      face->m_face->GetLimits ().RemoveOutstanding ();
+      m_announceEvent = Simulator::Schedule (Seconds (1.0),
+                                             &PerFibLimits::AnnounceLimits, this);
+      return;
+    }
+  
+  double sumOfWeights = 0;
+  double weightNormalization = 1.0;
+  for (uint32_t faceId = 0; faceId < l3->GetNFaces (); faceId ++)
+    {
+      Ptr<Face> inFace = l3->GetFace (faceId);
+      
+      const ndnSIM::LoadStatsFace &stats = GetStatsTree ()["/"].incoming ().find (inFace)->second;
+      double weight = std::min (1.0, stats.GetSatisfiedRatio ().get<0> ());
+      if (weight < 0) weight = 0.5;
+
+      sumOfWeights += weight;
+    }
+  if (sumOfWeights >= 1)
+    {
+      // disable normalization (not necessary)
+      weightNormalization = 1.0;
+    }
+  else
+    {
+      // sumOfWeights /= (l3->GetNFaces ());
+      weightNormalization = 1 / sumOfWeights;
     }
 
-  m_pit->MarkErased (pitEntry);
+  for (Ptr<fib::Entry> entry = m_fib->Begin ();
+       entry != m_fib->End ();
+       entry = m_fib->Next (entry))
+    {
+      InterestHeader announceInterest;
+      announceInterest.SetScope (0); // link-local
+
+      uint32_t totalAllowance = 0;
+      for (fib::FaceMetricContainer::type::iterator fibFace = entry->m_faces.begin ();
+           fibFace != entry->m_faces.end ();
+           fibFace ++)
+        {
+          totalAllowance += fibFace->m_face->GetLimits ().GetMaxLimit ();
+        }
+      
+      if (totalAllowance == 0)
+        {
+          // don't announce anything, there is no limit
+          continue;
+        }
+      
+      for (uint32_t faceId = 0; faceId < l3->GetNFaces (); faceId ++)
+        {
+          Ptr<Face> inFace = l3->GetFace (faceId);
+
+          const ndnSIM::LoadStatsFace &stats = GetStatsTree ()["/"].incoming ().find (inFace)->second;
+          double weight = std::min (1.0, stats.GetSatisfiedRatio ().get<0> ());
+          if (weight < 0) weight = 0.5;
+
+          Ptr<NameComponents> prefixWithLimit = Create<NameComponents> (entry->GetPrefix ());
+          (*prefixWithLimit)
+            ("limit")
+            (static_cast<uint32_t> (std::max (1.0, weightNormalization * weight * totalAllowance)));
+          
+          announceInterest.SetName (prefixWithLimit);
+          // lifetime is 0
+
+          Ptr<Packet> pkt = Create<Packet> ();
+          pkt->AddHeader (announceInterest);
+
+          inFace->Send (pkt);
+        }
+    }
+
+  m_announceEvent = Simulator::Schedule (Seconds (1.0),
+                                         &PerFibLimits::AnnounceLimits, this);
+}
+
+void
+PerFibLimits::ApplyAnnouncedLimit (Ptr<Face> inFace,
+                                   Ptr<const InterestHeader> header)
+{
+  // Ptr<fib::Entry> fibEntry = m_fib->LongestPrefixMatch (header);
+  // if (fibEntry == 0)
+  //   return;
+
+  uint32_t limit = boost::lexical_cast<uint32_t> (header->GetName ().GetLastComponent ());
+  inFace->GetLimits ().SetMaxLimit (limit);
   
-  ProcessFromQueue ();
+  // if (Simulator::GetContext () == 6 || Simulator::GetContext () == 4)
+  //   {
+      // std::cerr << Simulator::Now ().ToDouble (Time::S) << "s  from:" << *inFace << " " << *header << std::endl;
+      // std::cerr << header->GetName ().GetLastComponent () << ", " << boost::lexical_cast<uint32_t> (header->GetName ().GetLastComponent ()) << std::endl;
+  //   }
 }
 
 
diff --git a/model/fw/per-fib-limits.h b/model/fw/per-fib-limits.h
index 298c9ee..4088ae2 100644
--- a/model/fw/per-fib-limits.h
+++ b/model/fw/per-fib-limits.h
@@ -51,6 +51,11 @@
   PerFibLimits ();
 
   virtual void
+  OnInterest (Ptr<Face> face,
+              Ptr<const InterestHeader> header,
+              Ptr<const Packet> origPacket);
+  
+  virtual void
   WillEraseTimedOutPendingInterest (Ptr<pit::Entry> pitEntry);
 
   virtual void
@@ -76,14 +81,26 @@
 private:
   void
   ProcessFromQueue ();
+
+  void
+  AnnounceLimits ();
+
+  void
+  ApplyAnnouncedLimit (Ptr<Face> inFace,
+                       Ptr<const InterestHeader> header);
   
   // from Object
-  void
+  virtual void
+  NotifyNewAggregate (); ///< @brief Even when object is aggregated to another Object
+
+  virtual void
   DoDispose ();
     
 private:
   typedef std::map< Ptr<Face>, PitQueue > PitQueueMap;
   PitQueueMap m_pitQueues; // per-outgoing face pit queue
+
+  EventId m_announceEvent;
 };