Index: main/waeup.sirp/trunk/src/waeup/sirp/hostels/browser.py
===================================================================
--- main/waeup.sirp/trunk/src/waeup/sirp/hostels/browser.py	(revision 6966)
+++ main/waeup.sirp/trunk/src/waeup/sirp/hostels/browser.py	(revision 6970)
@@ -142,5 +142,5 @@
     grok.require('waeup.manageHostels')
     grok.name('addhostel')
-    grok.template('hosteladdpage')
+    #grok.template('hosteladdpage')
     form_fields = grok.AutoFields(IHostel)
     title = 'Hostels'
@@ -186,5 +186,5 @@
     grok.require('waeup.manageHostels')
     text = 'Manage'
-    target = 'edit'
+    target = 'manage'
 
 class HostelManageFormPage(WAeUPEditFormPage):
@@ -192,10 +192,12 @@
     """
     grok.context(IHostel)
-    grok.name('edit')
+    grok.name('manage')
     grok.require('waeup.manageHostels')
     form_fields = grok.AutoFields(IHostel).omit('hostel_id')
-    #grok.template('hostelmanagepage')
+    grok.template('hostelmanagepage')
     label = 'Manage hostel'
     pnav = 5
+    taboneactions = ['Save']
+    tabtwoactions = ['Update beds']
 
     @property
@@ -205,4 +207,6 @@
     def update(self):
         datepicker.need() # Enable jQuery datepicker in date fields.
+        tabs.need()
+        datatable.need()
         super(HostelManageFormPage, self).update()
         return
@@ -212,2 +216,9 @@
         msave(self, **data)
         return
+
+    @grok.action('Update beds')
+    def updateBeds(self, **data):
+        added, modified = self.context.updateBeds()
+        self.flash('%d added, %d modified' % (added, modified))
+        self.redirect(self.url(self.context, '@@manage')+'#tab-2')
+        return
Index: main/waeup.sirp/trunk/src/waeup/sirp/hostels/browser_templates/hostelmanagepage.pt
===================================================================
--- main/waeup.sirp/trunk/src/waeup/sirp/hostels/browser_templates/hostelmanagepage.pt	(revision 6970)
+++ main/waeup.sirp/trunk/src/waeup/sirp/hostels/browser_templates/hostelmanagepage.pt	(revision 6970)
@@ -0,0 +1,104 @@
+<h2 i18n:translate=""
+  tal:condition="view/label"
+  tal:content="view/label">Label</h2>
+
+  <div class="form-status"
+      tal:define="status view/status"
+      tal:condition="status">
+      Form Status:
+      <span i18n:translate="" tal:content="view/status">
+        Form status summary
+      </span>
+      <ul tal:condition="view/errors">
+        <li tal:repeat="error view/error_views">
+           <span tal:replace="structure error">Error Type</span>
+        </li>
+      </ul>
+  </div>
+
+  <form action="." tal:attributes="action request/URL" method="POST"
+        class="edit-form" enctype="multipart/form-data">
+
+  <div id="tabs">
+    <ul>
+      <li><a href="#tab-1"><span>Hostel Data</span></a></li>
+      <li><a href="#tab-2"><span>Beds</span></a></li>
+    </ul>
+
+    <div id="tab-1">
+      <table class="zebra">
+      <tbody>
+      <tal:block repeat="widget view/widgets">
+        <tr>
+          <td class="label">
+            <label tal:attributes="for widget/name">
+              <span class="required" tal:condition="widget/required">*</span>
+              <span i18n:translate="" tal:content="widget/label">label</span>:
+            </label>
+          </td>
+          <td class="field">
+            <span class="widget" tal:content="structure widget">
+              <input type="text" />
+            </span>
+            <tal:error tal:condition="widget/error">
+              <span tal:replace="structure widget/error">error</span>
+            </tal:error>
+            <tal:hint tal:condition="widget/hint">
+              <span class="hint" tal:content="structure widget/hint">hint</span>
+            </tal:hint>
+          </td>
+        </tr>
+      </tal:block>
+      </tbody>
+      </table>
+      <div class="actionButtons" tal:condition="view/availableActions">
+        <span tal:repeat="action view/actions"
+              tal:omit-tag="">
+          <input tal:condition="python:action.label in view.taboneactions"
+                 tal:replace="structure action/render"/>
+        </span>
+      </div>
+    </div>
+
+    <div id="tab-2">
+      <h3>Beds</h3>
+      <table class="display dataTableManage">
+      <thead>
+        <tr>
+          <th>&nbsp;</th>
+          <th>Bed Id</th>
+          <th>Bed Type</th>
+          <th>Sort Id</th>
+          <th>Owner</th>
+        </tr>
+      </thead>
+      <tbody>
+        <tr tal:repeat="value context/values">
+           <td>
+            <input type="checkbox" name="val_id"
+      		  tal:attributes="value value/__name__" />
+          </td>
+          <td> <a tal:attributes="href value/__name__">
+          <span tal:content="value/bed_id">Bed Id</span>
+          </a></td>
+          <td tal:content="value/bed_type">Bed Type</td>
+          <td tal:content="value/sort_id">Sort Id</td>
+          <td tal:content="value/owner">Owner</td>
+        </tr>
+      </tbody>
+      </table>
+
+      <div class="actionButtons" tal:condition="view/availableActions">
+        <span tal:repeat="action view/actions"
+              tal:omit-tag="">
+          <input tal:condition="python:action.label in view.tabtwoactions"
+                 tal:replace="structure action/render"/>
+        </span>
+      </div>
+
+    </div>
+  </div>
+</form>  
+
+
+
Index: main/waeup.sirp/trunk/src/waeup/sirp/hostels/hostel.py
===================================================================
--- main/waeup.sirp/trunk/src/waeup/sirp/hostels/hostel.py	(revision 6966)
+++ main/waeup.sirp/trunk/src/waeup/sirp/hostels/hostel.py	(revision 6970)
@@ -23,4 +23,6 @@
 from waeup.sirp.hostels.interfaces import IHostel, IBed
 
+NOT_OCCUPIED = u'not occupied'
+
 class Hostel(grok.Container):
     """This is a hostel.
@@ -34,11 +36,77 @@
 
     def addBed(self, bed):
-        """Add a hostel.
+        """Add a bed.
         """
         if not IBed.providedBy(bed):
             raise TypeError(
                 'Hostels contain only IBed instances')
-        self[hostel.bed_id] = bed
+        self[bed.bed_id] = bed
         return
+
+    # not yet tested nor used
+    def updateBeds(self):
+        """Fill hostel with beds or update beds.
+        """
+        added_counter = 0
+        modified_counter = 0
+        blocks_for_female = getattr(self,'blocks_for_female',[])
+        blocks_for_male = getattr(self,'blocks_for_male',[])
+        beds_for_fresh = getattr(self,'beds_for_fresh',[])
+        beds_for_pre = getattr(self,'beds_for_pre',[])
+        beds_for_returning = getattr(self,'beds_for_returning',[])
+        beds_for_final = getattr(self,'beds_for_final',[])
+        beds_reserved = [] #temporarily empty
+        all_blocks = blocks_for_female + blocks_for_male
+        all_beds = (beds_for_pre + beds_for_fresh +
+            beds_for_returning + beds_for_final)
+        #import pdb;pdb.set_trace()
+        for block in all_blocks:
+            sex = 'male'
+            if block in blocks_for_female:
+                sex = 'female'
+            for floor in range(1,int(self.floors_per_block)+1):
+                for room in range(1,int(self.rooms_per_floor)+1):
+                    for bed in all_beds:
+                        room_nr = floor*100 + room
+                        bt = 'all'
+                        if (block,room_nr) in beds_reserved:
+                            bt = "reserved"
+                        # Hostels with special handling and
+                        # without bed categorisation
+                        elif (self.special_handling != 'none' and not
+                              self.special_handling.endswith("_withcat")):
+                            bt = self.special_handling[3:]
+                        elif bed in beds_for_fresh:
+                            bt = 'fr'
+                        elif bed in beds_for_pre:
+                            bt = 'pr'
+                        elif bed in beds_for_final:
+                            bt = 'fi'
+                        elif bed in beds_for_returning:
+                            bt = 're'
+                        # Hostels with special handling and
+                        # with bed categorisation
+                        if (self.special_handling != 'none' and
+                            self.special_handling.endswith("_withcat")):
+                            bt += "_" + self.special_handling
+                        bt = u'%(sex)s_%(bt)s' % vars()
+                        uid = u'%s_%s_%d_%s' % (self.hostel_id,block,room_nr,bed)
+                        if self.has_key(uid):
+                            bed = self[uid]
+                            if bed.bed_type != bt:
+                                bed.bed_type = bt
+                                bed.sort_id = getattr(self,'sort_id',0)
+                                #modified.append('"%(uid)s","%(bt)s","%(bed.owner)s"' % vars())
+                                modified_counter += 1
+                        else:
+                            bed = Bed()
+                            bed.bed_id = uid
+                            bed.bed_type = bt
+                            bed.sort_id = getattr(self,'sort_id',0)
+                            bed.owner = NOT_OCCUPIED
+                            self.addBed(bed)
+                            #generated.append('"%(uid)s","%(bt)s"' % vars())
+                            added_counter +=1
+        return added_counter, modified_counter
 
 Hostel = attrs_to_fields(Hostel)
Index: main/waeup.sirp/trunk/src/waeup/sirp/hostels/interfaces.py
===================================================================
--- main/waeup.sirp/trunk/src/waeup/sirp/hostels/interfaces.py	(revision 6966)
+++ main/waeup.sirp/trunk/src/waeup/sirp/hostels/interfaces.py	(revision 6970)
@@ -1,8 +1,9 @@
 ##
 ## interfaces.py
-from zope.interface import Attribute, invariant
+from zope.interface import Attribute, invariant, Invalid
 from zope import schema
 from waeup.sirp.interfaces import IWAeUPObject
-from waeup.sirp.hostels.vocabularies import bed_letters, blocks
+from waeup.sirp.hostels.vocabularies import (
+    bed_letters, blocks, special_handling)
 
 class IHostelsContainer(IWAeUPObject):
@@ -18,4 +19,8 @@
     def loggerInfo(ob_class, comment):
         """Adds an INFO message to the log file
+        """
+
+    def updateBeds():
+        """Fill hostel with beds or update beds.
         """
 
@@ -37,10 +42,4 @@
         )
 
-    nr_of_blocks = schema.Int(
-        title = u'Number of Blocks',
-        required = True,
-        default = 3,
-        )
-
     floors_per_block = schema.Int(
         title = u'Floors per Block',
@@ -55,12 +54,19 @@
         )
 
-    beds_per_room = schema.Int(
-        title = u'Beds per Room',
-        required = True,
-        default = 6,
-        )
+    #beds_per_room = schema.Int(
+    #    title = u'Beds per Room',
+    #    required = True,
+    #    default = 6,
+    #    )
 
     blocks_for_female = schema.List(
         title = u'Blocks for Female Students',
+        value_type = schema.Choice(
+            vocabulary = blocks
+            ),
+        )
+
+    blocks_for_male = schema.List(
+        title = u'Blocks for Male Students',
         value_type = schema.Choice(
             vocabulary = blocks
@@ -75,4 +81,11 @@
         )
 
+    beds_for_returning = schema.List(
+        title = u'Beds for Returning Students',
+        value_type = schema.Choice(
+            vocabulary = bed_letters
+            ),
+        )
+
     beds_for_final = schema.List(
         title = u'Beds for Final Year Students',
@@ -81,4 +94,43 @@
             ),
         )
+
+    special_handling = schema.Choice(
+        title = u'Special Handling',
+        vocabulary = special_handling,
+        required = True,
+        default = u'none',
+        )
+
+    reserved = schema.TextLine(
+        title = u'Reserved Rooms',
+        required = False,
+        default = u'',
+        )
+
+    @invariant
+    def blocksOverlap(hostel):
+        bfe = hostel.blocks_for_female
+        bma = hostel.blocks_for_male
+        if set(bfe).intersection(set(bma)):
+            raise Invalid('Female and male blocks overlap.')
+
+    @invariant
+    def bedsOverlap(hostel):
+        bfr = hostel.beds_for_fresh
+        bre = hostel.beds_for_returning
+        bfi = hostel.beds_for_final
+        if (set(bfr).intersection(set(bre)) or
+            set(bfr).intersection(set(bfi)) or
+            set(bre).intersection(set(bfi))):
+            raise Invalid('Bed categories overlap.')
+
+    #@invariant
+    #def numberOfBeds(hostel):
+    #    bfr = hostel.beds_for_fresh
+    #    bre = hostel.beds_for_returning
+    #    bfi = hostel.beds_for_final
+    #    if len(bfr + bre + bfi) != hostel.beds_per_room:
+    #        raise Invalid(
+    #            'Bed categories and number of beds per room do not match.')
 
 class IBed(IWAeUPObject):
Index: main/waeup.sirp/trunk/src/waeup/sirp/hostels/tests.py
===================================================================
--- main/waeup.sirp/trunk/src/waeup/sirp/hostels/tests.py	(revision 6966)
+++ main/waeup.sirp/trunk/src/waeup/sirp/hostels/tests.py	(revision 6970)
@@ -133,6 +133,6 @@
 <li>Block B</li></ul>...'''
         self.assertMatches(expected,self.browser.contents)
-        self.browser.open(self.container_path + '/hall_1/edit')
-        self.browser.getControl(name="form.nr_of_blocks").value = '5'
+        self.browser.open(self.container_path + '/hall_1/manage')
+        self.browser.getControl(name="form.floors_per_block").value = '4'
         self.browser.getControl("Save").click()
         self.assertTrue('Form has been saved' in self.browser.contents)
Index: main/waeup.sirp/trunk/src/waeup/sirp/hostels/vocabularies.py
===================================================================
--- main/waeup.sirp/trunk/src/waeup/sirp/hostels/vocabularies.py	(revision 6966)
+++ main/waeup.sirp/trunk/src/waeup/sirp/hostels/vocabularies.py	(revision 6970)
@@ -34,2 +34,8 @@
     ('Block P','P'),
     )
+
+special_handling = SimpleWAeUPVocabulary(
+    ('No special handling','none'),
+    ('Blocked','blocked'),
+    ('Postgraduate Hostel','pg'),
+    )
