## $Id: utils.py 9831 2013-01-05 22:45:40Z 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
##
import grok
from time import time
from zope.component import createObject, getUtility
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.platypus import Paragraph, Image, Table, Spacer
from waeup.kofa.interfaces import (IKofaUtils,
    CLEARED, RETURNING, PAID, REGISTERED, VALIDATED)
from kofacustom.nigeria.students.utils import NigeriaStudentsUtils
from waeup.kofa.accesscodes import create_accesscode
from waeup.uniben.interfaces import MessageFactory as _
from waeup.kofa.students.utils import (trans, render_student_data,
    render_table_data, get_signature_table)

class CustomStudentsUtils(NigeriaStudentsUtils):
    """A collection of customized methods.

    """

    def getReturningData(self, student):
        """ This method defines what happens after school fee payment
        of returning students depending on the student's senate verdict.
        """
        prev_level = student['studycourse'].current_level
        cur_verdict = student['studycourse'].current_verdict
        if cur_verdict in ('A','B','L','M','N','Z',):
            # Successful student
            new_level = divmod(int(prev_level),100)[0]*100 + 100
        elif cur_verdict == 'C':
            # Student on probation
            new_level = int(prev_level) + 10
        else:
            # Student is somehow in an undefined state.
            # Level has to be set manually.
            new_level = prev_level
        new_session = student['studycourse'].current_session + 1
        return new_session, new_level

    def _paymentMade(self, student, session):
        if len(student['payments']):
            for ticket in student['payments'].values():
                if ticket.p_state == 'paid' and \
                    ticket.p_category == 'schoolfee' and \
                    ticket.p_session == session:
                    return True
        return False

    def setPaymentDetails(self, category, student,
            previous_session, previous_level):
        """Create Payment object and set the payment data of a student for
        the payment category specified.

        """
        p_item = u''
        amount = 0.0
        if previous_session:
            if previous_session < student['studycourse'].entry_session:
                return _('The previous session must not fall below '
                         'your entry session.'), None
            if category == 'schoolfee':
                # School fee is always paid for the following session
                if previous_session > student['studycourse'].current_session:
                    return _('This is not a previous session.'), None
            else:
                if previous_session > student['studycourse'].current_session - 1:
                    return _('This is not a previous session.'), None
            p_session = previous_session
            p_level = previous_level
            p_current = False
        else:
            p_session = student['studycourse'].current_session
            p_level = student['studycourse'].current_level
            p_current = True
        academic_session = self._getSessionConfiguration(p_session)
        if academic_session == None:
            return _(u'Session configuration object is not available.'), None
        # Determine fee.
        if category == 'transfer':
            amount = academic_session.transfer_fee
        elif category == 'gown':
            amount = academic_session.gown_fee
        elif category == 'bed_allocation':
            amount = academic_session.booking_fee
        elif category == 'hostel_maintenance':
            amount = academic_session.maint_fee
        elif category == 'tempmaint_1':
            amount = 8150.0
        elif category == 'tempmaint_2':
            amount = 12650.0
        elif category == 'tempmaint_3':
            amount = 9650.0
        elif category == 'clearance':
            p_item = student.certcode
            if p_item is None:
                return _('Study course data are incomplete.'), None
            if student.faccode == 'FCETA':
                amount = 22500.0
            elif p_item in ('BSCANA', 'BSCMBC', 'BMLS', 'BSCNUR', 'BSCPHS', 'BDS',
                'MBBSMED', 'MBBSNDU'):
                amount = 65000.0
            elif p_item in ('BEDCET', 'BIOEDCET', 'CHMEDCET', 'ISEDCET',
                'MTHEDCET', 'PHYEDCET', 'ITECET', 'AGREDCET', 'HEEDCET'):
                amount = 22500.0
            else:
                amount = 45000.0
        elif category == 'schoolfee':
            try:
                certificate = student['studycourse'].certificate
                p_item = certificate.code
            except (AttributeError, TypeError):
                return _('Study course data are incomplete.'), None
            if previous_session:
                # Students can pay for previous sessions in all workflow states.
                # Fresh students are excluded by the update method of the
                # PreviousPaymentAddFormPage.
                if previous_session == student['studycourse'].entry_session:
                    if student.is_foreigner:
                        amount = getattr(certificate, 'school_fee_3', 0.0)
                    else:
                        amount = getattr(certificate, 'school_fee_1', 0.0)
                else:
                    if student.is_foreigner:
                        amount = getattr(certificate, 'school_fee_4', 0.0)
                    else:
                        amount = getattr(certificate, 'school_fee_2', 0.0)
            else:
                if student.state == CLEARED:
                    if student.is_foreigner:
                        amount = getattr(certificate, 'school_fee_3', 0.0)
                    else:
                        amount = getattr(certificate, 'school_fee_1', 0.0)
                elif student.state in (PAID, REGISTERED, VALIDATED):
                    p_session += 1
                    # We don't know which level the student is paying for.
                    p_level = None
                    academic_session = self._getSessionConfiguration(p_session)
                    if academic_session == None:
                        return _(u'Session configuration object is not available.'), None

                    # Students are only allowed to pay for the next session
                    # if current session payment
                    # has really been made, i.e. payment object exists.
                    #if not self._paymentMade(
                    #    student, student.current_session):
                    #    return _('You have not yet paid your current/active' +
                    #             ' session. Please use the previous session' +
                    #             ' payment form first.'), None

                    if student.is_foreigner:
                        amount = getattr(certificate, 'school_fee_4', 0.0)
                    else:
                        amount = getattr(certificate, 'school_fee_2', 0.0)
                elif student.state == RETURNING:
                    # In case of returning school fee payment the payment session
                    # and level contain the values of the session the student
                    # has paid for.
                    p_session, p_level = self.getReturningData(student)
                    academic_session = self._getSessionConfiguration(p_session)
                    if academic_session == None:
                        return _(u'Session configuration object is not available.'), None

                    # Students are only allowed to pay for the next session
                    # if current session payment has really been made,
                    # i.e. payment object exists and is paid.
                    #if not self._paymentMade(
                    #    student, student.current_session):
                    #    return _('You have not yet paid your current/active' +
                    #             ' session. Please use the previous session' +
                    #             ' payment form first.'), None

                    if student.is_foreigner:
                        amount = getattr(certificate, 'school_fee_4', 0.0)
                    else:
                        amount = getattr(certificate, 'school_fee_2', 0.0)
            # Give 50% school fee discount to staff members.
            if student.is_staff:
                amount /= 2
        if amount in (0.0, None):
            return _('Amount could not be determined.'), None
        # Add session specific penalty fee.
        if category == 'schoolfee' and student.is_postgrad:
            amount += academic_session.penalty_pg
        elif category == 'schoolfee':
            amount += academic_session.penalty_ug
        # XXX: Obsolete in 2013
        if category.startswith('tempmaint'):
            p_item = getUtility(IKofaUtils).PAYMENT_CATEGORIES[category]
            p_item = unicode(p_item)
            # Now we change the category because tempmaint payments
            # will be obsolete in 2013
            category = 'hostel_maintenance'
        # Create ticket.
        for key in student['payments'].keys():
            ticket = student['payments'][key]
            if ticket.p_state == 'paid' and\
               ticket.p_category == category and \
               ticket.p_item == p_item and \
               ticket.p_session == p_session:
                  return _('This type of payment has already been made.'), None
        payment = createObject(u'waeup.StudentOnlinePayment')
        timestamp = ("%d" % int(time()*10000))[1:]
        payment.p_id = "p%s" % timestamp
        payment.p_category = category
        payment.p_item = p_item
        payment.p_session = p_session
        payment.p_level = p_level
        payment.p_current = p_current
        payment.amount_auth = amount
        return None, payment

    def maxCredits(self, studylevel):
        """Return maximum credits.

        """
        studycourse = studylevel.__parent__
        certificate = getattr(studycourse,'certificate', None)
        current_level = studycourse.current_level
        if None in (current_level, certificate):
            return 0
        end_level = certificate.end_level
        if current_level >= end_level:
            return 51
        return 50

    # Uniben prefix
    STUDENT_ID_PREFIX = u'B'