add zipf-mandelbrot support to NDN Interest app consumer
diff --git a/apps/ndn-consumer-zipf-mandelbrot.cc b/apps/ndn-consumer-zipf-mandelbrot.cc
new file mode 100644
index 0000000..d744143
--- /dev/null
+++ b/apps/ndn-consumer-zipf-mandelbrot.cc
@@ -0,0 +1,209 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2012 Tsinghua University, P.R.China
+ *
+ * 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: Xiaoke Jiang <shock.jiang@gmail.com>
+ */
+
+#include "ndn-consumer-zipf-mandelbrot.h"
+
+#include "ns3/ndn-app-face.h"
+#include "ns3/ndn-interest.h"
+#include "ns3/ndn-content-object.h"
+#include <math.h>
+//#include <random-variable.h>
+
+
+NS_LOG_COMPONENT_DEFINE ("ndn.ConsumerZipfMandelbrot");
+
+namespace ns3 {
+namespace ndn {
+
+NS_OBJECT_ENSURE_REGISTERED (ConsumerZipfMandelbrot);
+
+TypeId
+ConsumerZipfMandelbrot::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::ndn::ConsumerZipfMandelbrot")
+    .SetGroupName ("Ndn")
+    .SetParent<ConsumerCbr> ()
+    .AddConstructor<ConsumerZipfMandelbrot> ()
+    .AddAttribute ("N", "Number of the Contents in total",
+                      StringValue ("100"),
+                      MakeUintegerAccessor (&ConsumerZipfMandelbrot::m_N),
+                      MakeUintegerChecker<uint32_t> ())
+    .AddAttribute ("q", "parameter of improve rank",
+                      StringValue ("0.7"),
+                      MakeDoubleAccessor (&ConsumerZipfMandelbrot::m_q),
+                      MakeDoubleChecker<double>())
+	  .AddAttribute ("s", "parameter of power",
+							StringValue ("0.7"),
+							MakeDoubleAccessor (&ConsumerZipfMandelbrot::m_s),
+							MakeDoubleChecker<double>())
+    ;
+
+  return tid;
+}
+
+
+ConsumerZipfMandelbrot::ConsumerZipfMandelbrot()
+	: m_N(100)
+	, m_q (0.7)
+	, m_s (0.7)
+{
+	m_Pcum = new double[m_N+1];
+	m_Pcum[0] = 0.0;
+	for (uint32_t i=1; i<=m_N; i++) {
+		m_Pcum[i] = m_Pcum[i-1] + 1.0/pow(i+m_q, m_s);
+	}
+	for (uint32_t i=1; i<=m_N; i++) {
+		m_Pcum[i] = m_Pcum[i] / m_Pcum[m_N];
+		NS_LOG_LOGIC("cum Probability ["<<i<<"]="<<m_Pcum[i]);
+	}
+	//Ptr<UniformRandomVariable> m_SeqRng = CreateObject<UniformRandomVariable> ();
+	m_SeqRng = new UniformVariable(0.0, 1.0); //[1, m_N+1)
+	//m_SeqRng = new UniformVariable ();
+}
+
+ConsumerZipfMandelbrot::~ConsumerZipfMandelbrot() {
+	if (m_Pcum) {
+		delete m_Pcum;
+		m_Pcum = NULL;
+	}
+//	if (m_SeqRng) {
+//		delete m_SeqRng;
+//		m_SeqRng = NULL;
+//	}
+}
+
+void
+ConsumerZipfMandelbrot::SendPacket() {
+	  if (!m_active) return;
+
+	  NS_LOG_FUNCTION_NOARGS ();
+
+	  uint32_t seq=std::numeric_limits<uint32_t>::max (); //invalid
+
+	  // std::cout << Simulator::Now ().ToDouble (Time::S) << "s max -> " << m_seqMax << "\n";
+
+	  while (m_retxSeqs.size ())
+	    {
+	      seq = *m_retxSeqs.begin ();
+	      m_retxSeqs.erase (m_retxSeqs.begin ());
+
+	      // NS_ASSERT (m_seqLifetimes.find (seq) != m_seqLifetimes.end ());
+	      // if (m_seqLifetimes.find (seq)->time <= Simulator::Now ())
+	      //   {
+
+	      //     NS_LOG_DEBUG ("Expire " << seq);
+	      //     m_seqLifetimes.erase (seq); // lifetime expired. Trying to find another unexpired sequence number
+	      //     continue;
+	      //   }
+	      NS_LOG_DEBUG("=interest seq "<<seq<<" from m_retxSeqs");
+	      break;
+	    }
+
+	  if (seq == std::numeric_limits<uint32_t>::max ()) //no retransmission
+	    {
+	      if (m_seqMax != std::numeric_limits<uint32_t>::max ())
+	        {
+	          if (m_seq >= m_seqMax)
+	            {
+	              return; // we are totally done
+	            }
+	        }
+
+	      seq = ConsumerZipfMandelbrot::GetNextSeq();
+	      m_seq ++;
+	    }
+
+	  // std::cout << Simulator::Now ().ToDouble (Time::S) << "s -> " << seq << "\n";
+
+	  //
+	  Ptr<NameComponents> nameWithSequence = Create<NameComponents> (m_interestName);
+	  (*nameWithSequence) (seq);
+	  //
+
+	  InterestHeader interestHeader;
+	  interestHeader.SetNonce               (m_rand.GetValue ());
+	  interestHeader.SetName                (nameWithSequence);
+
+	  // NS_LOG_INFO ("Requesting Interest: \n" << interestHeader);
+	  NS_LOG_INFO ("> Interest for " << seq<<", Total: "<<m_seq<<", face: "<<m_face->GetId());
+
+	  Ptr<Packet> packet = Create<Packet> ();
+
+	  //NS_LOG_DEBUG ("= Interest for " << seq<<", Total: "<<m_seq<<", face: "<<m_face->GetId());
+	  packet->AddHeader (interestHeader);
+	  //NS_LOG_DEBUG ("Interest packet size: " << packet->GetSize ());
+
+	  NS_LOG_DEBUG ("Trying to add " << seq << " with " << Simulator::Now () << ". already " << m_seqTimeouts.size () << " items");
+
+	  m_seqTimeouts.insert (SeqTimeout (seq, Simulator::Now ()));
+	  m_seqLifetimes.insert (SeqTimeout (seq, Simulator::Now () + m_interestLifeTime)); // only one insert will work. if entry exists, nothing will happen... nothing should happen
+	  m_transmittedInterests (&interestHeader, this, m_face);
+
+	  m_rtt->SentSeq (SequenceNumber32 (seq), 1);
+
+	  m_protocolHandler (packet);
+
+	 ConsumerZipfMandelbrot::ScheduleNextPacket ();
+}
+
+
+uint32_t
+ConsumerZipfMandelbrot::GetNextSeq(){
+	uint32_t content_index = 1; //[1, m_N]
+	double p_sum = 0;
+
+	double p_random = m_SeqRng->GetValue();
+	while (p_random == 0){
+		p_random = m_SeqRng->GetValue();
+	}
+	//if (p_random == 0)
+	NS_LOG_LOGIC("p_random="<<p_random);
+	for (uint32_t i=1; i<=m_N; i++) {
+		p_sum = m_Pcum[i];   //m_Pcum[i] = m_Pcum[i-1] + p[i], p[0] = 0;   e.g.: p_cum[1] = p[1], p_cum[2] = p[1] + p[2]
+		if (p_random <= p_sum) {
+			content_index = i;
+			break;
+		} //if
+	} //for
+	//content_index = 1;
+	NS_LOG_DEBUG("RandomNumber="<<content_index);
+	return content_index;
+}
+
+void
+ConsumerZipfMandelbrot::ScheduleNextPacket() {
+
+	  if (m_firstTime)
+	    {
+	      m_sendEvent = Simulator::Schedule (Seconds (0.0),
+	                                         &ConsumerZipfMandelbrot::SendPacket, this);
+	      m_firstTime = false;
+	    }
+	  else if (!m_sendEvent.IsRunning ())
+	    m_sendEvent = Simulator::Schedule (
+	                                       (m_random == 0) ?
+	                                         Seconds(1.0 / m_frequency)
+	                                       :
+	                                         Seconds(m_random->GetValue ()),
+	                                       &ConsumerZipfMandelbrot::SendPacket, this);
+}
+
+} /* namespace ndn */
+} /* namespace ns3 */
diff --git a/apps/ndn-consumer-zipf-mandelbrot.h b/apps/ndn-consumer-zipf-mandelbrot.h
new file mode 100644
index 0000000..7d72ef3
--- /dev/null
+++ b/apps/ndn-consumer-zipf-mandelbrot.h
@@ -0,0 +1,82 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2012 Tsinghua University, P.R.China
+ *
+ * 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: Xiaoke Jiang <shock.jiang@gmail.com>
+ */
+
+
+#ifndef NDN_CONSUMER_ZIPF_MANDELBROT_H_
+#define NDN_CONSUMER_ZIPF_MANDELBROT_H_
+
+#include "ndn-consumer.h"
+#include "ns3/ptr.h"
+#include "ns3/log.h"
+#include "ns3/simulator.h"
+#include "ns3/packet.h"
+#include "ns3/callback.h"
+#include "ns3/string.h"
+#include "ns3/uinteger.h"
+#include "ns3/double.h"
+#include "ndn-consumer-cbr.h"
+#include "ns3/random-variable.h"
+
+namespace ns3 {
+namespace ndn {
+
+/**
+ * @ingroup ndn
+ * @brief NDN app requesting contents following Zipf-Mandelbrot Distbituion
+ *
+ * The class implements an app which requests contents following Zipf-Mandelbrot Distribution
+ * Here is the explaination of Zipf-Mandelbrot Distribution: http://en.wikipedia.org/wiki/Zipf%E2%80%93Mandelbrot_law
+
+ */
+//
+class ConsumerZipfMandelbrot: public ns3::ndn::ConsumerCbr {
+public:
+	static TypeId GetTypeId ();
+
+  /**
+   * \brief Default constructor
+   * Sets up randomized Number Generator (RNG)
+   * Note: m_seq of its parent class ConsumerCbr here is used to record the interest number
+   */
+	ConsumerZipfMandelbrot();
+	virtual ~ConsumerZipfMandelbrot();
+
+	virtual void SendPacket();
+	uint32_t GetNextSeq();
+
+protected:
+	virtual void
+	  ScheduleNextPacket ();
+
+private:
+	uint32_t m_N;  //number of the contents
+	double m_q;  //q in (k+q)^s
+	double m_s;  //s in (k+q)^s
+	double * m_Pcum;  //cumulative probability
+
+	UniformVariable * m_SeqRng; //RNG
+
+
+
+};
+
+} /* namespace ndn */
+} /* namespace ns3 */
+#endif /* NDN_CONSUMER_ZIPF_MANDELBROT_H_ */
diff --git a/examples/zipf-mandelbrot.cc b/examples/zipf-mandelbrot.cc
new file mode 100644
index 0000000..b775973
--- /dev/null
+++ b/examples/zipf-mandelbrot.cc
@@ -0,0 +1,130 @@
+/* -*-  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>
+ */
+// ndn-grid.cc
+#include "ns3/core-module.h"
+#include "ns3/network-module.h"
+#include "ns3/point-to-point-module.h"
+#include "ns3/point-to-point-layout-module.h"
+#include "ns3/ndnSIM-module.h"
+
+using namespace ns3;
+
+/**
+ * This scenario simulates a grid topology (using PointToPointGrid module)
+ *
+ * (consumer) -- ( ) ----- ( )
+ *     |          |         |
+ *    ( ) ------ ( ) ----- ( )
+ *     |          |         |
+ *    ( ) ------ ( ) -- (producer)(2,2)
+ *
+ * All links are 1Mbps with propagation 10ms delay.
+ *
+ * FIB is populated using NdnGlobalRoutingHelper.
+ *
+ * Consumer requests data from producer with frequency 100 interests per second
+ * (interests contain constantly increasing sequence number).
+ *
+ * For every received interest, producer replies with a data packet, containing
+ * 1024 bytes of virtual payload.
+ *
+ * To run scenario and see what is happening, use the following command:
+ *
+ *     NS_LOG=ndn.Consumer:ndn.Producer ./waf --run=ndn-grid
+ */
+
+int
+main (int argc, char *argv[])
+{
+	LogComponentEnable("ndn.ConsumerZipfMandelbrot", LOG_LEVEL_DEBUG);
+	LogComponentEnable("ndn.ConsumerCbr", LOG_LEVEL_INFO);
+	LogComponentEnable("ndn.Producer", LOG_LEVEL_INFO);
+	LogComponentEnable("ndn.Consumer", LOG_LEVEL_INFO);
+	//LogComponentEnable("ndn.CbisGlobalRoutingHelper", LOG_LEVEL_INFO);
+  // Setting default parameters for PointToPoint links and channels
+  Config::SetDefault ("ns3::PointToPointNetDevice::DataRate", StringValue ("1Mbps"));
+  Config::SetDefault ("ns3::PointToPointChannel::Delay", StringValue ("1ms"));
+  Config::SetDefault ("ns3::DropTailQueue::MaxPackets", StringValue ("10"));
+
+  // Read optional command-line parameters (e.g., enable visualizer with ./waf --run=<> --visualize
+  CommandLine cmd;
+  cmd.Parse (argc, argv);
+
+  // Creating 3x3 topology
+  PointToPointHelper p2p;
+  PointToPointGridHelper grid (3, 3, p2p);
+  grid.BoundingBox(100,100,200,200);
+
+  // Install CCNx stack on all nodes
+  ndn::StackHelper ccnxHelper;
+  ccnxHelper.SetForwardingStrategy ("ns3::ndn::fw::SmartFlooding");
+  ccnxHelper.SetContentStore ("ns3::ndn::cs::Lru", "MaxSize", "10");
+  ccnxHelper.InstallAll ();
+
+  // Installing global routing interface on all nodes
+  //ndn::CbisGlobalRoutingHelper ccnxGlobalRoutingHelper;
+  ndn::GlobalRoutingHelper ccnxGlobalRoutingHelper;
+  ccnxGlobalRoutingHelper.InstallAll ();
+
+  // Getting containers for the consumer/producer
+  Ptr<Node> producer = grid.GetNode (2, 2);
+  NodeContainer consumerNodes;
+  consumerNodes.Add (grid.GetNode (0,0));
+
+  // Install CCNx applications
+  std::string prefix = "/prefix";
+
+  ndn::AppHelper consumerHelper ("ns3::ndn::ConsumerZipfMandelbrot");
+  //ndn::AppHelper consumerHelper ("ns3::ndn::ConsumerCbr");
+  consumerHelper.SetPrefix (prefix);
+  consumerHelper.SetAttribute ("Frequency", StringValue ("100")); // 100 interests a second
+  //consumerHelper.SetAttribute ("Randomize", StringValue ("uniform")); // 100 interests a second
+  consumerHelper.Install (consumerNodes);
+
+  ndn::AppHelper producerHelper ("ns3::ndn::Producer");
+  producerHelper.SetPrefix (prefix);
+  producerHelper.SetAttribute ("PayloadSize", StringValue("100"));
+  producerHelper.Install (producer);
+  ccnxGlobalRoutingHelper.AddOrigins (prefix, producer);
+
+  //Ptr<Node> producer2 = grid.GetNode(1,2);
+  //producerHelper.Install (producer2);
+  // Add /prefix origins to ndn::GlobalRouter
+  //ccnxGlobalRoutingHelper.AddOrigins (prefix, producer2);
+
+
+
+
+  // Add /prefix origins to ndn::GlobalRouter
+  //ccnxGlobalRoutingHelper.AddOrigins (prefix, producer);
+
+
+  // Calculate and install FIBs
+  ccnxGlobalRoutingHelper.CalculateRoutes ();
+
+  //ccnxGlobalRoutingHelper.CalculateRoutes2 ();
+
+  Simulator::Stop (Seconds (10.0));
+
+  Simulator::Run ();
+  Simulator::Destroy ();
+
+  return 0;
+}