Index: /main/waeup.sirp/trunk/src/waeup/sirp/accesscodes/accesscodes.py
===================================================================
--- /main/waeup.sirp/trunk/src/waeup/sirp/accesscodes/accesscodes.py	(revision 5148)
+++ /main/waeup.sirp/trunk/src/waeup/sirp/accesscodes/accesscodes.py	(revision 5149)
@@ -19,9 +19,10 @@
 
     def __init__(self, batch_serial, random_num, invalidation_date=None,
-                 student_id=None):
+                 student_id=None, disabled=False):
         self.batch_serial = batch_serial
         self.random_num = random_num
         self._invalidation_date = invalidation_date
         self.student_id = student_id
+        self._disabled = disabled
 
     @property
@@ -57,5 +58,11 @@
         # This attribute should be set by the surrounding batch only.
         return self._invalidation_date
-    
+
+    @property
+    def disabled(self):
+        # We define this as a property to make it unwritable.
+        # This attribute should be set by the surrounding batch only.
+        return self._disabled
+
 class AccessCodeBatch(grok.Model):
     """A batch of access codes.
@@ -73,6 +80,8 @@
         self.num = num
         self.invalidated_num = 0
+        self.disabled_num = 0
         self._entries = list()
         self._acids = OIBTree()
+        self._studids = OIBTree()
         self._createEntries()
 
@@ -121,4 +130,9 @@
         return self._entries[self._acids[ac_id]]
 
+    def getAccessCodeForStudentId(self, stud_id):
+        """Get any AccessCode invalidated for ``stud_id`` or ``KeyError``.
+        """
+        return self._entries[self._studids[stud_id]]
+
     def addAccessCode(self, num, pin):
         """Add an access-code.
@@ -137,5 +151,41 @@
         ac._invalidation_date = datetime.now()
         ac.student_id = student_id
+        if student_id is not None:
+            self._studids.update({student_id: num})
         self.invalidated_num += 1
+
+    def disable(self, ac_id, user_id):
+        """Disable the AC with ID ``ac_id``.
+
+        ``user_id`` is the user ID of the user triggering the
+        process. Already disabled ACs are left untouched.
+        """
+        num = self._acids[ac_id]
+        ac = self.getAccessCode(ac_id)
+        if ac._disabled == True:
+            return
+        ac._disabled = True
+        old_student_id = ac.student_id
+        if old_student_id is not None:
+            del self._studids[old_student_id]
+            self._studids.update({user_id: num})
+        ac.student_id = user_id
+        ac._invalidation_date = datetime.now()
+        self.disabled_num += 1
+        
+    def enable(self, ac_id):
+        """(Re-)enable the AC with ID ``ac_id``.
+
+        This leaves the given AC in state ``unused``. Already enabled
+        ACs are left untouched.
+        """
+        num = self._acids[ac_id]
+        ac = self.getAccessCode(ac_id)
+        if ac._disabled == False:
+            return
+        ac.student_id = None
+        ac._disabled = False
+        ac._invalidation_date = None
+        self.disabled_num -= 1
 
     def createCSVLogFile(self):
@@ -195,4 +245,24 @@
         return os.path.basename(csv_path)
 
+    def search(self, searchterm, searchtype):
+        if searchtype == 'serial':
+            if len(self._entries) < searchterm + 1:
+                return []
+            return [self._entries[searchterm]]
+        if searchtype == 'pin':
+            try:
+                entry = self.getAccessCode(searchterm)
+                return [entry]
+            except KeyError:
+                return []
+        if searchtype != 'stud_id':
+            return []
+        try:
+            entry = self.getAccessCodeForStudentId(searchterm)
+            return [entry]
+        except KeyError:
+            pass
+        return []
+
 class AccessCodeBatchContainer(grok.Container):
     grok.implements(IAccessCodeBatchContainer)
@@ -269,5 +339,19 @@
         batch.createCSVLogFile()
         return
-    
+
+    def search(self, searchterm, searchtype, ):
+        """Look for access-codes that comply with the given params.
+        """
+        results = []
+        if searchtype == 'serial':
+            try:
+                searchterm = int(searchterm)
+            except:
+                return []
+        for batchname in self.keys():
+            part_result = self[batchname].search(searchterm, searchtype)
+            results.extend(part_result)
+        return results
+
 class AccessCodePlugin(grok.GlobalUtility):
     grok.name('accesscodes')
