## $Id: utils.py 7310 2011-12-08 08:38:02Z henrik $
##
## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 2 of the License, or
## (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program; if not, write to the Free Software
## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
##
"""General helper functions for the student section.
"""
import grok
from random import SystemRandom as r
from datetime import datetime
from reportlab.pdfgen import canvas
from reportlab.lib.units import cm
from reportlab.lib.enums import TA_RIGHT
from reportlab.lib.pagesizes import A4
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.platypus import (Frame, Paragraph, Image,
    Table, Spacer)
from reportlab.platypus.tables import TableStyle
from reportlab.platypus.flowables import PageBreak
from zope.component import getUtility
from zope.formlib.form import setUpEditWidgets
from waeup.sirp.interfaces import IExtFileStore
from waeup.sirp.students.interfaces import IStudentsUtils

SLIP_STYLE = TableStyle(
    [('VALIGN',(0,0),(-1,-1),'TOP')]
    )

CONTENT_STYLE = TableStyle(
    [('VALIGN',(0,0),(-1,-1),'TOP')]
    )

def generate_student_id(students,letter):
    if letter == '?':
        letter= r().choice('ABCDEFGHKLMNPQRSTUVWXY')
    sid = u"%c%d" % (letter,r().randint(99999,1000000))
    while sid in students.keys():
        sid = u"%c%d" % (letter,r().randint(99999,1000000))
    return sid

def set_returning_data(student):
    student['studycourse'].current_level += 100
    student['studycourse'].current_session += 1
    verdict = student['studycourse'].current_verdict
    student['studycourse'].current_verdict = '0'
    student['studycourse'].previous_verdict = verdict
    return

def set_up_widgets(view, ignore_request=False):
    view.adapters = {}
    view.widgets = setUpEditWidgets(
        view.form_fields, view.prefix, view.context, view.request,
        adapters=view.adapters, for_display=True,
        ignore_request=ignore_request
        )

def render_student_data(studentview):
    set_up_widgets(studentview, ignore_request=True)
    data = []
    style = getSampleStyleSheet()
    img = getUtility(IExtFileStore).getFileByContext(
        studentview.context, attr='passport.jpg')
    if img is None:
        from waeup.sirp.browser import DEFAULT_PASSPORT_IMAGE_PATH
        img = open(DEFAULT_PASSPORT_IMAGE_PATH, 'rb')
    doc_img = Image(img.name, width=4*cm, height=3*cm, kind='bound')
    data.append([doc_img])
    data.append([Spacer(1, 12)])
    for widget in studentview.widgets:
        if widget.name == 'form.adm_code':
            continue
        f_label = '<font size=12>%s</font>:' % (
            widget.label.strip())
        f_label = Paragraph(f_label, style["Normal"])
        f_text = '<font size=12>%s</font>' % widget()
        f_text = Paragraph(f_text, style["Normal"])
        data.append([f_label,f_text])
    table = Table(data,style=SLIP_STYLE)
    return table

def insert_footer(pdf,width,style,text=None):
      story = []
      frame_footer = Frame(1*cm,0,width-(2*cm),1*cm)
      timestamp = datetime.now().strftime("%d/%m/%Y %H:%M:%S")
      left_text = '<font size=10>%s</font>' % timestamp
      story.append(Paragraph(left_text, style["Normal"]))
      frame_footer.addFromList(story,pdf)
      story = []
      frame_footer = Frame(1*cm,0,width-(2*cm),1*cm)
      right_text = '<font size=10>%s Page %s</font>' % (
          text, pdf.getPageNumber())
      story.append(Paragraph(right_text, style["Right"]))
      frame_footer.addFromList(story,pdf)

def render_table_data(tableheader,tabledata):
    data = []
    data.append([Spacer(1, 12)])
    line = []
    style = getSampleStyleSheet()
    for element in tableheader:
        field = '<strong><font size=10>%s</font></strong>' % element[0]
        field = Paragraph(field, style["Normal"])
        line.append(field)
    data.append(line)
    for ticket in tabledata:
        line = []
        for element in tableheader:
              fieldcontent = getattr(ticket,element[1],u' ')
              field = '<font size=10>%s</font>' % fieldcontent
              field = Paragraph(field, style["BodyText"])
              line.append(field)
        data.append(line)
    # ToDo: The table does not show up if there are too many line
    # and it thus doesn't fit on the page
    table = Table(data,colWidths=[
        element[2]*cm for element in tableheader],style=CONTENT_STYLE)
    return table

class StudentsUtils(grok.GlobalUtility):
    """A collection of methods subject to customization.
    """
    grok.implements(IStudentsUtils)

    def getPaymentDetails(self,category, student):
        d = {}
        d['p_item'] = u''
        d['amount'] = 0
        d['error'] = u''
        d['p_session'] = student['studycourse'].current_session
        session = str(d['p_session'])
        try:
            academic_session = grok.getSite()['configuration'][session]
        except KeyError:
            d['error'] = u'Session configuration object is not available.'
            return d
        d['surcharge_1'] = academic_session.surcharge_1
        d['surcharge_2'] = academic_session.surcharge_2
        d['surcharge_3'] = academic_session.surcharge_3
        if category == 'schoolfee':
            d['amount'] = academic_session.school_fee_base
            d['p_item'] = student['studycourse'].certificate.code
        elif category == 'clearance':
            d['p_item'] = student['studycourse'].certificate.code
            d['amount'] = academic_session.clearance_fee
        elif category == 'bed_allocation':
            d['p_item'] = self.getAccommodationDetails(student)['bt']
            d['amount'] = academic_session.booking_fee
        return d

    def getAccommodationDetails(self, student):
        d = {}
        d['error'] = u''
        site_confoguration = grok.getSite()['configuration']
        d['booking_session'] = site_confoguration.accommodation_session
        d['allowed_states'] = site_confoguration.accommodation_states
        # Determine bed type
        studycourse = student['studycourse']
        entry_session = studycourse.entry_session
        current_level = studycourse.current_level
        end_level = studycourse.certificate.end_level
        if entry_session == grok.getSite()['configuration'].accommodation_session:
            bt = 'fr'
        elif current_level >= end_level:
            bt = 'fi'
        else:
            bt = 're'
        if student.sex == 'f':
            sex = 'female'
        else:
            sex = 'male'
        special_handling = 'regular'
        d['bt'] = u'%s_%s_%s' % (special_handling,sex,bt)
        return d

    # In the standard configuration we select the first bed found,
    # but can also randomize the selection if we like.
    def selectBed(self, available_beds):
        return available_beds[0]

    def renderPDF(self, view, subject='', filename='slip.pdf',
        student=None, studentview=None, tableheader=None, tabledata=None):
        # (0,0),(-1,-1) = whole table
        # (0,0),(0,-1) = first column
        # (-1,0),(-1,-1) = last column
        # (0,0),(-1,0) = first row
        # (0,-1),(-1,-1) = last row

        pdf = canvas.Canvas(filename,pagesize=A4)
        pdf.setTitle(view.label)
        pdf.setSubject(subject)
        pdf.setAuthor('%s (%s)' % (view.request.principal.title,
            view.request.principal.id))
        pdf.setCreator('WAeUP SIRP')
        width, height = A4
        footer_text = view.label
        if student is not None:
            footer_text = "%s - %s - " % (student.student_id, footer_text)
        style = getSampleStyleSheet()
        style.add(ParagraphStyle(name='Right', alignment=TA_RIGHT))
        pdf.line(1*cm,height-(1.8*cm),width-(1*cm),height-(1.8*cm))

        story = []
        frame_header = Frame(1*cm,1*cm,width-(1.7*cm),height-(1.7*cm))
        header_title = getattr(grok.getSite(), 'name', u'Sample University')
        story.append(Paragraph(header_title, style["Heading1"]))
        frame_header.addFromList(story,pdf)

        story = []
        frame_body = Frame(1*cm,1*cm,width-(2*cm),height-(3.5*cm))
        story.append(Paragraph(view.label, style["Heading2"]))

        # Insert student data table
        if student is not None:
            story.append(Spacer(1, 12))
            studenttable = render_student_data(studentview)
            story.append(studenttable)

        story.append(Spacer(1, 12))
        #story.append(PageBreak())
        set_up_widgets(view)
        data = []
        for widget in view.widgets:
            f_label = '<font size=12>%s</font>:' % widget.label.strip()
            f_label = Paragraph(f_label, style["Normal"])
            f_text = '<font size=12>%s</font>' % widget()
            f_text = Paragraph(f_text, style["Normal"])
            data.append([f_label,f_text])
        # First, import browser components locally
        # to avoid circular import
        from waeup.sirp.students.viewlets import FileManager
        from waeup.sirp.browser import DEFAULT_IMAGE_PATH
        fm = FileManager(view.context, view.request, view)
        # Collect viewlets
        fm.update()
        # Insert list of scanned documents
        for viewlet in fm.viewlets:
            f_label = '<font size=12>%s</font>' % viewlet.label
            f_label = Paragraph(f_label, style["Normal"])
            if viewlet.template.__grok_name__ == 'imagedisplay':
                # In case we define FileDisplay viewlets with
                # an imagedisplay template in the customization package
                img = getUtility(IExtFileStore).getFileByContext(
                    view.context, attr=viewlet.download_name)
                if img is None:
                    img = open(DEFAULT_IMAGE_PATH, 'rb')
                doc_img = Image(img.name, width=2*cm, height=1*cm, kind='bound')
                data.append([f_label,doc_img])
            else:
                f_text = '<font size=12>%s</font>' % viewlet.title
                f_text = Paragraph(f_text, style["Normal"])
                data.append([f_label,f_text])
        table = Table(data,style=SLIP_STYLE)
        story.append(table)
        try:
            frame_body.addFromList(story,pdf)
        except IOError:
            view.flash('Error in image file.')
            return view.redirect(view.url(view.context))
        insert_footer(pdf,width,style,footer_text)
        pdf.showPage()
        frame_body = Frame(1*cm,1*cm,width-(2*cm),height-(1.5*cm))
        # Insert content table
        if tabledata and tableheader:
            story = []
            #story.append(Spacer(1, 12))
            contenttable = render_table_data(tableheader,tabledata)
            story.append(contenttable)
            frame_body.addFromList(story,pdf)
        insert_footer(pdf,width,style,footer_text)
        view.response.setHeader(
            'Content-Type', 'application/pdf')
        return pdf.getpdfdata()
