## $Id: browser.py 17159 2022-11-09 12:23:24Z 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
##
"""UI components for basic applicants and related components.
"""
import grok
import os
from zope.component import getUtility, queryUtility
from zope.catalog.interfaces import ICatalog
from zope.formlib.textwidgets import BytesDisplayWidget
from waeup.kofa.interfaces import (
    IExtFileStore, IFileStoreNameChooser)
from waeup.kofa.utils.helpers import string_from_bytes, file_size, now
from waeup.kofa.applicants.browser import (
    ApplicantRegistrationPage, ApplicantsContainerPage, AdditionalFile,
    RefereeReportAddFormPage, ExportPDFReportSlipPage, ExportPDFReportSlipPage2,
    RefereeReportDisplayFormPage,
    ApplicantsContainerManageFormPage,
    ApplicantAddFormPage,
    ApplicantsRootPage)
from waeup.kofa.applicants.interfaces import (
    ISpecialApplicant, IApplicantsContainer, AppCatCertificateSource)
from kofacustom.nigeria.applicants.browser import (
    NigeriaApplicantDisplayFormPage,
    NigeriaApplicantManageFormPage,
    NigeriaApplicantEditFormPage,
    NigeriaPDFApplicationSlip)
from waeup.kofa.widgets.datewidget import (
    FriendlyDateDisplayWidget,
    FriendlyDatetimeDisplayWidget)
from kofacustom.nigeria.applicants.interfaces import (
    OMIT_DISPLAY_FIELDS,
    #UG_OMIT_DISPLAY_FIELDS,
    #UG_OMIT_PDF_FIELDS,
    #UG_OMIT_MANAGE_FIELDS,
    #UG_OMIT_EDIT_FIELDS,
    #PG_OMIT_DISPLAY_FIELDS,
    #PG_OMIT_PDF_FIELDS,
    #PG_OMIT_MANAGE_FIELDS,
    #PG_OMIT_EDIT_FIELDS,
    )
from kofacustom.iuokada.applicants.interfaces import (
    ICustomPGApplicant, ICustomUGApplicant, ICustomApplicant,
    ICustomPGApplicantEdit, ICustomUGApplicantEdit,
    ICustomApplicantOnlinePayment, ICustomApplicantRefereeReport,
    ITranscriptApplicant, ICustomApplicantRegisterUpdate
    )
from kofacustom.iuokada.interfaces import MessageFactory as _

MAX_FILE_UPLOAD_SIZE = 1024 * 500

# UG students are all undergraduate students.
UG_OMIT_DISPLAY_FIELDS = OMIT_DISPLAY_FIELDS + (
    #'jamb_subjects_list',
    'programme_type',)
UG_OMIT_PDF_FIELDS = UG_OMIT_DISPLAY_FIELDS + ('phone',)
UG_OMIT_MANAGE_FIELDS = (
    'special_application',
    #'jamb_subjects_list',
    'programme_type',
    'course1',
    'course2',)
UG_OMIT_EDIT_FIELDS = UG_OMIT_MANAGE_FIELDS + OMIT_DISPLAY_FIELDS + (
    'student_id',
    'notice',
    'screening_score',
    'screening_venue',
    'screening_date',
    #'jamb_age',
    #'jamb_subjects',
    #'jamb_score',
    #'jamb_reg_number',
    'aggregate',
    )

JUPEB_OMIT_FIELDS = (
    'jamb_age',
    'jamb_subjects',
    'jamb_score',
    'jamb_reg_number',
    'jamb_subjects_list',
    'jamb_fname',
    )

# PG has its own interface
PG_OMIT_DISPLAY_FIELDS = OMIT_DISPLAY_FIELDS + (
    'employer',
    'emp_position',
    'emp_start',
    'emp_end',
    'emp_reason',
    'employer2',
    'emp2_position',
    'emp2_start',
    'emp2_end',
    'emp2_reason',
    )
PG_OMIT_PDF_FIELDS = PG_OMIT_DISPLAY_FIELDS + ('phone',)
PG_OMIT_MANAGE_FIELDS = (
    'special_application',
    'employer',
    'emp_position',
    'emp_start',
    'emp_end',
    'emp_reason',
    'employer2',
    'emp2_position',
    'emp2_start',
    'emp2_end',
    'emp2_reason',
    'course1',
    'course2',
    )
PG_OMIT_EDIT_FIELDS = PG_OMIT_MANAGE_FIELDS + PG_OMIT_DISPLAY_FIELDS + (
    'student_id',
    'notice',
    'screening_score',
    'screening_venue',
    'screening_date',)

TRANS_OMIT_FIELDS = ('suspended', 'applicant_id',)

TRANS_SHORT_OMIT_FIELDS = TRANS_OMIT_FIELDS + (
    #'date_of_birth',
    'sex',
    'nationality',
    #'entry_mode',
    #'entry_session',
    'end_session',
    #'course_studied',
    #'course_changed',
    #'change_level',
    )

class CustomApplicantsRootPage(ApplicantsRootPage):
    
    grok.template('applicantsrootpage')

class CustomApplicantsContainerPage(ApplicantsContainerPage):
    """The standard view for regular applicant containers.
    """

    @property
    def form_fields(self):
        form_fields = grok.AutoFields(IApplicantsContainer).omit(
            'title', 'description')
        if self.request.principal.id == 'zope.anybody':
            form_fields = form_fields.omit(
                'code', 'prefix', 'year', 'mode', 'hidden',
                'strict_deadline', 'application_category',
                'application_slip_notice',
                'application_fee', 'with_picture',
                'startdate', 'enddate')
        return form_fields

class CustomApplicantsContainerManageFormPage(ApplicantsContainerManageFormPage):

    max_applicants = 5000

class CustomApplicantDisplayFormPage(NigeriaApplicantDisplayFormPage):
    """A display view for applicant data.
    """

    @property
    def form_fields(self):
        if self.target is not None and self.target == 'tscf':
            form_fields = grok.AutoFields(ITranscriptApplicant)
            for field in TRANS_OMIT_FIELDS:
                form_fields = form_fields.omit(field)
            form_fields['dispatch_address'].custom_widget = BytesDisplayWidget
            #form_fields['perm_address'].custom_widget = BytesDisplayWidget
            return form_fields
        if self.target is not None and self.target == 'tscs':
            form_fields = grok.AutoFields(ITranscriptApplicant)
            for field in TRANS_SHORT_OMIT_FIELDS:
                form_fields = form_fields.omit(field)
            form_fields['dispatch_address'].custom_widget = BytesDisplayWidget
            #form_fields['perm_address'].custom_widget = BytesDisplayWidget
            return form_fields
        if self.target is not None and self.target.startswith('pg'):
            form_fields = grok.AutoFields(ICustomPGApplicant)
            for field in PG_OMIT_DISPLAY_FIELDS:
                form_fields = form_fields.omit(field)
        else:
            form_fields = grok.AutoFields(ICustomUGApplicant)
            for field in UG_OMIT_DISPLAY_FIELDS:
                form_fields = form_fields.omit(field)
        if self.target is not None and self.target == 'pre':
            for field in JUPEB_OMIT_FIELDS:
                form_fields = form_fields.omit(field)
        #form_fields['perm_address'].custom_widget = BytesDisplayWidget
        form_fields['notice'].custom_widget = BytesDisplayWidget
        if not getattr(self.context, 'student_id'):
            form_fields = form_fields.omit('student_id')
        if not getattr(self.context, 'screening_score'):
            form_fields = form_fields.omit('screening_score')
        if not getattr(self.context, 'screening_venue') or self._not_paid():
            form_fields = form_fields.omit('screening_venue')
        if not getattr(self.context, 'screening_date') or self._not_paid():
            form_fields = form_fields.omit('screening_date')
        return form_fields

def getCerts(view, coursex):
    yield(dict(code='', title='--', selected=''))
    appcatcertificatesource = AppCatCertificateSource().factory
    for cert in appcatcertificatesource.getValues(view.context):
        selected = ''
        course = getattr(view.context, coursex)
        if course is not None and course.code == cert.code:
            selected = 'selected'
        title = appcatcertificatesource.getTitle(view.context, cert)
        yield(dict(code=cert.code, title=title, selected=selected))

def saveCourses(view):
    """In custom packages we needed to customize the certificate
    select widget. We just save course1 and course2 if these customized
    fields appear in the form.
    """
    changed_courses = []
    form = view.request.form
    course1 = form.get('custom.course1', None)
    if not course1:
        return 'Please select your 1st Choice Course of Study.', None
    cat = queryUtility(ICatalog, name='certificates_catalog')
    results = list(
        cat.searchResults(code=(course1, course1)))
    new_course1 = results[0]
    old_course1 = view.context.course1
    if old_course1 != new_course1:
        view.context.course1 = new_course1
        changed_courses.append('course1')
    new_course2 = None
    old_course2 = view.context.course2
    course2 = form.get('custom.course2', None)
    if course2:
        results = list(
            cat.searchResults(code=(course2, course2)))
        new_course2 = results[0]
    if old_course2 != new_course2:
        view.context.course2 = new_course2
        changed_courses.append('course2')
    return None, changed_courses

def display_fileupload(view, filename):
    if view.target.startswith('tsc'):
        return False
    if filename[1] == 'res_stat.pdf':
        if view.context.subtype != 'transfer':
            return False
    if filename[1] == 'jamb.pdf' \
        and view.target is not None \
        and view.target.startswith('pg'):
        return False
    if filename[1] == 'nysc.pdf' \
        and view.target is not None \
        and not view.target.startswith('pg'):
        return False
    return True

class CustomApplicantManageFormPage(NigeriaApplicantManageFormPage):
    """A full edit view for applicant data.
    """

    def getCerts(self, coursex):
        return getCerts(self, coursex)

    def saveCourses(self):
        return saveCourses(self)

    def display_fileupload(self, filename):
        return display_fileupload(self, filename)

    @property
    def display_refereereports(self):
        if self.context.refereereports:
            return True
        return False

    @property
    def form_fields(self):
        self.course_selector = False
        if self.target is not None and self.target == 'tscf':
            form_fields = grok.AutoFields(ITranscriptApplicant)
            for field in TRANS_OMIT_FIELDS:
                form_fields = form_fields.omit(field)
            return form_fields
        if self.target is not None and self.target == 'tscs':
            form_fields = grok.AutoFields(ITranscriptApplicant)
            for field in TRANS_SHORT_OMIT_FIELDS:
                form_fields = form_fields.omit(field)
            return form_fields
        self.course_selector = True
        if self.target is not None and self.target.startswith('pg'):
            form_fields = grok.AutoFields(ICustomPGApplicant)
            for field in PG_OMIT_MANAGE_FIELDS:
                form_fields = form_fields.omit(field)
        else:
            form_fields = grok.AutoFields(ICustomUGApplicant)
            for field in UG_OMIT_MANAGE_FIELDS:
                form_fields = form_fields.omit(field)
        if self.target is not None and self.target == 'pre':
            for field in JUPEB_OMIT_FIELDS:
                form_fields = form_fields.omit(field)
        form_fields['student_id'].for_display = True
        form_fields['applicant_id'].for_display = True
        return form_fields

class CustomApplicantEditFormPage(NigeriaApplicantEditFormPage):
    """An applicant-centered edit view for applicant data.
    """

    def getCerts(self, coursex):
        return getCerts(self, coursex)

    def saveCourses(self):
        return saveCourses(self)

    def display_fileupload(self, filename):
        return display_fileupload(self, filename)

    @property
    def _finalsubmit_msg(self):
        if self.context.subtype in ('transfer', 'de'):
            return 'Form has been submitted. Please note: DE and Transfer applicants are to present their application form and the proof of JAMB local transfer form at the admissions office for application approval.'
        return _('Form has been submitted.')

    def dataNotComplete(self, data):
        store = getUtility(IExtFileStore)
        if self.context.subtype \
            and self.context.subtype not in ('transfer', 'de', 'jupeb') \
            and (not self.context.jamb_fname
                 or not self.context.jamb_reg_number):
            return _('JAMB fields must be filled.')
        if self.context.subtype in ('transfer', 'de') \
            and not self.context.ref_number:
            return _('Reference Number field must be filled.')
        if self.context.__parent__.with_picture:
            store = getUtility(IExtFileStore)
            if not store.getFileByContext(self.context, attr=u'passport.jpg'):
                return _('No passport picture uploaded.')
        if self.context.subtype == 'transfer' \
            and self.context.__parent__.code!= 'ug2020' \
            and not store.getFileByContext(self.context, attr=u'res_stat.pdf'):
            return _('No statement of result pdf file uploaded.')
        return False

    @property
    def form_fields(self):
        self.course_selector = False
        if self.target is not None and self.target == 'tscf':
            form_fields = grok.AutoFields(ITranscriptApplicant)
            for field in TRANS_OMIT_FIELDS:
                form_fields = form_fields.omit(field)
                form_fields = form_fields.omit('locked')
            return form_fields
        if self.target is not None and self.target == 'tscs':
            form_fields = grok.AutoFields(ITranscriptApplicant)
            for field in TRANS_SHORT_OMIT_FIELDS:
                form_fields = form_fields.omit(field)
                form_fields = form_fields.omit('locked')
            return form_fields
        self.course_selector = True
        if self.target is not None and self.target.startswith('pg'):
            form_fields = grok.AutoFields(ICustomPGApplicantEdit)
            for field in PG_OMIT_EDIT_FIELDS:
                form_fields = form_fields.omit(field)
        else:
            form_fields = grok.AutoFields(ICustomUGApplicantEdit)
            for field in UG_OMIT_EDIT_FIELDS:
                form_fields = form_fields.omit(field)
        if self.target is not None and self.target == 'pre':
            for field in JUPEB_OMIT_FIELDS:
                form_fields = form_fields.omit(field)
        form_fields['applicant_id'].for_display = True
        form_fields['reg_number'].for_display = True
        return form_fields

class CustomPDFApplicationSlip(NigeriaPDFApplicationSlip):

    @property
    def form_fields(self):
        if self.target is not None and self.target.startswith('pg'):
            form_fields = grok.AutoFields(ICustomPGApplicant)
            for field in PG_OMIT_PDF_FIELDS:
                form_fields = form_fields.omit(field)
        else:
            form_fields = grok.AutoFields(ICustomUGApplicant)
            for field in UG_OMIT_PDF_FIELDS:
                form_fields = form_fields.omit(field)
        if not getattr(self.context, 'student_id'):
            form_fields = form_fields.omit('student_id')
        if not getattr(self.context, 'screening_score'):
            form_fields = form_fields.omit('screening_score')
        if not getattr(self.context, 'screening_venue'):
            form_fields = form_fields.omit('screening_venue')
        if not getattr(self.context, 'screening_date'):
            form_fields = form_fields.omit('screening_date')
        return form_fields

class CustomApplicantRegistrationPage(ApplicantRegistrationPage):
    """Captcha'd registration page for applicants.
    """
    @property
    def form_fields(self):
        form_fields = None
        if self.context.mode == 'update':
            form_fields = grok.AutoFields(ICustomApplicantRegisterUpdate).select(
                'lastname','reg_number','email')
        else: #if self.context.mode == 'create':
            form_fields = grok.AutoFields(ICustomUGApplicant).select(
                'firstname', 'middlename', 'lastname', 'email', 'phone')
        return form_fields

class CustomApplicantAddFormPage(ApplicantAddFormPage):
    """Add-form to add an applicant.
    """
    form_fields = grok.AutoFields(ICustomApplicant).select(
        'firstname', 'middlename', 'lastname',
        'email', 'phone')

class RefereeReportAddFormPage(RefereeReportAddFormPage):
    """Add-form to add an referee report. This form
    is protected by a mandate.
    """
    form_fields = grok.AutoFields(
        ICustomApplicantRefereeReport).omit('creation_date')

class CustomRefereeReportDisplayFormPage(RefereeReportDisplayFormPage):
    """A display view for referee reports.
    """
    form_fields = grok.AutoFields(ICustomApplicantRefereeReport)
    form_fields[
        'creation_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')


class CustomExportPDFReportSlipPage(ExportPDFReportSlipPage):
    form_fields = grok.AutoFields(ICustomApplicantRefereeReport)
    form_fields[
        'creation_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')

class CustomExportPDFReportSlipPage2(ExportPDFReportSlipPage2):
    form_fields = grok.AutoFields(ICustomApplicantRefereeReport)
    form_fields[
        'creation_date'].custom_widget = FriendlyDatetimeDisplayWidget('le')

class ResultStatement(AdditionalFile):
    grok.name('res_stat')

class JAMBResult(AdditionalFile):
    grok.name('jamb')

class FirstSitting(AdditionalFile):
    grok.name('fst_sit_scan')

class SecondSitting(AdditionalFile):
    grok.name('scd_sit_scan')

class HighQual(AdditionalFile):
    grok.name('hq_scan')

class AdvancedLevelResult(AdditionalFile):
    grok.name('alr_scan')

class NYSCCertificate(AdditionalFile):
    grok.name('nysc')

class PaymentReceipts(AdditionalFile):
    grok.name('rmp')
