## $Id: export.py 8971 2012-07-10 21:51:28Z 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 zope.catalog.interfaces import ICatalog
from zope.component import queryUtility
from waeup.kofa.interfaces import MessageFactory as _
from waeup.kofa.students.interfaces import (
    IStudent, IStudentStudyCourse, IStudentStudyLevel, ICourseTicket,
    IStudentOnlinePayment, ICSVStudentExporter)
from waeup.kofa.utils.batching import ExporterBase
from waeup.kofa.utils.helpers import iface_names

#: A tuple containing all exporter names referring to students or
#: subobjects thereof.
EXPORTER_NAMES = ('students', 'studentstudycourses', 'studentstudylevels',
                  'coursetickets', 'studentpayments')

def get_students(site):
    """Get all students registered in catalog in `site`.
    """
    catalog = queryUtility(
        ICatalog, context=site, name='students_catalog', default=None)
    if catalog is None:
        return []
    students = catalog.searchResults(student_id=(None, None))
    return students

def get_studycourses(students):
    """Get studycourses of `students`.
    """
    return [x.get('studycourse', None) for x in students
            if x is not None]

def get_levels(students):
    """Get all studylevels of `students`.
    """
    levels = []
    for course in get_studycourses(students):
        for level in course.values():
            levels.append(level)
    return levels

def get_tickets(students):
    """Get all course tickets of `students`.
    """
    tickets = []
    for level in get_levels(students):
        for ticket in level.values():
            tickets.append(ticket)
    return tickets

def get_payments(students):
    """Get all payments of `students`.
    """
    payments = []
    for student in students:
        for payment in student.get('payments', {}).values():
            payments.append(payment)
    return payments


class StudentExporterBase(ExporterBase):
    """Exporter for students or related objects.

    This is a baseclass.
    """
    grok.baseclass()
    grok.implements(ICSVStudentExporter)
    grok.provides(ICSVStudentExporter)

    def export(self, values, filepath=None):
        """Export `values`, an iterable, as CSV file.

        If `filepath` is ``None``, a raw string with CSV data is returned.
        """
        writer, outfile = self.get_csv_writer(filepath)
        for value in values:
            self.write_item(value, writer)
        return self.close_outfile(filepath, outfile)


class StudentsExporter(grok.GlobalUtility, StudentExporterBase):
    """Exporter for Students.
    """
    grok.name('students')

    #: Fieldnames considered by this exporter
    fields = tuple(sorted(iface_names(
        IStudent, omit=['loggerInfo']))) + (
        'password', 'state', 'history', 'certcode')

    #: The title under which this exporter will be displayed
    title = _(u'Students')

    def mangle_value(self, value, name, context=None):
        if name == 'history':
            value = value.messages
        if name == 'phone' and value is not None:
            # Append hash '#' to phone numbers to circumvent
            # unwanted excel automatic
            value = str('%s#' % value)
        return super(
            StudentsExporter, self).mangle_value(
            value, name, context=context)

    def export_all(self, site, filepath=None):
        """Export students into filepath as CSV data.

        If `filepath` is ``None``, a raw string with CSV data is returned.
        """
        return self.export(get_students(site), filepath)

    def export_student(self, student, filepath=None):
        return self.export([student], filepath=filepath)


class StudentStudyCourseExporter(grok.GlobalUtility, StudentExporterBase):
    """Exporter for StudentStudyCourses.
    """
    grok.name('studentstudycourses')

    #: Fieldnames considered by this exporter
    fields = tuple(sorted(iface_names(IStudentStudyCourse))) + ('student_id',)

    #: The title under which this exporter will be displayed
    title = _(u'Student Study Courses')

    def mangle_value(self, value, name, context=None):
        """Treat location values special.
        """
        if name == 'certificate' and value is not None:
            # XXX: hopefully cert codes are unique site-wide
            value = value.code
        if name == 'student_id' and context is not None:
            student = context.student
            value = getattr(student, name, None)
        return super(
            StudentStudyCourseExporter, self).mangle_value(
            value, name, context=context)

    def export_all(self, site, filepath=None):
        """Export study courses into filepath as CSV data.

        If `filepath` is ``None``, a raw string with CSV data is returned.
        """
        return self.export(get_studycourses(get_students(site)), filepath)

    def export_student(self, student, filepath=None):
        """Export studycourse of a single student object.
        """
        return self.export(get_studycourses([student]), filepath)


class StudentStudyLevelExporter(grok.GlobalUtility, StudentExporterBase):
    """Exporter for StudentStudyLevels.
    """
    grok.name('studentstudylevels')

    #: Fieldnames considered by this exporter
    fields = tuple(sorted(iface_names(
        IStudentStudyLevel) + ['level'])) + ('student_id',)

    #: The title under which this exporter will be displayed
    title = _(u'Student Study Levels')

    def mangle_value(self, value, name, context=None):
        """Treat location values special.
        """
        if name == 'student_id' and context is not None:
            student = context.student
            value = getattr(student, name, None)
        return super(
            StudentStudyLevelExporter, self).mangle_value(
            value, name, context=context)

    def export_all(self, site, filepath=None):
        """Export study levels into filepath as CSV data.

        If `filepath` is ``None``, a raw string with CSV data is returned.
        """
        return self.export(get_levels(get_students(site)), filepath)

    def export_student(self, student, filepath=None):
        return self.export(get_levels([student]), filepath)

class CourseTicketExporter(grok.GlobalUtility, StudentExporterBase):
    """Exporter for CourseTickets.
    """
    grok.name('coursetickets')

    #: Fieldnames considered by this exporter
    fields = tuple(sorted(iface_names(ICourseTicket) +
        ['level', 'code', 'title', 'credits',
        'passmark', 'semester', 'fcode', 'dcode'])) + ('student_id',)

    #: The title under which this exporter will be displayed
    title = _(u'Course Tickets')

    def mangle_value(self, value, name, context=None):
        """Treat location values special.
        """
        if context is not None:
            student = context.student
            if name == 'student_id' and student is not None:
                value = getattr(student, name, None)
            if name == 'level':
                value = getattr(context, 'getLevel', lambda: None)()
        return super(
            CourseTicketExporter, self).mangle_value(
            value, name, context=context)

    def export_all(self, site, filepath=None):
        """Export course tickets into filepath as CSV data.

        If `filepath` is ``None``, a raw string with CSV data is returned.
        """
        return self.export(get_tickets(get_students(site)), filepath)

    def export_student(self, student, filepath=None):
        return self.export(get_tickets([student]), filepath)


class PaymentsExporter(grok.GlobalUtility, StudentExporterBase):
    """Exporter for OnlinePayment instances.
    """
    grok.name('studentpayments')

    #: Fieldnames considered by this exporter
    fields = tuple(
        sorted(iface_names(
            IStudentOnlinePayment, exclude_attribs=False))) + ('student_id',)

    #: The title under which this exporter will be displayed
    title = _(u'Student Payments')

    def mangle_value(self, value, name, context=None):
        """Treat location values special.
        """
        if context is not None:
            student = context.student
            if name in ['student_id'] and student is not None:
                value = getattr(student, name, None)
        return super(
            PaymentsExporter, self).mangle_value(
            value, name, context=context)

    def export_all(self, site, filepath=None):
        """Export payments into filepath as CSV data.

        If `filepath` is ``None``, a raw string with CSV data is returned.
        """
        return self.export(get_payments(get_students(site)), filepath)

    def export_student(self, student, filepath=None):
        return self.export(get_payments([student]), filepath)
