## $Id: export.py 16916 2022-04-09 19:33:01Z 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
##
"""Exporters for student related stuff.
"""
import grok
from copy import deepcopy
from zope.component import getUtility, createObject
from waeup.kofa.utils.batching import ExporterBase
from waeup.kofa.utils.helpers import iface_names
from waeup.kofa.interfaces import IKofaUtils
from waeup.kofa.students.export import (get_levels,
    DataForLecturerExporter, StudentExporterBase,
    SchoolFeePaymentsOverviewExporter, StudentExporter)
from waeup.aaue.students.interfaces import (
    ICustomStudent, ICustomStudentStudyCourse,
    ICustomStudentStudyLevel,
    ICustomCourseTicket,
    ICustomStudentOnlinePayment)
from kofacustom.nigeria.students.export import (
    NigeriaStudentExporter, NigeriaStudentStudyCourseExporter,
    NigeriaStudentStudyLevelExporter,
    NigeriaCourseTicketExporter, NigeriaStudentPaymentExporter)


def get_tickets_for_ict(students, previous=0, **kw):
    """
    """
    tickets = list()
    #code = kw.get('code', None)
    level = kw.get('level', None)
    session = kw.get('session', None)
    ct_level = kw.get('ct_level', None)
    ct_session = kw.get('ct_session', None)
    ct_semester = kw.get('ct_semester', None)
    for level_obj in get_levels(students, previous, **kw):
        allticketcodes = list()
        for ticket in level_obj.values():
            if ct_level not in ('all', None):
                if level_obj.level in (10, 999, 1000, None)  \
                    and int(ct_level) != level_obj.level:
                    continue
                if level_obj.level not in range(
                    int(ct_level), int(ct_level)+100, 10):
                    continue
            if ct_session not in ('all', None) and \
                int(ct_session) != level_obj.level_session:
                continue
            if ct_semester not in ('all', None) and \
                int(ct_semester) != ticket.semester:
                continue
            if ticket.total_score is not None:
                if ticket.total_score < ticket.passmark:
                    remark = 'failed'
                else:
                    remark = 'passed'
            else:
                remark = 'nottaken'
            ticket.remark = remark
            ticket.stdnt = level_obj.student
            tickets.append(ticket)
            allticketcodes.append(ticket.code)
        # collect missed tickets for each study level
        certificate = getattr(
            level_obj.student.get('studycourse', None), 'certificate', None)
        if certificate:
            for certcourse in certificate.values():
                if certcourse.level != level_obj.level:
                    continue
                if certcourse.getCourseCode() not in allticketcodes:
                    ticket = createObject(u'waeup.CourseTicket')
                    ticket.code = certcourse.getCourseCode()
                    ticket.remark = 'missed'
                    ticket.course_category = certcourse.course_category
                    ticket.stdnt = level_obj.student
                    tickets.append(ticket)
    # Remove failed or missed tickets if they have been passed later
    obsolete = list()
    for student in students:
        all_tickets = [i for i in tickets if student == i.stdnt]
        passed_tickets = [i for i in all_tickets if i.remark == 'passed']
        for passed_ticket in passed_tickets:
            for ticket in all_tickets:
                 if ticket.code == passed_ticket.code: # remove passed ticket too
                    obsolete.append(ticket)
    for ticket in set(obsolete):
        tickets.remove(ticket)
    return tickets

class CustomStudentExporter(NigeriaStudentExporter):
    """Exporter for Students.
    """

    fields = tuple(sorted(iface_names(
        ICustomStudent, omit=['loggerInfo']))) + (
        'password', 'state', 'history', 'certcode', 'is_postgrad',
        'current_level', 'current_session')

class CustomStudentStudyCourseExporter(NigeriaStudentStudyCourseExporter):
    """Exporter for StudentStudyCourses.
    """

    fields = tuple(
        sorted(iface_names(ICustomStudentStudyCourse))) + (
            'matric_number', 'state', 'student_id',)

    def mangle_value(self, value, name, context=None):
        if name == 'certificate' and value is not None:
            # XXX: hopefully cert codes are unique site-wide
            value = value.code
        if name in ('student_id', 'matric_number', 'state') and context is not None:
            student = context.student
            value = getattr(student, name, None)
        return ExporterBase().mangle_value(value, name, context=context)

class CustomCourseTicketExporter(NigeriaCourseTicketExporter):
    """Exporter for CourseTickets.
    """

    fields = tuple(sorted(iface_names(ICustomCourseTicket) +
        ['level', 'code', 'level_session'])) + ('student_id',
        'certcode', 'display_fullname', 'matric_number', 'state', 'grade',
        'total_score', 'total_credits', 'previous')

    def mangle_value(self, value, name, context=None):
        """The mangler determines the student's id and fullname.
        """
        if name == 'previous':
            return self.previous
        if context is not None:
            student = context.student
            if name in ('student_id', 'display_fullname', 'matric_number', 'state') \
                and student is not None:
                value = getattr(student, name, None)
            if name == 'total_credits':
                value = context.__parent__.total_credits
        return ExporterBase().mangle_value(value, name, context=context)

class CustomStudentStudyLevelExporter(NigeriaStudentStudyLevelExporter):
    """Exporter for StudentStudyLevels.
    """
    #: Fieldnames considered by this exporter
    fields = tuple(sorted(iface_names(
        ICustomStudentStudyLevel))) + (
        'student_id', 'matric_number', 'number_of_tickets','certcode', 'cgpa')

    def mangle_value(self, value, name, context=None):
        """The mangler determines the student id, nothing else.
        """
        if name in ('student_id', 'matric_number') and context is not None:
            student = context.student
            value = getattr(student, name, None)
        elif name == 'cgpa':
            value = context.cumulative_params[0]
        return super(
            CustomStudentStudyLevelExporter, self).mangle_value(
            value, name, context=context)

class CustomStudentPaymentExporter(NigeriaStudentPaymentExporter):
    """Exporter for OnlinePayment instances.
    """

    fields = tuple(
        sorted(iface_names(
            ICustomStudentOnlinePayment, exclude_attribs=False,
            omit=['display_item','formatted_p_date']))) + (
            'student_id','state','current_session')

class CustomDataForLecturerExporter(DataForLecturerExporter):
    """
    """

    fields = ('matric_number', 'student_id','display_fullname',
              'depcode', 'faccode',
              'level', 'code', 'level_session', 'ca', 'score',
              'total_score', 'grade', 'imported_ts')

    def mangle_value(self, value, name, context=None):
        """The mangler determines the student's id and fullname.
        """
        if context is not None:
            student = context.student
            if name in ('matric_number',
                        'reg_number',
                        'student_id',
                        'display_fullname',
                        'depcode',
                        'faccode') and student is not None:
                value = getattr(student, name, None)
        return super(
            DataForLecturerExporter, self).mangle_value(
            value, name, context=context)

class LevelReportDataExporter(grok.GlobalUtility, StudentExporterBase):
    """
    """
    grok.name('levelreportdata')

    fields = ('matric_number', 'display_fullname','level','level_session',
        'credits_counted', 'credits_passed','level_gpa',
        'failed_courses','not_taken_courses','cum_credits_taken',
        'cum_credits_passed','cgpa','remark')
    title = u'Summary of Result Data'

    def filter_func(self, x, **kw):
        return get_levels(x, **kw)

    def mangle_value(self, value, name, context=None):
        """The mangler determines the student id, nothing else.
        """
        if context is not None:
            student = context.student
            format_float = getUtility(IKofaUtils).format_float
            if name in ('matric_number',
                        'display_fullname',) and student is not None:
                value = getattr(student, name, None)
            elif name == 'credits_counted':
                value = context.gpa_params[1]
            elif name == 'credits_passed':
                value = context.passed_params[2]
            elif name == 'level_gpa':
                value = format_float(context.gpa_params[0], 3)
            elif name == 'failed_courses':
                value = context.passed_params[4]
            elif name == 'not_taken_courses':
                value = context.passed_params[5]
            elif name == 'cum_credits_taken':
                value = context.cumulative_params[1]
            elif name == 'cum_credits_passed':
                value = context.cumulative_params[4]
            elif name == 'cgpa':
                value = format_float(context.cumulative_params[0], 3)
            elif name == 'remark':
                value = getattr(context, 'remark', '')
        return super(
            LevelReportDataExporter, self).mangle_value(
            value, name, context=context)

class CustomSchoolFeePaymentsOverviewExporter(SchoolFeePaymentsOverviewExporter):
    """
    """

    def mangle_value(self, value, name, context=None):
        """
        """
        if name in self.year_range_tuple and context is not None:
            value = 0
            for ticket in context['payments'].values():
                if ticket.p_category in (
                    'schoolfee',
                    'schoolfee_1',
                    'schoolfee_2',
                    'schoolfee_incl',) and \
                    ticket.p_session == int(name):
                    if ticket.p_state == 'waived':
                        value = 'waived'
                        break
                    if ticket.p_state == 'paid':
                        try:
                            value += ticket.amount_auth
                        except TypeError:
                            pass
            if value == 0:
                value = ''
            elif isinstance(value, float):
                value = round(value, 2)
        return super(
            StudentExporter, self).mangle_value(
            value, name, context=context)

class OutstandingCourses2Exporter(grok.GlobalUtility, StudentExporterBase):
    """
    """
    grok.name('outstandingcourses_2')

    title = u'Outstanding Courses V2'

    fields = ('student_id', 'matric_number', 'certcode', 'display_fullname',
              'code', 'course_category', 'remark')

    def filter_func(self, x, **kw):
        return get_tickets_for_ict(x, **kw)

    def mangle_value(self, value, name, context=None):
        """The mangler determines the student's id and fullname.
        """
        if context is not None:
            student = context.student
            if not student:
                student = getattr(context, 'stdnt', None)
            if name in ('student_id', 'display_fullname', 'matric_number',
                'certcode') and student is not None:
                value = getattr(student, name, None)
        return ExporterBase().mangle_value(value, name, context=context)
