Initial steps in stats tree building. Almost done, but something is fishy
diff --git a/model/ccnx-face.h b/model/ccnx-face.h
index 8bae198..1119ba8 100644
--- a/model/ccnx-face.h
+++ b/model/ccnx-face.h
@@ -208,6 +208,14 @@
    *
    * Internal index is used for comparison.
    */
+  inline bool
+  operator!= (const CcnxFace &face) const;
+  
+  /**
+   * \brief Compare two faces. Only two faces on the same node could be compared.
+   *
+   * Internal index is used for comparison.
+   */
   bool
   operator< (const CcnxFace &face) const;
 
@@ -266,6 +274,13 @@
   return m_id;
 }
 
+inline bool
+CcnxFace::operator!= (const CcnxFace &face) const
+{
+  return !(*this == face);
+}
+
+
 } // namespace ns3
 
 #endif //CCNX_FACE_H
diff --git a/test/ndnSIM-stats-tree.cc b/test/ndnSIM-stats-tree.cc
new file mode 100644
index 0000000..8e522c5
--- /dev/null
+++ b/test/ndnSIM-stats-tree.cc
@@ -0,0 +1,176 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011,2012 University of California, Los Angeles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include "ndnSIM-stats-tree.h"
+#include "ns3/core-module.h"
+#include "ns3/ndnSIM-module.h"
+#include "../utils/stats-tree.h"
+#include "../apps/ccnx-producer.h"
+
+#include <boost/lexical_cast.hpp>
+
+NS_LOG_COMPONENT_DEFINE ("CcnxStatsTreeTest");
+
+using namespace ndnSIM;
+
+namespace ns3
+{
+
+void
+StatsTreeTest::DoRun ()
+{
+  CcnxStackHelper ccnx;
+
+  Ptr<Node> node1   = CreateObject<Node> ();
+  Ptr<CcnxApp> app1 = CreateObject<CcnxProducer> ();
+  node1->AddApplication (app1);
+  ccnx.Install (node1);
+
+  Ptr<CcnxFace> face1 = CreateObject<CcnxAppFace> (app1);
+  Ptr<CcnxFace> face2 = CreateObject<CcnxAppFace> (app1);
+  Ptr<CcnxFace> face3 = CreateObject<CcnxAppFace> (app1);
+
+  node1->GetObject<Ccnx> ()->AddFace (face1);
+  node1->GetObject<Ccnx> ()->AddFace (face2);
+  node1->GetObject<Ccnx> ()->AddFace (face3);
+
+  NS_LOG_DEBUG (*face1 << ", " << *face2 << ", " << *face3);
+  
+  NS_TEST_ASSERT_MSG_NE (*face1, *face2, "Face1 should not be equal to Face2");
+  NS_TEST_ASSERT_MSG_NE (face1, face2, "&Face1 should not be equal to &Face2");
+  NS_TEST_ASSERT_MSG_NE (*face2, *face3, "Face2 should not be equal to Face3");
+  NS_TEST_ASSERT_MSG_NE (face2, face3, "&Face2 should not be equal to &Face3");
+
+  // hack
+  face3->SetId (0);
+  NS_TEST_ASSERT_MSG_EQ (*face1, *face3, "Face1 should be now equal to Face3");
+  NS_TEST_ASSERT_MSG_NE (face1, face3, "&Face1 should not be equal to &Face3");
+
+  LoadStatsNode::stats_container bla;
+  bla[face1].Step (); 
+  bla[face2].Step ();
+
+  NS_TEST_ASSERT_MSG_EQ (bla.size (), 2, "Should be two entries in the container");
+
+  bla[face3].Step ();
+  NS_TEST_ASSERT_MSG_EQ (bla.size (), 2, "Should be still two entries in the container");
+
+  LoadStatsNode node;
+  node.AddIncoming (face1);
+  node.AddIncoming (face1);
+  node.AddIncoming (face2);
+  node.AddIncoming (face3);
+
+  NS_TEST_ASSERT_MSG_EQ (node.incoming ().size (), 2, "Incoming should have two entries again");
+  NS_TEST_ASSERT_MSG_EQ (node.outgoing ().size (), 0, "Outgoing should have 0 entries");
+
+  node.Satisfy ();
+  node.Satisfy ();
+  NS_TEST_ASSERT_MSG_EQ (node.incoming ().size (), 2, "Incoming should have two entries again");
+  NS_TEST_ASSERT_MSG_EQ (node.outgoing ().size (), 0, "Outgoing should have 0 entries");
+
+  node.Timeout ();
+  NS_TEST_ASSERT_MSG_EQ (node.incoming ().size (), 2, "Incoming should have two entries again");
+  NS_TEST_ASSERT_MSG_EQ (node.outgoing ().size (), 0, "Outgoing should have 0 entries");
+
+  NS_LOG_DEBUG ("count:      " << node.incoming ().find (face1)->second.count ());
+  NS_LOG_DEBUG ("satisfied:  " << node.incoming ().find (face1)->second.satisfied ());
+  NS_LOG_DEBUG ("unsatisfied:" << node.incoming ().find (face1)->second.unsatisfied ());
+
+  node.Step ();
+  
+  NS_LOG_DEBUG ("count:      " << node.incoming ().find (face1)->second.count ());
+  NS_LOG_DEBUG ("satisfied:  " << node.incoming ().find (face1)->second.satisfied ());
+  NS_LOG_DEBUG ("unsatisfied:" << node.incoming ().find (face1)->second.unsatisfied ());
+  
+  LoadStats::stats_tuple tuple = node.incoming ().find (face1)->second.GetSatisfiedRatio ();
+  NS_LOG_DEBUG ("In, face1, satisfied ratio: " << tuple.get<0> () << ", " << tuple.get<1> () << ", " << tuple.get<2> ());
+
+  NS_TEST_ASSERT_MSG_EQ_TOL (tuple.get<0> (), 0.667, 0.01, "Satisfied ratio should be ~ 2/3");
+  NS_TEST_ASSERT_MSG_EQ_TOL (tuple.get<1> (), 0.667, 0.01, "Satisfied ratio should be ~ 2/3");
+  NS_TEST_ASSERT_MSG_EQ_TOL (tuple.get<2> (), 0.667, 0.01, "Satisfied ratio should be ~ 2/3");
+  
+  tuple = node.incoming ().find (face1)->second.GetUnsatisfiedRatio ();
+  NS_LOG_DEBUG ("In, face1, unsatisfied ratio: " << tuple.get<0> () << ", " << tuple.get<1> () << ", " << tuple.get<2> ());
+
+  NS_TEST_ASSERT_MSG_EQ_TOL (tuple.get<0> (), 0.333, 0.01, "Satisfied ratio should be ~ 1/3");
+  NS_TEST_ASSERT_MSG_EQ_TOL (tuple.get<1> (), 0.333, 0.01, "Satisfied ratio should be ~ 1/3");
+  NS_TEST_ASSERT_MSG_EQ_TOL (tuple.get<2> (), 0.333, 0.01, "Satisfied ratio should be ~ 1/3");
+
+  node.AddIncoming (face1);
+  node.Timeout ();
+  node.Step ();
+
+  NS_LOG_DEBUG ("After decaying");
+  
+  tuple = node.incoming ().find (face1)->second.GetSatisfiedRatio ();
+  NS_LOG_DEBUG ("In, face1, satisfied ratio: " << tuple.get<0> () << ", " << tuple.get<1> () << ", " << tuple.get<2> ());
+
+  NS_TEST_ASSERT_MSG_EQ_TOL (tuple.get<0> (), 0.489, 0.01, "");
+  NS_TEST_ASSERT_MSG_EQ_TOL (tuple.get<1> (), 0.489, 0.01, "");
+  NS_TEST_ASSERT_MSG_EQ_TOL (tuple.get<2> (), 0.489, 0.01, "");
+  
+  tuple = node.incoming ().find (face1)->second.GetUnsatisfiedRatio ();
+  NS_LOG_DEBUG ("In, face1, unsatisfied ratio: " << tuple.get<0> () << ", " << tuple.get<1> () << ", " << tuple.get<2> ());
+
+  NS_TEST_ASSERT_MSG_EQ_TOL (tuple.get<0> (), 0.51, 0.01, "");
+  NS_TEST_ASSERT_MSG_EQ_TOL (tuple.get<1> (), 0.51, 0.01, "");
+  NS_TEST_ASSERT_MSG_EQ_TOL (tuple.get<2> (), 0.51, 0.01, "");  
+
+  for (uint32_t i = 0; i < 50; i++ )
+    node.Step ();
+
+  NS_LOG_DEBUG ("After more decaying");
+
+  tuple = node.incoming ().find (face1)->second.GetSatisfiedRatio ();
+  NS_LOG_DEBUG ("In, face1, satisfied ratio: " << tuple.get<0> () << ", " << tuple.get<1> () << ", " << tuple.get<2> ());
+
+  NS_TEST_ASSERT_MSG_EQ_TOL (tuple.get<0> (), 0.228, 0.01, "");
+  NS_TEST_ASSERT_MSG_EQ_TOL (tuple.get<1> (), 0.047, 0.01, "");
+  NS_TEST_ASSERT_MSG_EQ_TOL (tuple.get<2> (), 0.015, 0.01, "");
+  
+  tuple = node.incoming ().find (face1)->second.GetUnsatisfiedRatio ();
+  NS_LOG_DEBUG ("In, face1, unsatisfied ratio: " << tuple.get<0> () << ", " << tuple.get<1> () << ", " << tuple.get<2> ());
+
+  NS_TEST_ASSERT_MSG_EQ_TOL (tuple.get<0> (), 0.238, 0.01, "");
+  NS_TEST_ASSERT_MSG_EQ_TOL (tuple.get<1> (), 0.049, 0.01, "");
+  NS_TEST_ASSERT_MSG_EQ_TOL (tuple.get<2> (), 0.016, 0.01, "");
+
+  /////////////////////////////////////////////////////
+  //              Actual tree testing                //
+  /////////////////////////////////////////////////////
+
+  StatsTree tree;
+  tree.NewPitEntry (CcnxNameComponents ("/bla/bla/bla"));
+  tree.NewPitEntry (CcnxNameComponents ("/foo/bar"));
+  tree.NewPitEntry (CcnxNameComponents ("/bar/foo"));
+  tree.NewPitEntry (CcnxNameComponents ("/tra/la/la"));
+
+  tree.Incoming (CcnxNameComponents ("/bla/bla/bla"), face1);
+  tree.Outgoing (CcnxNameComponents ("/foo/bar"), face2);
+  tree.Satisfy  (CcnxNameComponents ("/bar/foo"));
+  tree.Satisfy  (CcnxNameComponents ("/tra/la/la"));
+
+  tree.Step ();
+  
+  NS_LOG_DEBUG (tree);
+}
+
+}
diff --git a/test/ndnSIM-stats-tree.h b/test/ndnSIM-stats-tree.h
new file mode 100644
index 0000000..504257c
--- /dev/null
+++ b/test/ndnSIM-stats-tree.h
@@ -0,0 +1,44 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011 University of California, Los Angeles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef NDNSIM_TEST_STATS_TREE_H
+#define NDNSIM_TEST_STATS_TREE_H
+
+#include "ns3/test.h"
+#include "ns3/ptr.h"
+
+namespace ns3
+{
+
+class StatsTreeTest : public TestCase
+{
+public:
+  StatsTreeTest ()
+    : TestCase ("StatsTree test")
+  {
+  }
+    
+private:
+  virtual void DoRun ();
+};
+  
+}
+
+#endif // NDNSIM_TEST_STATS_TREE_H
diff --git a/test/ndnSIM-tests.cc b/test/ndnSIM-tests.cc
index 004f761..e62dc19 100644
--- a/test/ndnSIM-tests.cc
+++ b/test/ndnSIM-tests.cc
@@ -23,6 +23,7 @@
 
 #include "ndnSIM-serialization.h"
 #include "ndnSIM-pit.h"
+#include "ndnSIM-stats-tree.h"
 
 namespace ns3
 {
@@ -38,6 +39,7 @@
     AddTestCase (new InterestSerializationTest ());
     AddTestCase (new ContentObjectSerializationTest ());
     AddTestCase (new PitTest ());
+    AddTestCase (new StatsTreeTest ());
   }
 };
 
diff --git a/utils/load-stats-face.cc b/utils/load-stats-face.cc
new file mode 100644
index 0000000..834004a
--- /dev/null
+++ b/utils/load-stats-face.cc
@@ -0,0 +1,68 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011 University of California, Los Angeles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include "load-stats-face.h"
+
+namespace ndnSIM
+{
+
+void
+LoadStatsFace::Step ()
+{
+  m_count.Step ();
+  m_satisfied.Step ();
+  m_unsatisfied.Step ();
+}
+  
+//
+LoadStats::stats_tuple
+LoadStatsFace::GetSatisfiedRatio () const
+{
+  return LoadStats::stats_tuple (m_satisfied.GetStats ().get<0> () / std::max (0.01, m_count.GetStats ().get<0> ()),
+				 m_satisfied.GetStats ().get<1> () / std::max (0.01, m_count.GetStats ().get<1> ()),
+				 m_satisfied.GetStats ().get<2> () / std::max (0.01, m_count.GetStats ().get<2> ()));
+}
+
+LoadStats::stats_tuple
+LoadStatsFace::GetUnsatisfiedRatio () const
+{
+  return LoadStats::stats_tuple (m_unsatisfied.GetStats ().get<0> () / std::max (0.01, m_count.GetStats ().get<0> ()),
+				 m_unsatisfied.GetStats ().get<1> () / std::max (0.01, m_count.GetStats ().get<1> ()),
+				 m_unsatisfied.GetStats ().get<2> () / std::max (0.01, m_count.GetStats ().get<2> ()));
+}
+  
+LoadStatsFace &
+LoadStatsFace::operator += (const LoadStatsFace &load)
+{
+  m_count       += load.m_count;
+  m_satisfied   += load.m_satisfied;
+  m_unsatisfied += load.m_unsatisfied;
+
+  return *this;
+}
+
+std::ostream &
+operator << (std::ostream &os, const LoadStatsFace &stats)
+{
+  os << stats.m_count << "/" << stats.m_satisfied << "/" << stats.m_unsatisfied;
+  return os;
+}
+
+}
diff --git a/utils/load-stats-face.h b/utils/load-stats-face.h
new file mode 100644
index 0000000..ad033b4
--- /dev/null
+++ b/utils/load-stats-face.h
@@ -0,0 +1,101 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011 University of California, Los Angeles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef LOAD_STATS_FACE_H
+#define LOAD_STATS_FACE_H
+
+#include "load-stats.h"
+
+namespace ndnSIM
+{
+
+class LoadStatsFace
+{
+public:
+  void
+  Step ();
+
+  inline LoadStats&
+  count ();
+
+  inline const LoadStats&
+  count () const;
+
+  inline LoadStats&
+  satisfied ();
+
+  inline const LoadStats&
+  satisfied () const;
+  
+  inline LoadStats&
+  unsatisfied ();
+
+  inline const LoadStats&
+  unsatisfied () const;
+  
+  //
+  LoadStats::stats_tuple
+  GetSatisfiedRatio () const;
+
+  LoadStats::stats_tuple
+  GetUnsatisfiedRatio () const;
+
+  LoadStatsFace &
+  operator += (const LoadStatsFace &load);
+  
+private:
+  LoadStats m_count;
+  LoadStats m_satisfied;
+  LoadStats m_unsatisfied;
+
+  friend std::ostream &
+  operator << (std::ostream &os, const LoadStatsFace &stats);
+};
+
+inline LoadStats&
+LoadStatsFace::count ()
+{ return m_count; }
+
+inline const LoadStats&
+LoadStatsFace::count () const
+{ return m_count; }
+
+inline LoadStats&
+LoadStatsFace::satisfied ()
+{ return m_satisfied; }
+
+inline const LoadStats&
+LoadStatsFace::satisfied () const
+{ return m_satisfied; }
+
+inline LoadStats&
+LoadStatsFace::unsatisfied ()
+{ return m_unsatisfied; }
+
+inline const LoadStats&
+LoadStatsFace::unsatisfied () const
+{ return m_unsatisfied; }
+
+std::ostream &
+operator << (std::ostream &os, const LoadStatsFace &stats);
+
+}
+
+#endif // LOAD_STATS_FACE_H
diff --git a/utils/load-stats-node.cc b/utils/load-stats-node.cc
new file mode 100644
index 0000000..34875c5
--- /dev/null
+++ b/utils/load-stats-node.cc
@@ -0,0 +1,139 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011 University of California, Los Angeles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include "load-stats-node.h"
+#include "ns3/ccnx-face.h"
+
+using namespace ns3;
+
+namespace ndnSIM
+{
+
+void
+LoadStatsNode::Step ()
+{
+  m_pit.Step ();
+  
+  for (stats_container::iterator item = m_incoming.begin ();
+       item != m_incoming.end ();
+       item ++)
+    {
+      item->second.Step ();
+    }
+  
+  for (stats_container::iterator item = m_outgoing.begin ();
+       item != m_outgoing.end ();
+       item ++)
+    {
+      item->second.Step ();
+    }
+}
+
+void
+LoadStatsNode::NewPitEntry ()
+{
+  m_pit.count ()++;
+}
+
+void
+LoadStatsNode::AddIncoming (ns3::Ptr<ns3::CcnxFace> face)
+{
+  m_incoming [face].count ()++;
+}
+
+void
+LoadStatsNode::AddOutgoing (ns3::Ptr<ns3::CcnxFace> face)
+{
+  m_outgoing [face].count ()++;
+}
+
+void
+LoadStatsNode::Satisfy ()
+{
+  m_pit.satisfied ()++;
+  
+  for (stats_container::iterator item = m_incoming.begin ();
+       item != m_incoming.end ();
+       item ++)
+    {
+      item->second.satisfied ()++;
+    }
+
+  for (stats_container::iterator item = m_outgoing.begin ();
+       item != m_outgoing.end ();
+       item ++)
+    {
+      item->second.satisfied ()++;
+    }
+}
+
+void
+LoadStatsNode::Timeout ()
+{
+  m_pit.unsatisfied ()++;
+  
+  for (stats_container::iterator item = m_incoming.begin ();
+       item != m_incoming.end ();
+       item ++)
+    {
+      item->second.unsatisfied ()++;
+    }
+
+  for (stats_container::iterator item = m_outgoing.begin ();
+       item != m_outgoing.end ();
+       item ++)
+    {
+      item->second.unsatisfied ()++;
+    }
+}
+
+LoadStatsNode &
+LoadStatsNode::operator += (const LoadStatsNode &stats)
+{
+  m_pit += stats.m_pit;
+  
+  // aggregate incoming
+  for (stats_container::const_iterator item = stats.m_incoming.begin ();
+       item != stats.m_incoming.end ();
+       item ++)
+    {
+      m_incoming [item->first] += item->second;
+    }
+  
+  // aggregate outgoing
+  for (stats_container::const_iterator item = stats.m_outgoing.begin ();
+       item != stats.m_outgoing.end ();
+       item ++)
+    {
+      m_outgoing [item->first] += item->second;
+    }
+
+  return *this;
+}
+
+std::ostream&
+operator << (std::ostream &os, const LoadStatsNode &node)
+{
+  os << "PIT: " << node.m_pit << std::endl;
+  return os;
+}
+
+
+}
diff --git a/utils/load-stats-node.h b/utils/load-stats-node.h
new file mode 100644
index 0000000..5376144
--- /dev/null
+++ b/utils/load-stats-node.h
@@ -0,0 +1,142 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011 University of California, Los Angeles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef LOAD_STATS_NODE_H
+#define LOAD_STATS_NODE_H
+
+#include "load-stats-face.h"
+#include <map>
+#include "ns3/ptr.h"
+
+namespace ns3
+{
+class CcnxFace;
+}
+
+namespace ndnSIM
+{
+
+// this thing is actually put into a tree node, associated with each "name entry"
+
+class LoadStatsNode
+{
+public:
+  typedef std::map< ns3::Ptr<ns3::CcnxFace>, LoadStatsFace > stats_container;
+
+  LoadStatsNode () {}
+  LoadStatsNode (const LoadStatsNode &) {}
+
+  void
+  Step ();
+
+  /**
+   * Increment face-independent counter
+   */
+  void
+  NewPitEntry ();
+  
+  /**
+   * Increment counter to incoming list
+   */
+  void
+  AddIncoming (ns3::Ptr<ns3::CcnxFace> face);
+
+  /**
+   * Increment counter to outgoing list
+   */
+  void
+  AddOutgoing (ns3::Ptr<ns3::CcnxFace> face);
+
+  /**
+   * Increment counter to both incoming and outgoing lists, for all faces
+   */
+  void
+  Satisfy ();
+
+  /**
+   * Increment counter to both incoming and outgoing lists, for all faces
+   */
+  void
+  Timeout ();
+
+  LoadStatsNode &
+  operator += (const LoadStatsNode &stats);
+
+  inline const stats_container &
+  incoming () const;
+  
+  inline const stats_container &
+  outgoing () const;
+
+  inline const LoadStatsFace &
+  pit () const;
+
+  bool
+  operator == (const LoadStatsNode &other) const
+  {
+    return false;
+  }
+
+  bool
+  operator != (const LoadStatsNode &other) const
+  {
+    return true;
+  }
+
+  LoadStatsNode &
+  operator = (const LoadStatsNode &other)
+  {
+    // don't do any copying at all
+    return *this;
+  }
+  
+private:
+  LoadStatsFace   m_pit;
+  stats_container m_incoming;
+  stats_container m_outgoing;
+
+  friend std::ostream&
+  operator << (std::ostream &os, const LoadStatsNode &node);
+};
+
+inline const LoadStatsNode::stats_container &
+LoadStatsNode::incoming () const
+{
+  return m_incoming;
+}
+  
+inline const LoadStatsNode::stats_container &
+LoadStatsNode::outgoing () const
+{
+  return m_outgoing;
+}
+
+inline const LoadStatsFace &
+LoadStatsNode::pit () const
+{
+  return m_pit;
+}
+
+std::ostream&
+operator << (std::ostream &os, const LoadStatsNode &node);
+
+}
+
+#endif
diff --git a/utils/load-stats.cc b/utils/load-stats.cc
new file mode 100644
index 0000000..ee61df4
--- /dev/null
+++ b/utils/load-stats.cc
@@ -0,0 +1,101 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011 University of California, Los Angeles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include "load-stats.h"
+
+using namespace ns3;
+
+const double EXP_1  = exp (-5.0/60.0);  /* 1/exp(5sec/1min) */
+const double EXP_5  = exp (-5.0/300.0); /* 1/exp(5sec/5min) */
+const double EXP_15 = exp (-5.0/900.0); /* 1/exp(5sec/15min) */
+
+const double EPSILON = 0.000001;
+
+namespace ndnSIM
+{
+
+LoadStats::LoadStats ()
+  : counter_ (0)
+  , avg1_ (0)
+  , avg5_ (0)
+  , avg15_ (0)
+{
+}
+
+void
+LoadStats::Step ()
+{
+  // do magic
+  avg1_  = EXP_1 * avg1_  + (1 - EXP_1)  * counter_;
+  avg5_  = EXP_1 * avg5_  + (1 - EXP_5)  * counter_;
+  avg15_ = EXP_1 * avg15_ + (1 - EXP_15) * counter_;
+
+  counter_ = 0;
+}
+
+LoadStats &
+LoadStats::operator ++ (int)
+{
+  counter_ ++;
+  return *this;
+}
+
+// void
+// LoadStats::Increment (uint32_t amount)
+// {
+//   counter_ += amount;
+// }
+
+// uint32_t
+// LoadStats::GetCounter () const
+// {
+//   return counter_;
+// }
+
+LoadStats &
+LoadStats::operator += (const LoadStats &stats)
+{
+  counter_ += stats.counter_;
+  return *this;
+}
+
+LoadStats::stats_tuple
+LoadStats::GetStats () const
+{
+  return stats_tuple (avg1_, avg5_, avg15_);
+}
+
+bool
+LoadStats::IsEmpty () const
+{
+  return (avg1_ < EPSILON &&
+	  avg5_ < EPSILON &&
+	  avg15_ < EPSILON);
+}
+
+std::ostream &
+operator << (std::ostream &os, const LoadStats &stats)
+{
+  LoadStats::stats_tuple data = stats.GetStats ();
+  os << data.get<0> () << ", " << data.get<1> () << ", " << data.get<2> ();// << std::endl;
+  return os;
+}
+
+} // ndnSIM
diff --git a/utils/load-stats.h b/utils/load-stats.h
new file mode 100644
index 0000000..8b2433e
--- /dev/null
+++ b/utils/load-stats.h
@@ -0,0 +1,71 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011 University of California, Los Angeles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef LOAD_STATS_H
+#define LOAD_STATS_H
+
+#include "ns3/nstime.h"
+#include <boost/tuple/tuple.hpp>
+
+namespace ndnSIM
+{
+
+class LoadStats
+{
+public:
+  typedef boost::tuple<double, double, double> stats_tuple;
+
+  LoadStats ();
+  
+  void
+  Step ();
+
+  // void
+  // Increment (uint32_t amount);
+
+  LoadStats &
+  operator ++ (int);
+  
+  // uint32_t
+  // GetCounter () const;
+
+  LoadStats &
+  operator += (const LoadStats &stats);
+
+  stats_tuple
+  GetStats () const;
+
+  bool
+  IsEmpty () const;
+  
+private:
+  uint32_t counter_;
+
+  double avg1_;
+  double avg5_;
+  double avg15_;
+};
+
+std::ostream &
+operator << (std::ostream &os, const LoadStats &stats);
+
+} // ndnSIM
+
+#endif // LOAD_STATS_H
diff --git a/utils/stats-tree.cc b/utils/stats-tree.cc
new file mode 100644
index 0000000..eb37c02
--- /dev/null
+++ b/utils/stats-tree.cc
@@ -0,0 +1,127 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2012 University of California, Los Angeles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include "stats-tree.h"
+#include "ns3/ccnx-face.h"
+#include "ns3/log.h"
+
+using namespace ns3;
+
+NS_LOG_COMPONENT_DEFINE ("StatsTree");
+
+namespace ndnSIM
+{
+
+StatsTree::StatsTree ()
+  : m_tree ("")
+{
+}
+
+void
+StatsTree::Step ()
+{
+  // walking the tree, aggregating and stepping on every node, starting the leaves
+  // for (trie_type::
+
+  WalkLeftRightRoot (&m_tree);
+}
+
+void
+StatsTree::NewPitEntry (const ns3::CcnxNameComponents &key)
+{
+  std::pair<tree_type::iterator, bool> item = m_tree.insert (key, LoadStatsNode ());
+  NS_ASSERT (item.second == false); // should always return false
+
+  item.first->payload ().NewPitEntry ();
+  NS_LOG_DEBUG ("NewPitEntry: " << item.first->payload ());
+}
+
+void
+StatsTree::Incoming (const CcnxNameComponents &key, Ptr<CcnxFace> face)
+{
+  std::pair<tree_type::iterator, bool> item = m_tree.insert (key, LoadStatsNode ());
+  NS_ASSERT (item.second == false); // should always return false
+
+  item.first->payload ().AddIncoming (face);
+}
+
+void
+StatsTree::Outgoing (const CcnxNameComponents &key, Ptr<CcnxFace> face)
+{
+  std::pair<tree_type::iterator, bool> item = m_tree.insert (key, LoadStatsNode ());
+  NS_ASSERT (item.second == false); // should always return false
+
+  item.first->payload ().AddOutgoing (face);
+}
+
+void
+StatsTree::Satisfy (const CcnxNameComponents &key)
+{
+  std::pair<tree_type::iterator, bool> item = m_tree.insert (key, LoadStatsNode ());
+  NS_ASSERT (item.second == false); // should always return false
+
+  item.first->payload ().Satisfy ();
+}
+
+void
+StatsTree::Timeout (const CcnxNameComponents &key)
+{
+  std::pair<tree_type::iterator, bool> item = m_tree.insert (key, LoadStatsNode ());
+  NS_ASSERT (item.second == false); // should always return false
+
+  item.first->payload ().Timeout ();
+}
+
+const LoadStatsNode &
+StatsTree::Get (const ns3::CcnxNameComponents &key) const
+{
+  tree_type::iterator foundItem, lastItem;
+  bool reachLast;
+  boost::tie (foundItem, reachLast, lastItem) = const_cast<tree_type&> (m_tree).find (key);
+
+  NS_ASSERT_MSG (foundItem == lastItem, "Found item should always be the same as last item (same address)");
+
+  return foundItem->payload ();
+}
+
+const LoadStatsNode&
+StatsTree::WalkLeftRightRoot (tree_type *node)
+{
+  tree_type::point_iterator item (*node), end;
+  
+  for (; item != end; item++)
+    {
+      node->payload () += WalkLeftRightRoot (&*item);
+      NS_LOG_DEBUG (node << ", " << node->payload ());
+    }
+
+  node->payload ().Step ();
+  return node->payload ();
+}
+
+std::ostream &
+operator << (std::ostream &os, const StatsTree &tree)
+{
+  os << tree.m_tree.payload ();
+  return os;
+}
+
+
+}
diff --git a/utils/stats-tree.h b/utils/stats-tree.h
new file mode 100644
index 0000000..e731d32
--- /dev/null
+++ b/utils/stats-tree.h
@@ -0,0 +1,77 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011 University of California, Los Angeles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef STATS_TREE_H
+#define STATS_TREE_H
+
+#include "trie.h"
+#include "load-stats-node.h"
+#include "ns3/ccnx-name-components.h"
+#include "ns3/ptr.h"
+
+namespace ndnSIM
+{
+
+class StatsTree
+{
+public:
+  typedef trie< ns3::CcnxNameComponents,
+                non_pointer_traits< LoadStatsNode >, void* > tree_type;
+  
+  StatsTree ();
+
+  void
+  Step ();
+  
+  void
+  NewPitEntry (const ns3::CcnxNameComponents &key);
+
+  void
+  Incoming (const ns3::CcnxNameComponents &key, ns3::Ptr<ns3::CcnxFace> face);
+
+  void
+  Outgoing (const ns3::CcnxNameComponents &key, ns3::Ptr<ns3::CcnxFace> face);
+
+  void
+  Satisfy (const ns3::CcnxNameComponents &key);
+
+  void
+  Timeout (const ns3::CcnxNameComponents &key);
+
+  const LoadStatsNode &
+  Get (const ns3::CcnxNameComponents &key) const;
+  
+private:
+  const LoadStatsNode &
+  WalkLeftRightRoot (tree_type *node);
+  
+private:
+  tree_type m_tree;
+
+  friend std::ostream &
+  operator << (std::ostream &os, const StatsTree &tree);
+};
+
+std::ostream &
+operator << (std::ostream &os, const StatsTree &tree);
+
+} // ndnSIM
+
+#endif // STATS_TREE_H
diff --git a/utils/trie-with-policy.h b/utils/trie-with-policy.h
index ea194b3..bb5a668 100644
--- a/utils/trie-with-policy.h
+++ b/utils/trie-with-policy.h
@@ -53,7 +53,7 @@
   }
 
   inline std::pair< iterator, bool >
-  insert (const FullKey &key, typename PayloadTraits::pointer_type payload)
+  insert (const FullKey &key, typename PayloadTraits::insert_type payload)
   {
     std::pair<iterator, bool> item =
       trie_.insert (key, payload);
diff --git a/utils/trie.h b/utils/trie.h
index 50288af..51a7678 100644
--- a/utils/trie.h
+++ b/utils/trie.h
@@ -41,9 +41,12 @@
 template<typename Payload>
 struct pointer_payload_traits
 {
-  typedef Payload         payload_type;
-  typedef Payload*        pointer_type;
-  typedef const Payload*  const_pointer_type;
+  typedef Payload         payload_type; // general type of the payload
+  typedef Payload*        storage_type; // how the payload is actually stored
+  typedef Payload*        insert_type;  // what parameter is inserted
+
+  typedef Payload*        return_type;  // what is returned on access
+  typedef const Payload*  const_return_type; // what is returned on const access
 
   static Payload* empty_payload;
 };
@@ -56,8 +59,11 @@
 struct smart_pointer_payload_traits
 {
   typedef Payload                 payload_type;
-  typedef ns3::Ptr<Payload>       pointer_type;
-  typedef ns3::Ptr<const Payload> const_pointer_type;
+  typedef ns3::Ptr<Payload>       storage_type;
+  typedef ns3::Ptr<Payload>       insert_type;
+  
+  typedef ns3::Ptr<Payload>       return_type;
+  typedef ns3::Ptr<const Payload> const_return_type;
   
   static ns3::Ptr<Payload> empty_payload;
 };
@@ -66,6 +72,23 @@
 ns3::Ptr<Payload>
 smart_pointer_payload_traits<Payload>::empty_payload = 0;
 
+template<typename Payload>
+struct non_pointer_traits
+{
+  typedef Payload         payload_type;
+  typedef Payload         storage_type;
+  typedef const Payload & insert_type; // nothing to insert
+
+  typedef Payload&        return_type;
+  typedef const Payload & const_return_type;
+  
+  static Payload empty_payload;
+};
+
+template<typename Payload>
+Payload 
+non_pointer_traits<Payload>::empty_payload = Payload ();
+
 
 ////////////////////////////////////////////////////
 // forward declarations
@@ -95,6 +118,9 @@
 template<class T>
 class trie_iterator;
 
+template<class T>
+class trie_point_iterator;
+
 template<typename FullKey,
 	 typename PayloadTraits,
          typename PolicyHook >
@@ -109,6 +135,9 @@
   typedef trie_iterator<trie> recursive_iterator;
   typedef trie_iterator<const trie> const_recursive_iterator;
 
+  typedef trie_point_iterator<trie> point_iterator;
+  typedef trie_point_iterator<const trie> const_point_iterator;
+
   typedef PayloadTraits payload_traits;
   
   inline
@@ -164,7 +193,7 @@
 
   inline std::pair<iterator, bool>
   insert (const FullKey &key,
-          typename PayloadTraits::pointer_type payload)
+          typename PayloadTraits::insert_type payload)
   {
     trie *trieNode = this;
   
@@ -331,20 +360,20 @@
     return 0;
   }
 
-  typename PayloadTraits::const_pointer_type
+  typename PayloadTraits::const_return_type
   payload () const
   {
     return payload_;
   }
 
-  typename PayloadTraits::pointer_type
+  typename PayloadTraits::return_type
   payload ()
   {
     return payload_;
   }
 
   void
-  set_payload (typename PayloadTraits::pointer_type payload)
+  set_payload (typename PayloadTraits::insert_type payload)
   {
     payload_ = payload;
   }
@@ -393,7 +422,10 @@
 
   template<class T>
   friend class trie_iterator;
-  
+
+  template<class T>
+  friend class trie_point_iterator;
+
   ////////////////////////////////////////////////
   // Actual data
   ////////////////////////////////////////////////
@@ -408,7 +440,7 @@
   buckets_array buckets_;
   unordered_set children_;
   
-  typename PayloadTraits::pointer_type payload_;
+  typename PayloadTraits::storage_type payload_;
   trie *parent_; // to make cleaning effective
 };
 
@@ -419,7 +451,7 @@
 inline std::ostream&
 operator << (std::ostream &os, const trie<FullKey, PayloadTraits, PolicyHook> &trie_node)
 {
-  os << "# " << trie_node.key_ << ((trie_node.payload_ != 0)?"*":"") << std::endl;
+  os << "# " << trie_node.key_ << ((trie_node.payload_ != PayloadTraits::empty_payload)?"*":"") << std::endl;
   typedef trie<FullKey, PayloadTraits, PolicyHook> trie;
 
   for (typename trie::unordered_set::const_iterator subnode = trie_node.children_.begin ();
@@ -427,8 +459,8 @@
        subnode++ )
   // BOOST_FOREACH (const trie &subnode, trie_node.children_)
     {
-      os << "\"" << &trie_node << "\"" << " [label=\"" << trie_node.key_ << ((trie_node.payload_ != 0)?"*":"") << "\"]\n";
-      os << "\"" << &(*subnode) << "\"" << " [label=\"" << subnode->key_ << ((subnode->payload_ != 0)?"*":"") << "\"]""\n";
+      os << "\"" << &trie_node << "\"" << " [label=\"" << trie_node.key_ << ((trie_node.payload_ != PayloadTraits::empty_payload)?"*":"") << "\"]\n";
+      os << "\"" << &(*subnode) << "\"" << " [label=\"" << subnode->key_ << ((subnode->payload_ != PayloadTraits::empty_payload)?"*":"") << "\"]""\n";
       
       os << "\"" << &trie_node << "\"" << " -> " << "\"" << &(*subnode) << "\"" << "\n";
       os << *subnode;
@@ -442,7 +474,7 @@
 trie<FullKey, PayloadTraits, PolicyHook>
 ::PrintStat (std::ostream &os) const
 {
-  os << "# " << key_ << ((payload_ != 0)?"*":"") << ": " << children_.size() << " children" << std::endl;
+  os << "# " << key_ << ((payload_ != PayloadTraits::empty_payload)?"*":"") << ": " << children_.size() << " children" << std::endl;
   for (size_t bucket = 0, maxbucket = children_.bucket_count ();
        bucket < maxbucket;
        bucket++)
@@ -543,6 +575,65 @@
 };
 
 
+template<class Trie>
+class trie_point_iterator
+{
+private:  
+  typedef typename boost::mpl::if_< boost::is_same<Trie, const Trie>,
+                                    typename Trie::unordered_set::const_iterator,
+                                    typename Trie::unordered_set::iterator>::type set_iterator;
+
+public:
+  trie_point_iterator () : trie_ (0) {}
+  trie_point_iterator (typename Trie::iterator item) : trie_ (item) {}
+  trie_point_iterator (Trie &item)
+  {
+    if (item.children_.size () != 0)
+      trie_ = &*item.children_.begin ();
+    else
+      trie_ = 0;
+  }
+  
+  Trie & operator* () { return *trie_; }
+  const Trie & operator* () const { return *trie_; }
+  Trie * operator-> () { return trie_; }
+  const Trie * operator-> () const { return trie_; }
+  bool operator== (trie_point_iterator<const Trie> &other) const { return (trie_ == other.trie_); }
+  bool operator== (trie_point_iterator<Trie> &other) { return (trie_ == other.trie_); }
+  bool operator!= (trie_point_iterator<const Trie> &other) const { return !(*this == other); }
+  bool operator!= (trie_point_iterator<Trie> &other) { return !(*this == other); }
+  
+  trie_point_iterator<Trie> &
+  operator++ (int)
+  {
+    if (trie_->parent_ != 0)
+      {
+        set_iterator item = trie_->parent_->children_.iterator_to (*trie_);
+        item ++;
+        if (item == trie_->parent_->children_.end ())
+          trie_ = 0;
+        else
+          trie_ = &*item;
+      }
+    else
+      {
+        trie_ = 0;
+      }
+    return *this;
+  }
+
+  trie_point_iterator<Trie> &
+  operator++ ()
+  {
+    (*this)++;
+    return *this;
+  }  
+
+private:
+  Trie *trie_;
+};
+
+
 } // ndnSIM
 
 #endif // TRIE_H_