================
Special Day View
================

Special days are days for which some periods are shortened or cancelled
altogether.  Our view for that presents the administrator with a way to alter
the schoolday template for this day.

First of all, we need an app object:

    >>> from schooltool.testing import setup as sbsetup
    >>> app = sbsetup.setUpSchoolToolSite()
    >>> from schooltool.timetable.schema import TimetableSchemaContainer
    >>> schemas = TimetableSchemaContainer()
    >>> from zope.location.location import locate
    >>> locate(schemas, app, 'ttschemas')

    >>> from schooltool.term.term import getTermContainer
    >>> from schooltool.term.interfaces import ITermContainer
    >>> from zope.interface import Interface
    >>> from zope.component import provideAdapter
    >>> from schooltool.schoolyear.schoolyear import getSchoolYearContainer
    >>> provideAdapter(getTermContainer, [Interface], ITermContainer)
    >>> provideAdapter(getSchoolYearContainer)

We have a timetable schema to put the view on:

    >>> from schooltool.timetable.browser.tests.test_timetable import \
    ...      createSchema
    >>> from schooltool.timetable.browser.timetable import SpecialDayView
    >>> ttschema = createSchema(['Day 1', 'Day 2'],
    ...                         ['First',
    ...                          'Second',
    ...                          'Third',
    ...                          'Fourth'])
    >>> schemas['usual'] = ttschema

The schema has a model attribute:

    >>> from schooltool.timetable.browser.tests.test_timetable import \
    ...      createDayTemplate
    >>> from schooltool.timetable.model import SequentialDaysTimetableModel
    >>> default = createDayTemplate([(9, 0, 45),
    ...                              (10, 0, 45),
    ...                              (11, 0, 45),
    ...                              (12, 0, 45)])
    >>> ttschema.model = SequentialDaysTimetableModel(['Day 1', 'Day 2'],
    ...                                               {None: default})

We will need a schoolyear and a term:

    >>> import datetime

    >>> from schooltool.schoolyear.schoolyear import SchoolYear
    >>> from schooltool.schoolyear.interfaces import ISchoolYearContainer
    >>> schoolyears = ISchoolYearContainer(app)
    >>> schoolyears['2005'] = SchoolYear("2005",
    ...                                  datetime.date(2005, 2, 1),
    ...                                  datetime.date(2005, 12, 31))

    >>> from schooltool.term.term import Term
    >>> ITermContainer(app)["2005-summer"] = Term('2005 summer',
    ...                                           datetime.date(2005, 6, 1),
    ...                                           datetime.date(2005, 8, 31))
    >>> ITermContainer(app)["2005-summer"].addWeekdays(0, 1, 2, 3, 4)

Now we can call the view.  First we get asked what day do we want to change:

    >>> from zope.publisher.browser import TestRequest
    >>> request = TestRequest()
    >>> view = SpecialDayView(ttschema, request)
    >>> print view()
    <BLANKLINE>
    ...
      <p>
        Please enter the date when the periods need to be changed below.
      </p>
    <BLANKLINE>
      <div class="row">
        <label for="date">Date</label>
        <input type="text" name="date" id="date" />
      </div>
    <BLANKLINE>
      <div class="controls">
        <input type="submit" class="button-ok" name="CHOOSE"
               value="Proceed" />
        <input type="submit" class="button-cancel" name="CANCEL"
               value="Cancel" />
      </div>
    ...

    >>> `view.template` == `view.select_template`
    True

If we pass a correct date to the view, it gets set as an attribute:

    >>> request = TestRequest(form={'date': '2005-07-05'})
    >>> view = SpecialDayView(ttschema, request)
    >>> view.update()
    >>> view.date
    datetime.date(2005, 7, 5)
    >>> `view.template` == `view.form_template`
    True

Our view now can get a list of period titles, start and end times:

    >>> pprint(view.getPeriods())
    [('First', '09:00', '09:45', '09:00', '09:45'),
     ('Second', '10:00', '10:45', '10:00', '10:45'),
     ('Third', '11:00', '11:45', '11:00', '11:45'),
     ('Fourth', '12:00', '12:45', '12:00', '12:45')]

The user is taken to the next step.  He gets a table with period names and
times, and fields for new start and end times:

    >>> print view()
    <BLANKLINE>
    ...
       <input type="hidden" name="date" value="2005-07-05" />
       <table>
         <tr>
           <th>Period title</th>
           <th>Original start</th>
           <th>Original end</th>
           <th>New start</th>
           <th>New end</th>
         </tr>
         <tr>
           <td>First</td>
           <td>09:00</td>
           <td>09:45</td>
           <td>
             <input type="text" name="First_start" value="09:00" />
           </td>
           <td>
             <input type="text" name="First_end" value="09:45" />
           </td>
         </tr>
         <tr>
           <td>Second</td>
           <td>10:00</td>
           <td>10:45</td>
           <td>
             <input type="text" name="Second_start"
                    value="10:00" />
           </td>
           <td>
             <input type="text" name="Second_end" value="10:45" />
           </td>
         </tr>
         <tr>
           <td>Third</td>
           <td>11:00</td>
           <td>11:45</td>
           <td>
             <input type="text" name="Third_start" value="11:00" />
           </td>
           <td>
             <input type="text" name="Third_end" value="11:45" />
           </td>
         </tr>
         <tr>
           <td>Fourth</td>
           <td>12:00</td>
           <td>12:45</td>
           <td>
             <input type="text" name="Fourth_start"
                    value="12:00" />
           </td>
           <td>
             <input type="text" name="Fourth_end" value="12:45" />
           </td>
         </tr>
       </table>
    ...
        <input type="submit" class="button-ok" name="SUBMIT"
               value="Modify" />
    ...

Now the user can fill in the form and create an exception template for this
day.

    >>> request = TestRequest(form={'date': '2005-07-05',
    ...                             'SUBMIT': 'next',
    ...                             'First_start': '8:00',
    ...                             'First_end': '8:30',
    ...                             'Second_start': '',
    ...                             'Second_end': '',
    ...                             'Third_start': '9:30',
    ...                             'Third_end': '10:00',
    ...                             'Fourth_start': '',
    ...                             'Fourth_end': '',
    ...                             })
    >>> view = SpecialDayView(ttschema, request)
    >>> from datetime import time, date, timedelta
    >>> view.update()
    >>> pprint(view.extractPeriods())
    [('First', datetime.time(8, 0), datetime.timedelta(0, 1800)),
     ('Third', datetime.time(9, 30), datetime.timedelta(0, 1800))]

The processing does not raise:

    >>> result = view()

There are no field errors:

    >>> view.field_errors
    []

The actual exception gets added:

    >>> exception = ttschema.model.exceptionDays[datetime.date(2005, 7, 5)]
    >>> exception
    [('First', <schooltool.timetable.SchooldaySlot object at ...>),
     ('Third', <schooltool.timetable.SchooldaySlot object at ...>)]

    >>> for period, slot in exception:
    ...     print period, slot.tstart, slot.duration
    First 08:00:00 0:30:00
    Third 09:30:00 0:30:00

The user is redirected to the schema main page:

    >>> request.response.getStatus()
    302
    >>> request.response.getHeader('location')
    'http://127.0.0.1/ttschemas/usual'

If we revisit this date, we see the original times on the left, and the times
of the exceptional template filled in in the form:

    >>> request = TestRequest(form={'date': '2005-07-05'})
    >>> view = SpecialDayView(ttschema, request)
    >>> print view()
    <BLANKLINE>
    ...
       <table>
         <tr>
           <th>Period title</th>
           <th>Original start</th>
           <th>Original end</th>
           <th>New start</th>
           <th>New end</th>
         </tr>
         <tr>
           <td>First</td>
           <td>09:00</td>
           <td>09:45</td>
           <td>
             <input type="text" name="First_start" value="08:00" />
           </td>
           <td>
             <input type="text" name="First_end" value="08:30" />
           </td>
         </tr>
         <tr>
           <td>Second</td>
           <td>10:00</td>
           <td>10:45</td>
           <td>
             <input type="text" name="Second_start" value="" />
           </td>
           <td>
             <input type="text" name="Second_end" value="" />
           </td>
         </tr>
         <tr>
           <td>Third</td>
           <td>11:00</td>
           <td>11:45</td>
           <td>
             <input type="text" name="Third_start" value="09:30" />
           </td>
           <td>
             <input type="text" name="Third_end" value="10:00" />
           </td>
         </tr>
         <tr>
           <td>Fourth</td>
           <td>12:00</td>
           <td>12:45</td>
           <td>
             <input type="text" name="Fourth_start" value="" />
           </td>
           <td>
             <input type="text" name="Fourth_end" value="" />
           </td>
         </tr>
       </table>
    ...
        <input type="submit" class="button-ok" name="SUBMIT"
               value="Modify" />
    ...

The disabled periods can be reenabled:

    >>> request = TestRequest(form={'date': '2005-07-05',
    ...                             'SUBMIT': 'next',
    ...                             'First_start': '8:00',
    ...                             'First_end': '8:30',
    ...                             'Second_start': '8:45',
    ...                             'Second_end': '9:15',
    ...                             'Third_start': '9:30',
    ...                             'Third_end': '10:00',
    ...                             'Fourth_start': '11:00',
    ...                             'Fourth_end': '12:00',
    ...                             })
    >>> view = SpecialDayView(ttschema, request)
    >>> from datetime import time, date, timedelta
    >>> view.update()
    >>> pprint(view.extractPeriods())
    [('First', datetime.time(8, 0), datetime.timedelta(0, 1800)),
     ('Second', datetime.time(8, 45), datetime.timedelta(0, 1800)),
     ('Third', datetime.time(9, 30), datetime.timedelta(0, 1800)),
     ('Fourth', datetime.time(11, 0), datetime.timedelta(0, 3600))]


Cancel button
-------------

If the user hits the Cancel button, he gets redurected to the ttschema default
view:

    >>> request = TestRequest(form={'date': '2005-07-06',
    ...                             'CANCEL': 'next',
    ...                             'First_start': '8:00',
    ...                             'First_end': '8:30',
    ...                             'Second_start': '8:45',
    ...                             'Second_end': '9:15',
    ...                             'Third_start': '9:30',
    ...                             'Third_end': '10:00',
    ...                             'Fourth_start': '',
    ...                             'Fourth_end': '',
    ...                             })
    >>> view = SpecialDayView(ttschema, request)
    >>> result = view()
    >>> request.response.getStatus()
    302
    >>> request.response.getHeader('location')
    'http://127.0.0.1/ttschemas/usual'

No exception gets added:

    >>> ttschema.model.exceptionDays[datetime.date(2005, 7, 6)]
    Traceback (most recent call last):
      ...
    KeyError: datetime.date(2005, 7, 6)


The Boring Bit -- Various Error Conditions
------------------------------------------

What if the date is incorrect?

    >>> request = TestRequest(form={'date': 'Your father was a hamster'})
    >>> view = SpecialDayView(ttschema, request)
    >>> result = view()
    >>> view.error == 'Invalid date. Please use YYYY-MM-DD format.'
    True
    >>> view.error in result
    True
    >>> `view.template` == `view.select_template`
    True

What if the date is not in a term?

    >>> request = TestRequest(form={'date': '2004-01-01'})
    >>> view = SpecialDayView(ttschema, request)
    >>> result = view()
    >>> view.error == 'The date does not belong to any term.'
    True
    >>> view.error in result
    True

We\'re courteous enough though to leave the date intact in the input field:

    >>> 'value="2004-01-01"' in result
    True

What if the start/end times are incorrect?  Highlight them with a red border.

If either a start or an end time is provided, the other must be provided as
well.  Otherwise it is considered an error.

    >>> request = TestRequest(form={'date': '2005-07-13',
    ...                             'SUBMIT': 'next',
    ...                             'First_start': '800',
    ...                             'First_end': '8:30',
    ...                             'Second_start': '',
    ...                             'Second_end': '9:15',
    ...                             'Third_start': '9:30',
    ...                             'Third_end': '',
    ...                             'Fourth_start': '14:00',
    ...                             'Fourth_end': '15:00',
    ...                             })
    >>> view = SpecialDayView(ttschema, request)
    >>> result = view()

Update did not happen:

    >>> ttschema.model.exceptionDays[datetime.date(2005, 7, 13)]
    Traceback (most recent call last):
      ...
    KeyError: datetime.date(2005, 7, 13)

The erroneous fields are noticed:

    >>> view.field_errors
    ['First_start', 'Second_start', 'Third_end']

    >>> view.error
    u'Some values were invalid.  They are highlighted in red.'

    >>> print result
    <BLANKLINE>
    ...
       <table>
         <tr>
           <th>Period title</th>
           <th>Original start</th>
           <th>Original end</th>
           <th>New start</th>
           <th>New end</th>
         </tr>
         <tr>
           <td>First</td>
           <td>09:00</td>
           <td>09:45</td>
           <td class="error">
             <input type="text" name="First_start" value="800" />
           </td>
           <td>
             <input type="text" name="First_end" value="8:30" />
           </td>
         </tr>
         <tr>
           <td>Second</td>
           <td>10:00</td>
           <td>10:45</td>
           <td class="error">
             <input type="text" name="Second_start" value="" />
           </td>
           <td>
           <input type="text" name="Second_end" value="9:15" />
           </td>
         </tr>
         <tr>
           <td>Third</td>
           <td>11:00</td>
           <td>11:45</td>
           <td>
             <input type="text" name="Third_start" value="9:30" />
           </td>
           <td class="error">
             <input type="text" name="Third_end" value="" />
           </td>
         </tr>
         <tr>
           <td>Fourth</td>
           <td>12:00</td>
           <td>12:45</td>
           <td>
             <input type="text" name="Fourth_start"
                    value="14:00" />
           </td>
           <td>
             <input type="text" name="Fourth_end" value="15:00" />
           </td>
         </tr>
       </table>
    ...
