GetPrefix was added to Producer app
diff --git a/apps/ccnx-producer.cc b/apps/ccnx-producer.cc
index 7e0757a..d320a2d 100644
--- a/apps/ccnx-producer.cc
+++ b/apps/ccnx-producer.cc
@@ -34,44 +34,18 @@
     static TypeId tid = TypeId ("ns3::CcnxProducer")
     .SetParent<Application> ()
     .AddConstructor<CcnxProducer> ()
-    // Alex: this is incorrect. SetNode call is not called if face is created using this accessor
-    // .AddAttribute ("Face","Local face to be used",
-    //                 PointerValue (CreateObject<CcnxLocalFace> ()),
-    //                 MakePointerAccessor (&CcnxProducer::m_face),
-    //                 MakePointerChecker<CcnxLocalFace> ())
-    .AddAttribute ("Ccnx","Ccnx is needed to access ContentStore",
-                   PointerValue (NULL),
-                   MakePointerAccessor (&CcnxProducer::m_ccnx),
-                   MakePointerChecker<Ccnx> ())
-
-        /*.AddAttribute ("InterestName","CcnxName of the Interest (use CcnxNameComponents)",
-                       PointerValue (CreateObject<CcnxNameComponents> ()),
-                       MakePointerAccessor (&CcnxConsumer::m_interestName),
-                       MakePointerChecker<CcnxNameComponents> ())
-        .AddAttribute ("LifeTime", "LifeTime fo interest packet",
-                       TimeValue (Seconds (4.0)),
-                       MakeTimeAccessor (&CcnxConsumer::m_interestLifeTime),
-                       MakeTimeChecker ())
-        .AddAttribute ("MinSuffixComponents", "MinSuffixComponents",
-                       IntegerValue(-1),
-                       MakeIntegerAccessor(&CcnxConsumer::m_minSuffixComponents),
-                       MakeIntegerChecker<int32_t>())
-        .AddAttribute ("MaxSuffixComponents", "MaxSuffixComponents",
-                       IntegerValue(-1),
-                       MakeIntegerAccessor(&CcnxConsumer::m_maxSuffixComponents),
-                       MakeIntegerChecker<int32_t>())
-        .AddAttribute ("ChildSelector", "ChildSelector",
-                       BooleanValue(false),
-                       MakeBooleanAccessor(&CcnxConsumer::m_childSelector),
-                       MakeBooleanChecker())
-        .AddAttribute ("Exclude", "only simple name matching is supported (use CcnxNameComponents)",
-                       PointerValue (CreateObject<CcnxNameComponents> ()),
-                       MakePointerAccessor (&CcnxConsumer::m_exclude),
-                       MakePointerChecker<CcnxNameComponents> ())*/
-    .AddAttribute ("Capacity", "Capacity of the ContentStore",
+    /*.AddAttribute ("Capacity", "Capacity of the ContentStore",
                     UintegerValue(100),
                     MakeUintegerAccessor(&CcnxProducer::m_storeCapacity),
-                    MakeUintegerChecker<uint32_t>())
+                    MakeUintegerChecker<uint32_t>())*/
+    .AddAttribute ("Prefix","Prefix, for which producer has the data",
+                   CcnxNameComponentsValue (),
+                   MakeCcnxNameComponentsAccessor (&CcnxProducer::m_prefix),
+                   MakeCcnxNameComponentsChecker ())
+    .AddAttribute ("PayloadSize", "Virtual payload size for Content packets",
+                   UintegerValue(100),
+                   MakeUintegerAccessor(&CcnxProducer::m_virtualPayloadSize),
+                   MakeUintegerChecker<uint32_t>())
     .AddTraceSource ("InterestTrace", "Interests that were received",
                     MakeTraceSourceAccessor (&CcnxProducer::m_interestsTrace))
     .AddTraceSource ("ContentObjectTrace", "ContentObjects that were sent",
@@ -104,15 +78,58 @@
 CcnxProducer::StartApplication () // Called at time specified by Start
 {
     NS_LOG_FUNCTION_NOARGS ();
-//    ScheduleNextTx();
+    
+    NS_ASSERT_MSG (m_face == 0, "Face should not exist");
+    m_face = Create<CcnxLocalFace> ();
+    
+    // step 1. Set up forwarding from face to application
+    m_face->SetNode (GetNode ());
+    m_face->SetInterestHandler (MakeCallback (&CcnxProducer::OnInterest, this));
+    
+    // step 2. Set up forwarding to and from ccnx
+    NS_ASSERT_MSG (GetNode ()->GetObject<Ccnx> () !=0,
+                   "Ccnx stack should be installed on the node " << GetNode ());
+    GetNode ()->GetObject<Ccnx> ()->AddFace (m_face);
+    //Add (const CcnxNameComponents &prefix, Ptr<CcnxFace> face, int32_t metric);
+    GetNode ()->GetObject<Ccnx> ()->GetObject<CcnxFib> ()->Add(m_prefix, m_face, 0);
+    // step 3. Enable face
+    m_face->SetUp ();
 }
     
 void 
 CcnxProducer::StopApplication () // Called at time specified by Stop
 {
     NS_LOG_FUNCTION_NOARGS ();
+}
+    
+void
+CcnxProducer::OnInterest(const Ptr<const CcnxInterestHeader> &interest)
+{
+    NS_LOG_FUNCTION (this);
+    
+    
+    
+    //Ptr<Packet> data = Lookup (interest);
+    
+    
+    
+    Ptr<Packet> incomingPacket = Create<Packet>(m_virtualPayloadSize);
+    incomingPacket->AddHeader (*interest);
+    m_interestsTrace(m_face,incomingPacket);
+    
+   
+
+    static CcnxContentObjectTail tail; ///< \internal for optimization purposes
+    Ptr<Packet> outgoingPacket = Create<Packet> (m_virtualPayloadSize);
+    Ptr<CcnxContentObjectHeader> header = Create<CcnxContentObjectHeader>();
+    header->SetName(Create<CcnxNameComponents>(interest->GetName()));
+    outgoingPacket->AddHeader(*header);
+    outgoingPacket->AddTrailer (tail);
+    
+    m_contentObjectsTrace(m_face,outgoingPacket);
         
-    CancelEvents ();
+    m_face->ReceiveFromApplication(outgoingPacket);
+   
 }
     
 void 
@@ -122,48 +139,26 @@
         
     // Simulator::Cancel (m_sendEvent);
 }
-    
-/*void 
-CcnxProducer::ScheduleNextTx ()
+  
+CcnxNameComponents
+CcnxProducer::GetPrefix() const
 {
-        NS_LOG_FUNCTION_NOARGS ();
-        
-        Time nextTime = Seconds(m_offTime);
-        m_sendEvent = Simulator::Schedule (nextTime, &CcnxConsumer::SendPacket, this);
-    }
-    */
+  return m_prefix;
+}
     
-/*void
-CcnxConsumer::SendPacket ()
-    {
-        NS_LOG_FUNCTION_NOARGS ();
-        NS_LOG_INFO ("Sending Interest at " << Simulator::Now ());
-        
-        uint32_t randomNonce = UniformVariable().GetInteger(1, std::numeric_limits<uint32_t>::max ());
-        CcnxInterestHeader interestHeader;
-        interestHeader.SetNonce(randomNonce);
-        interestHeader.SetName(m_interestName);
-        interestHeader.SetInterestLifetime(m_interestLifeTime);
-        interestHeader.SetChildSelector(m_childSelector);
-        interestHeader.SetExclude(m_exclude);
-        interestHeader.SetMaxSuffixComponents(m_maxSuffixComponents);
-        interestHeader.SetMinSuffixComponents(m_minSuffixComponents);
-        
-        Ptr<Packet> packet = Create<Packet> ();
-        packet->AddHeader (interestHeader);
-        
-        m_face->Receive(packet);
-        
-        ScheduleNextTx();
-    }*/
-    
-uint32_t
+/*uint32_t
 CcnxProducer::GetStoreCapacity()
 {
-    return m_storeCapacity;
+  return m_storeCapacity;
 }
     
 void
+CcnxProducer::SetStoreCapacity(uint32_t capacity)
+{
+  m_storeCapacity = capacity;
+}
+  */  
+/*void
 CcnxProducer::HandlePacket(const Ptr<CcnxFace> &face, const Ptr<const Packet> &packet)
 {
     uint8_t type[2];
@@ -182,11 +177,41 @@
     {
         m_contentObjectsTrace(face,packet);
     }
-}
+}*/
+    
+/*Ptr<Packet>
+CcnxProducer::Lookup (Ptr<const CcnxInterestHeader> interest)
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  DataStoreContainer::type::iterator it = m_availableData.get<i_prefix> ().find (interest->GetName ());
+        
+  if (it != m_availableData.end ())
+  {
+    // return fully formed CCNx packet
+    return it->GetFullyFormedCcnxPacket ();
+  }
+    
+  return 0;
+}   
     
 void 
-CcnxProducer::AddContentStoreEntry (Ptr<CcnxContentObjectHeader> header, Ptr<const Packet> packet)
+CcnxProducer::Add (Ptr<CcnxContentObjectHeader> header, Ptr<const Packet> packet)
 {
-    // m_ccnx->m_contentStore->Add (header, packet);
-}
+  NS_LOG_FUNCTION_NOARGS ();
+  DataStoreContainer::type::iterator it = m_availableData.get<i_prefix> ().find (header->GetName ());
+        
+  if (it == m_availableData.end ())
+  { // add entry to the top
+    m_availableData.get<i_mru> ().push_front (DataStoreEntry (header, packet));
+            
+    if (m_availableData.size () > m_storeCapacity)
+      m_availableData.get<i_mru> ().pop_back ();
+  }
+  else
+  {
+    // promote entry to the top
+    //m_contentStore.get<i_mru> ().relocate (m_contentStore.get<i_mru> ().begin (),
+      //                                             m_contentStore.project<i_mru> (it));
+  }
+}*/
 }
diff --git a/apps/ccnx-producer.h b/apps/ccnx-producer.h
index 55049dd..840400b 100644
--- a/apps/ccnx-producer.h
+++ b/apps/ccnx-producer.h
@@ -45,10 +45,73 @@
 #include "ns3/header.h"
 #include "ns3/ccnx.h"
 #include "ns3/ccnx-content-object-header.h"
+#include "ns3/ccnx-name-components.h"
+#include "ns3/ccnx-fib.h"
+
+#include <boost/multi_index_container.hpp>
+#include <boost/multi_index/tag.hpp>
+#include <boost/multi_index/ordered_index.hpp>
+#include <boost/multi_index/sequenced_index.hpp>
+#include <boost/multi_index/hashed_index.hpp>
+#include <boost/multi_index/mem_fun.hpp>
 
 namespace ns3 
 {
     
+    class DataStoreEntry
+    {
+    public:
+        /**
+         * \brief Construct data store entry
+         *
+         * \param header Parsed CcnxContentObject header
+         * \param packet Original CCNx packet
+         *
+         * The constructor will make a copy of the supplied packet and calls
+         * RemoveHeader and RemoveTail on the copy.
+         */
+        DataStoreEntry (Ptr<CcnxContentObjectHeader> header, Ptr<const Packet> packet);
+        
+        /**
+         * \brief Get prefix of the stored entry
+         * \returns prefix of the stored entry
+         */
+        inline const CcnxNameComponents&
+        GetName () const;
+        
+        /**
+         * \brief Get CcnxContentObjectHeader of the stored entry
+         * \returns CcnxContentObjectHeader of the stored entry
+         */
+        inline Ptr<const CcnxContentObjectHeader>
+        GetHeader () const;
+        
+        /**
+         * \brief Get content of the stored entry
+         * \returns content of the stored entry
+         */
+        inline Ptr<const Packet>
+        GetPacket () const;
+        
+        /**
+         * \brief Convenience method to create a fully formed CCNx packet from stored header and content
+         * \returns A read-write copy of the packet with CcnxContentObjectHeader and CcxnContentObjectTail
+         */
+        Ptr<Packet>
+        GetFullyFormedCcnxPacket () const;
+        
+        // Copy constructor is required by the container. Though, we're
+        // storing only two pointers, so shouldn't be a problem
+        // private:
+        //   CcnxContentStoreEntry (const CcnxContentStoreEntry &); ///< disabled copy constructor
+        //   CcnxContentStoreEntry& operator= (const CcnxContentStoreEntry&); ///< disabled copy operator
+        
+    private:
+        //Ptr<CcnxContentObjectHeader> m_header; ///< \brief non-modifiable CcnxContentObjectHeader
+        //Ptr<Packet> m_packet; ///< \brief non-modifiable content of the ContentObject packet
+    };
+
+    
 class CcnxProducer: public Application
 {
 public: 
@@ -58,9 +121,26 @@
         
     virtual ~CcnxProducer ();
         
-    void HandlePacket (const Ptr<CcnxFace> &face, const Ptr<const Packet> &packet);
-    uint32_t GetStoreCapacity();
-    void AddContentStoreEntry (Ptr<CcnxContentObjectHeader> header, Ptr<const Packet> packet);
+    //void HandlePacket (const Ptr<CcnxFace> &face, const Ptr<const Packet> &packet);
+    //uint32_t GetStoreCapacity();
+    //void SetStoreCapacity(uint32_t capacity);
+    //void AddContentStoreEntry (Ptr<CcnxContentObjectHeader> header, Ptr<const Packet> packet);
+    
+    void OnInterest(const Ptr<const CcnxInterestHeader> &interest);
+    
+    CcnxNameComponents GetPrefix() const;  
+    /**
+     * \brief Add a new content to the data store.
+     *
+     * \param header Fully parsed CcnxContentObjectHeader
+     * \param packet Fully formed CCNx packet to add to content store
+     * (will be copied and stripped down of headers)
+     *
+     * If entry with the same prefix exists, the old entry will be
+     * promoted to the top of the MRU hash
+     */
+    //void
+    //Add (Ptr<CcnxContentObjectHeader> header, Ptr<const Packet> packet);
     
 protected:
     virtual void DoDispose (void);
@@ -69,48 +149,59 @@
     virtual void StartApplication (void);    // Called at time specified by Start
     virtual void StopApplication (void);     // Called at time specified by Stop
         
+    /**
+     * \brief Find corresponding CS entry for the given interest
+     *
+     * \param interest Interest for which matching content store entry
+     * will be searched
+     *
+     * If an entry is found, it is promoted to the top of most recent
+     * used entries index, \see m_contentStore
+     */
+    //Ptr<Packet>
+    //Lookup (Ptr<const CcnxInterestHeader> interest);
+
+    
     Ptr<Ccnx> m_ccnx;
     Time m_offTime;
-    //Ptr<CcnxNameComponents> m_interestName;
-    //Time m_interestLifeTime;
-    //int32_t m_minSuffixComponents;
-    //int32_t m_maxSuffixComponents;
-    //bool m_childSelector;
-    //Ptr<CcnxNameComponents> m_exclude;
-    //uint32_t m_initialNonce;
-        
+           
     //EventId         m_sendEvent;    // Eventid of pending "send packet" event
     TypeId          m_tid;
     Ptr<CcnxLocalFace> m_face;
     
-    uint32_t m_storeCapacity;
-        
+    /*struct DataStoreContainer
+    {
+        typedef
+        boost::multi_index::multi_index_container<
+          DataStoreEntry,
+          boost::multi_index::indexed_by<
+            boost::multi_index::hashed_unique<
+              boost::multi_index::tag<__ccnx_private::i_prefix>,
+              boost::multi_index::const_mem_fun<DataStoreEntry,
+                                                const CcnxNameComponents&,
+                                                &DataStoreEntry::GetName>,
+              CcnxPrefixHash>,
+          boost::multi_index::sequenced<boost::multi_index::tag<__ccnx_private::i_mru> >
+#ifdef _DEBUG
+          ,
+          boost::multi_index::ordered_unique<
+          boost::multi_index::tag<__ccnx_private::i_ordered>,
+          boost::multi_index::const_mem_fun<DataStoreEntry,
+          const CcnxNameComponents&,
+          &CcnxContentStoreEntry::GetName>
+          >
+#endif
+        >
+      > type;
+    };*/
+
     //helpers
     void CancelEvents ();
-        
-    void Construct (Ptr<Node> n,
-                    std::string tid,
-                    const Time& offtime,
-                    Ptr<CcnxLocalFace> face,
-                    Ptr<CcnxNameComponents> nameComponents,
-                    const Time& lifetime,
-                    const int32_t& minSuffixComponents,
-                    const int32_t& maxSuffixComponents,
-                    const bool childSelector,
-                    Ptr<CcnxNameComponents> exclude,
-                    const uint32_t& initialNonce
-                    );
-        
-    // Event handlers
-    void StartSending ();
-    void StopSending ();
-    void SendPacket ();
-    //typedef Callback<void,const Ptr<CcnxFace>&,const Ptr<const Packet>& > ProtocolHandler;
-        
-private:
-    void ScheduleNextTx ();
-    //typedef Callback<void,const Ptr<CcnxFace>&,const Ptr<const Packet>& > ProtocolHandler;
-        
+    
+    //DataStoreContainer::type m_availableData;
+    //uint32_t m_storeCapacity;
+    uint32_t m_virtualPayloadSize;
+    CcnxNameComponents m_prefix;
     TracedCallback<const Ptr<CcnxFace>&,const Ptr<const Packet>& > m_interestsTrace;
     TracedCallback<const Ptr<CcnxFace>&,const Ptr<const Packet>& > m_contentObjectsTrace;
 };