PyNDN: A lot of fixes and API unification

There is actually a very strange/interesting bug with callback
Python/C++/Python callback mechanism.  Needed to add a nasty addition
(potential memory leak and performance degradation) to eliminate
segfaults.
diff --git a/PyNDN/Data.py b/PyNDN/Data.py
index 5165d2c..6d36dc9 100644
--- a/PyNDN/Data.py
+++ b/PyNDN/Data.py
@@ -35,6 +35,11 @@
                 self._data = data._data
             elif isinstance (data, ns.ndnSIM.ndn.Data):
                 self._data = data
+                self.signedInfo = SignedInfo ()
+                # timestamp
+                self.signedInfo.freshnessSeconds = self._data.GetFreshness ().ToDouble (ns.core.Time.S)
+                if self._data.GetKeyLocator ():
+                    self.signedInfo.keyLocator = Name (name = self._data.GetKeyLocator ())
             else:
                 raise TypeError ("Invalid type supplied for 'data' parameter [%s]" % type (data))
         else:
@@ -46,11 +51,7 @@
 
     @staticmethod
     def fromWire (wire):
-        data = Data (data = ns.ndnSIM.ndn.Wire.ToData (wire))
-        # timestamp
-        data.signedInfo.freshnessSeconds = data._data.GetFreshness ()
-        if data._data.GetKeyLocator ():
-            data.keyLocator = Name (_name = data._data.GetKeyLocator ())
+        return Data (data = ns.ndnSIM.ndn.Wire.ToDataStr (bytes (wire)))
 
     def sign (self, key):
         """There is no actual signing in ndnSIM for now, but we will assign signature bits based on key"""
@@ -60,7 +61,7 @@
         if self._data.GetSignature () == 0:
             raise DataError ("Data packet has not been signed, cannot create wire format")
 
-        return ns.ndnSIM.ndn.Wire.FromData (self._data)
+        return ns.ndnSIM.ndn.Wire.FromDataStr (self._data)
 
     def verify_signature (self, key):
         """There is no actual signing in ndnSIM for now, but we will check if signature matches the key"""
@@ -79,7 +80,7 @@
         elif name == "interestLifetime":
             return self._data.GetInterestLifetime ().ToDouble (ns.core.Time.S)
         elif name == "content":
-            pkt = self._data.GetContent ()
+            pkt = self._data.GetPayload ()
             return ns.ndnSIM.ndn.PacketToBuffer (pkt)
         else:
             return self._data.__getattribute__ (name)
@@ -125,4 +126,4 @@
             raise NameError ("Unknown attribute [%s]" % name)
 
     def __repr__(self):
-        return "ndn.Data(%s)" % str (self._data)
+        return "ndn.Data(%s; %s)" % str (self._data, self.signedInfo)
diff --git a/PyNDN/Face.py b/PyNDN/Face.py
index 3f76f5d..3a905fa 100644
--- a/PyNDN/Face.py
+++ b/PyNDN/Face.py
@@ -24,8 +24,11 @@
 from Interest import Interest
 from Name import Name
 
+import time
 import functools
 
+deleteList = []
+
 class Face (ns.ndnSIM.ndn.ApiFace):
     def __init__(self):
         self.nodeId = ns.core.Simulator.GetContext ()
@@ -41,6 +44,7 @@
     def defer_verification (self, deferVerification = True):
         pass
 
+
     def expressInterest (self, name, onData, onTimeout, template = None):
         """
         onData:    void <interest, name>
@@ -50,34 +54,16 @@
         interest = Interest (interest = template)
         interest.name = name
 
-        class OnDataConvert:
-            def __init__ (self, onData):
-                self.onData = onData
-            def __call__ (self, interest, data):
-                if self.onData:
-                    return self.onData (Interest (interest=interest), Data (data = data))
+        converter = ExpressInterestConverter (onData, onTimeout)
+        deleteList.append (converter)
 
-        class OnTimeoutConvert:
-            def __init__ (self, onTimeout):
-                self.onTimeout = onTimeout
-            def __call__ (self, interest):
-                if self.onTimeout:
-                    self.onTimeout (Interest (interest=interest))
-
-        self.ExpressInterest (interest._interest, OnDataConvert (onData), OnTimeoutConvert (onTimeout))
+        self.ExpressInterest (interest._interest, converter.handleOnData, converter.handleOnTimeout)
 
     def setInterestFilter (self, name, onInterest, flags = None):
         """
         onInterest: void <name, interest>
         """
 
-        class OnInterestConvert:
-            def __init__ (self, onInterest):
-                self.onInterest = onInterest
-            def __call__ (self, name, interest):
-                if self.onInterest:
-                    self.onInterest (Name (name = name), Interest (interest = interest))
-
         if isinstance (name, Name):
             name = name._name
         elif isinstance (name, ns.ndnSIM.ndn.Name):
@@ -85,7 +71,10 @@
         else:
             raise TypeError ("Wrong type for 'name' parameter [%s]" % type (name))
 
-        self.SetInterestFilter (name, OnInterestConvert (onInterest))
+        converter = OnInterestConvert (onInterest)
+        deleteList.append (converter)
+
+        self.SetInterestFilter (name, converter)
 
     def clearInterestFilter (self, name):
         if isinstance (name, Name):
@@ -95,10 +84,42 @@
         else:
             raise TypeError ("Wrong type for 'name' parameter [%s]" % type (name))
 
+        # @bug: memory leak, deleteList need to remove previosly set callback... but how?
         self.ClearInterestFilter (name)
 
     def get (self, name, template = None, timeoutms = 3000):
         raise NotImplementedError ("NS-3 simulation cannot have syncrhonous operations")
 
     def put (self, data):
-        self.Put (data)
+        if isinstance (data, Data):
+            self.Put (data._data)
+        elif isinstance (data, ns.ndnSIM.ndn.Data):
+            self.Put (data)
+        else:
+            raise TypeError ("Unsupported type to publish data [%s]" % type (data))
+
+def removeFromDeleteList (object):
+    deleteList.remove (object)
+
+class ExpressInterestConverter:
+    def __init__ (self, onData, onTimeout):
+        self.onData = onData
+        self.onTimeout = onTimeout
+
+    def handleOnData (self, interest, data):
+        ns.core.Simulator.ScheduleNow (removeFromDeleteList, self)
+        if self.onData:
+            return self.onData (Interest (interest=interest), Data (data = data))
+
+    def handleOnTimeout (self, interest):
+        ns.core.Simulator.ScheduleNow (removeFromDeleteList, self)
+        if self.onTimeout:
+            self.onTimeout (Interest (interest=interest))
+
+class OnInterestConvert (object):
+    def __init__ (self, onInterest):
+        self.onInterest = onInterest
+    def __call__ (self, name, interest):
+        ns.core.Simulator.ScheduleNow (removeFromDeleteList, self)
+        if self.onInterest:
+            self.onInterest (Name (name = name), Interest (interest = interest))
diff --git a/PyNDN/Interest.py b/PyNDN/Interest.py
index b4b5b9a..d831bb5 100644
--- a/PyNDN/Interest.py
+++ b/PyNDN/Interest.py
@@ -43,10 +43,10 @@
 
     @staticmethod
     def fromWire (wire):
-        return Interest (interest = ns.ndnSIM.ndn.Wire.ToInterest (wire))
+        return Interest (interest = ns.ndnSIM.ndn.Wire.ToInterestStr (wire))
 
     def toWire (self):
-        return ns.ndnSIM.ndn.Wire.FromInterest (self._interest)
+        return ns.ndnSIM.ndn.Wire.FromInterestStr (self._interest)
 
     def __getattr__ (self, name):
         if name == "_interest":
diff --git a/PyNDN/Name.py b/PyNDN/Name.py
index 7729a25..60ac68d 100644
--- a/PyNDN/Name.py
+++ b/PyNDN/Name.py
@@ -73,7 +73,10 @@
             raise ValueError("Unknown __getitem__ type: %s" % type (key))
 
     def __repr__ (self):
-        return "ndnSIM.Name('" + self._name.toUri () + "')"
+        return "ndn.Name('" + self._name.toUri () + "')"
 
     def __str__ (self):
         return self._name.toUri ()
+
+    def isPrefixOf (self, other):
+        return self[:] == other[:len(self)]
diff --git a/PyNDN/SignedInfo.py b/PyNDN/SignedInfo.py
index 79c2f4f..cadf1e7 100644
--- a/PyNDN/SignedInfo.py
+++ b/PyNDN/SignedInfo.py
@@ -44,7 +44,7 @@
             args += ["keyLocator=%r" % self.keyLocator]
         if self.freshnessSeconds is not None:
             args += ["freshness=%r" % self.freshnessSeconds]
-        if self.timeStamp is not None:
+        if self.timestamp is not None:
             args += ["timestamp=%r" % self.timestamp]
         if self.type != CONTENT_DATA:
             args += ["type=%r" % self.type]