#
# SchoolTool - common information systems platform for school administration
# Copyright (c) 2005 Shuttleworth Foundation
#
# 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, see <http://www.gnu.org/licenses/>.
#
"""
Student Intervention browser views.
"""
import csv
from StringIO import StringIO
import tempfile
import urllib
import zipfile

from zope.app.form.browser.editview import EditView
from zope.browserpage.viewpagetemplatefile import ViewPageTemplateFile
from zope.catalog.interfaces import ICatalog
from zope.component import getUtility, getMultiAdapter, queryUtility
from zope.container.interfaces import INameChooser
from zope.intid.interfaces import IIntIds
from zope.publisher.browser import BrowserView
from zope.schema import Bool, Date
from zope.security.checker import canWrite
from zope.security.proxy import removeSecurityProxy
from zope.security import checkPermission
from zope.traversing.api import getParents
from zope.traversing.browser.absoluteurl import absoluteURL
from zope.i18n import translate

from zc.table.column import GetterColumn

from z3c.form import field, button
import z3c.form.interfaces
from z3c.form import form as z3cform

from schooltool.app.interfaces import ISchoolToolApplication
from schooltool.app.browser import app
from schooltool.app.membership import URIGroup, URIMembership
from schooltool.intervention import InterventionGettext as _
from schooltool.common import format_message
from schooltool.common.inlinept import InheritTemplate
from schooltool.common.inlinept import InlineViewPageTemplate
from schooltool.contact.interfaces import IContact
from schooltool.course.interfaces import ISection, IInstructor
from schooltool.email.interfaces import IEmailUtility, IEmailContainer
from schooltool.email.mail import status_messages
from schooltool.intervention.catalog import getStudentFirstName, getStudentLastName
from schooltool.intervention import intervention, sendmail
from schooltool.intervention import interfaces
from schooltool.person.interfaces import IPerson
from schooltool.relationship import getRelatedObjects
from schooltool.report.browser.report import RequestReportDownloadDialog
from schooltool.schoolyear.interfaces import ISchoolYear
from schooltool.schoolyear.interfaces import ISchoolYearContainer
from schooltool.securitypolicy.crowds import AdministrationCrowd
from schooltool.skin.skin import NavigationViewlet
from schooltool.skin import flourish
from schooltool.skin.flourish.viewlet import ViewletManager
from schooltool.table.catalog import IndexedTableFormatter, FilterWidget
from schooltool.table.catalog import IndexedGetterColumn
from schooltool.table.catalog import IndexedLocaleAwareGetterColumn
from schooltool.table.table import SchoolToolTableFormatter
from schooltool.table.interfaces import ITableFormatter
from schooltool.term.interfaces import ITerm, IDateManager


class InterventionNavigationViewlet(NavigationViewlet):
    """View class for rendering the Intervention tab."""

    def canRender(self):
        person = IPerson(self.request.principal, None)
        return person is not None

    def url(self):
        person = IPerson(self.request.principal)
        return absoluteURL(person, self.request) + '/intervention_tab'


class FlourishInterventionNavViewlet(flourish.page.LinkViewlet):

    @property
    def person(self):
        return IPerson(self.request.principal, None)

    @property
    def enabled(self):
        person = self.person
        if person is None or queryUtility(IDateManager).current_term is None:
            return False
        return True

    @property
    def url(self):
        person = self.person
        if person is None:
            return ''
        return absoluteURL(person, self.request) + '/intervention_tab'


class StudentTableFormatter(SchoolToolTableFormatter):
    """View class for rendering the student table."""

    def columns(self):
        first_name = GetterColumn(
            name='first_name',
            title=_(u'First Name'),
            getter=lambda i, f: i.first_name,
            cell_formatter=self.cell_formatter,
            subsort=True)
        last_name = GetterColumn(
            name='last_name',
            title=_(u'Last Name'),
            getter=lambda i, f: i.last_name,
            cell_formatter=self.cell_formatter,
            subsort=True)
        return [first_name, last_name]

    def items(self):
        if AdministrationCrowd(None).contains(self.request.principal):
            persons = ISchoolToolApplication(None)['persons']
            return list(persons.values())

        students = set()
        person = IPerson(self.request.principal, None)
        for section in IInstructor(person).sections():
            for student in section.members:
                students.add(student)
        for student in person.advisees:
            students.add(student)
        return list(students)

    def sortOn(self):
        return (("last_name", False),)

    def cell_formatter(self, value, item, formatter):
        app = ISchoolToolApplication(None)
        container = interfaces.IInterventionSchoolYear(app)
        url = absoluteURL(container, formatter.request)
        if item.username not in container:
            # need to auto-vivyfy because we give the user a link to it
            getMultiAdapter((item, ISchoolYear(container)),
                interfaces.IInterventionStudent)
        return '<a href="%s/%s">%s</a>' % (url, item.username, value)


class StudentFilterWidget(FilterWidget):
    """View class for rendering the student filter widget."""

    template = ViewPageTemplateFile('templates/student_filter.pt')
    parameters = ['SEARCH_STUDENT_NAME', 'WITH_GOALS_ONLY']

    def filter(self, items):
        username = IPerson(self.request.principal).username

        if 'CLEAR_STUDENT_SEARCH' in self.request:
            for parameter in self.parameters:
                self.request.form[parameter] = ''
            return items

        if 'SEARCH_STUDENT_NAME' in self.request:
            searchstr = self.request['SEARCH_STUDENT_NAME'].lower()
            new_items = []
            for item in items:
                targetstr = '%s %s' % (item.first_name.lower(),
                    item.last_name.lower())
                if searchstr in targetstr:
                    new_items.append(item)
                else:
                    targetstr = item.username.lower()
                    if searchstr in targetstr:
                        new_items.append(item)
            items = new_items

        if self.request.get('WITH_GOALS_ONLY'):
            app = ISchoolToolApplication(None)
            year = interfaces.IInterventionSchoolYear(app)
            new_items = []
            for item in items:
                username = item.username
                if username in year and len(year[username]['goals']):
                    new_items.append(item)
            items = new_items

        return items


class FlourishStudentFilterWidget(StudentFilterWidget):
    """Flourish view class for rendering the student filter widget."""

    template = ViewPageTemplateFile('templates/f_student_filter.pt')


class InterventionTableFormatter(IndexedTableFormatter):
    """View class for rendering the intervention table."""

    def columns(self):
        first_name = IndexedLocaleAwareGetterColumn(
            index='first_name',
            name='first_name',
            title=_(u'First Name'),
            getter=lambda i, f: getStudentFirstName(i),
            subsort=True)
        last_name = IndexedLocaleAwareGetterColumn(
            index='last_name',
            name='last_name',
            title=_(u'Last Name'),
            getter=lambda i, f: getStudentLastName(i),
            subsort=True)
        inter_type = GetterColumn(
            name='intervention_type',
            title='',
            getter=self.intervention_type_getter)
        inter = GetterColumn(
            name='intervention',
            title=_(u"Intervention"),
            cell_formatter=self.intervention_cell_formatter,
            getter=interfaces.IInterventionGetter)
        created = IndexedGetterColumn(
            index='created',
            name='created',
            cell_formatter=self.created_cell_formatter,
            title=_(u'Created'),
            getter=lambda i, f: i.created,
            subsort=True)
        return [first_name, last_name, inter_type, inter, created]

    def sortOn(self):
        return (("created", True),)

    def intervention_type_getter(self, item, formatter):
        if interfaces.IInterventionType(item) == 'message':
            return translate(_('Msg:'), context=formatter.request)
        else:
            return translate(_('Goal:'), context=formatter.request)

    def intervention_cell_formatter(self, value, item, formatter):
        url = absoluteURL(IPerson(item), formatter.request)
        year = interfaces.IInterventionSchoolYear(item)
        url += '/schoolyears/%s/%ss/%s' % (year.__name__,
                                           interfaces.IInterventionType(item),
                                           item.__name__)
        url += '?nexturl=%s' % self.request.getURL()
        return '<a href="%s">%s</a>' % (url, value)

    def created_cell_formatter(self, value, item, formatter):
        return '<span>%s</span>' % value.strftime('%x')


class InterventionFilterWidget(FilterWidget):
    """View class for rendering the intervention filter widget."""

    template = ViewPageTemplateFile('templates/filter.pt')
    parameters = ['SEARCH_NAME', 'GOALS_ONLY']

    def filter(self, items):
        catalog = ICatalog(self.context)
        user_contact = IContact(IPerson(self.request.principal))
        contact_intid = getUtility(IIntIds).getId(user_contact)
        pr_idx = catalog['persons_responsible']
        items = [item for item in items
                 if contact_intid in pr_idx.documents_to_values[item['id']]]

        if 'CLEAR_SEARCH' in self.request:
            for parameter in self.parameters:
                self.request.form[parameter] = ''
            return items

        if 'SEARCH_NAME' in self.request:
            fn_idx = catalog['first_name']
            ln_idx = catalog['last_name']
            searchstr = self.request['SEARCH_NAME'].lower()
            new_items = []
            for item in items:
                targetstr = '%s %s' % (
                    fn_idx.documents_to_values[item['id']].lower(),
                    ln_idx.documents_to_values[item['id']].lower())
                if searchstr in targetstr:
                    new_items.append(item)
            items = new_items

        if self.request.get('GOALS_ONLY'):
            type_idx = catalog['intervention_type']
            items = [item for item in items
                     if type_idx.documents_to_values[item['id']] == 'goal']

        return items


class FlourishInterventionFilterWidget(InterventionFilterWidget):
    """Flourish view class for rendering the intervention filter widget."""

    template = ViewPageTemplateFile('templates/f_filter.pt')

    @property
    def show_goals(self):
        if 'form-submitted' in self.request:
            return self.request.get('SHOW_GOALS')
        else:
            return 'checked'

    @property
    def show_messages(self):
        if 'form-submitted' in self.request:
            return self.request.get('SHOW_MESSAGES')
        else:
            return 'checked'

    def filter(self, items):
        catalog = ICatalog(self.context)
        user_contact = IContact(IPerson(self.request.principal))
        contact_intid = getUtility(IIntIds).getId(user_contact)
        pr_idx = catalog['persons_responsible']
        items = [item for item in items
                 if contact_intid in pr_idx.documents_to_values[item['id']]]

        if self.request.get('SEARCH_NAME'):
            fn_idx = catalog['first_name']
            ln_idx = catalog['last_name']
            searchstr = self.request['SEARCH_NAME'].lower()
            new_items = []
            for item in items:
                targetstr = '%s %s' % (
                    fn_idx.documents_to_values[item['id']].lower(),
                    ln_idx.documents_to_values[item['id']].lower())
                if searchstr in targetstr:
                    new_items.append(item)
            items = new_items

        if self.show_messages and self.show_goals:
            return items
        elif self.show_goals:
            compare = 'goal'
        elif self.show_messages:
            compare = 'message'
        else:
            return []

        type_idx = catalog['intervention_type']
        items = [item for item in items
                 if type_idx.documents_to_values[item['id']] == compare]

        return items


class InterventionStartupView(BrowserView):
    """Dashboard view containing the user's intreventions."""

    title = _("Intervention")
    student_title = _("Search Students")
    inbox_title = _("Inbox")

    def __call__(self):
        if queryUtility(IDateManager).current_term is None:
            template = ViewPageTemplateFile('templates/no_current_term.pt')
            return template(self)
        else:
            return super(InterventionStartupView, self).__call__()

    def createInterventionTableFormatter(self, **kwargs):
        container = ISchoolToolApplication(None)['schooltool.interventions']
        formatter = getMultiAdapter((container, self.request),
                                    ITableFormatter)
        formatter.setUp(**kwargs)
        return formatter

    def setUpTables(self):
        self.available_table = self.createInterventionTableFormatter(
            prefix="intervention", batch_size=40)

    def update(self):
        self.setUpTables()


class FlourishInterventionStartupView(InterventionStartupView,
                                      flourish.page.Page):
    """Flourish Dashboard view containing the user's intreventions."""

    @property
    def no_data(self):
        return not self.available_table.filter(self.available_table.items())


class FlourishInterventionStartupLinks(flourish.page.RefineLinksViewlet):
    """flourish Intervention Dashboard search links viewlet."""


class InterventionStudentsView(BrowserView):
    """View to search for the user's student interventions."""

    title = _("Search Students")
    student_title = _("Students")

    def __call__(self):
        if queryUtility(IDateManager).current_term is None:
            template = ViewPageTemplateFile('templates/no_current_term.pt')
            return template(self)
        else:
            return super(InterventionStudentsView, self).__call__()

    def inboxURL(self):
        return absoluteURL(self.context, self.request)

    def createStudentTableFormatter(self, **kwargs):
        app = ISchoolToolApplication(None)
        container = interfaces.IInterventionSchoolYear(app)
        formatter = getMultiAdapter((container, self.request),
                                    ITableFormatter)
        formatter.setUp(**kwargs)
        return formatter

    def setUpTables(self):
        self.student_table = self.createStudentTableFormatter(
            prefix="student", batch_size=40)

    def update(self):
        self.setUpTables()


class FlourishInterventionStudentsView(InterventionStudentsView,
                                       flourish.page.Page):
    """Flourish view to search for the user's student intreventions."""


class InterventionStudentRedirectView(BrowserView):
    """View for redirecting to the no current term view."""

    def __call__(self):
        template = ViewPageTemplateFile('templates/no_current_term.pt')
        return template(self)


class InterventionStudentView(object):
    """View for managing a student's intervention."""

    @property
    def currentSchoolYear(self):
        return ISchoolYear(self.context.__parent__).title

    @property
    def isCurrentSchoolYear(self):
        app = ISchoolToolApplication(None)
        interventionSchoolYear = interfaces.IInterventionSchoolYear(app)
        return interventionSchoolYear == self.context.__parent__

    @property
    def schoolyears(self):
        results = []
        student = IPerson(self.context)
        app = ISchoolToolApplication(None)
        for year in ISchoolYearContainer(app).values():
            interventionSchoolYear = interfaces.IInterventionSchoolYear(year)
            interventionStudent = getMultiAdapter((student, year),
                interfaces.IInterventionStudent)

            result = {
                'url': absoluteURL(interventionStudent, self.request),
                'title': year.title,
                }
            results.append(result)
        return results

    def learnerOf(self):
        """Get the sections the student is a member of."""
        results = []

        for item in IPerson(self.context).groups:
            if ISection.providedBy(item):
                results.append(item)
            else:
                group_sections = getRelatedObjects(item, URIGroup,
                                                   rel_type=URIMembership)
                for section in group_sections:
                    results.append(section)
        results.sort(key=lambda s: s.__name__)
        return results

    def update(self):
        if 'schoolyear' in self.request:
            title = self.request['schoolyear']
            if title != self.currentSchoolYear:
                for year in self.schoolyears:
                    if year['title'] == title:
                        self.request.response.redirect(year['url'])

        interventionURL = absoluteURL(self.context, self.request)
        student = IPerson(self.context)

        self.studentURL = absoluteURL(student, self.request)
        self.studentName = '%s %s' % (IContact(student).first_name,
                                      IContact(student).last_name)

        self.messages = []
        for k, v in sorted(self.context['messages'].items()):
            if v.status_change:
                continue
            name = ', '.join(intervention.contactsName(v.sender))
            added = v.created
            message = {
                'creation_date': added,
                'url': absoluteURL(v, self.request),
                'text': _('Message from ${sender} sent ${date}',
                          mapping={'sender': name,
                                   'date': added.strftime('%x')})
                }
            self.messages.append(message)
        self.messages.sort(key=lambda m: m['creation_date'], reverse=True)
        self.newMessageURL = interventionURL + '/messages/+/addMessage.html'
        self.allMessagesURL = interventionURL + '/messages/allMessages.html'

        self.goals = []
        for k, v in sorted(self.context['goals'].items()):
            added = v.created.strftime('%x')
            due = v.timeline.strftime('%x')
            if v.goal_met:
                status = _('CLOSED')
            else:
                status = _('OPEN')
            goal = {
                'url': absoluteURL(v, self.request),
                'text': _('Goal ${goal_name} - Added ${date_added} - '
                          'Due ${date_due} - ${status}',
                          mapping={'goal_name': k,
                                   'date_added': added,
                                   'date_due': due,
                                   'status': status})
                }
            self.goals.append(goal)
        self.newGoalURL = interventionURL + '/goals/+/addGoal.html'
        self.allGoalsURL = interventionURL + '/goals/allGoals.html'

        studentId = IPerson(self.context).username
        currentYear = ISchoolYear(self.context.__parent__)
        terms = {}
        for section in self.learnerOf():
            if not canWrite(section, 'title'):
                continue
            if ISchoolYear(ITerm(section)) != currentYear:
                continue
            sheets = terms.setdefault(ITerm(section), [])
            activities = interfaces.IIndependentActivities(section, None)
            if activities is None:
                continue
            for worksheet in activities.values():
                if not worksheet.deployed:
                    continue
                course_title = ', '.join([course.title for course in
                                            section.courses])
                title = _('${worksheet_title} for ${course_title} - '
                          '${section_title}',
                          mapping={'worksheet_title': worksheet.title,
                                   'course_title': course_title,
                                   'section_title': section.title})
                worksheet_url = absoluteURL(worksheet, self.request)
                sheet = {
                    'url': '%s/gradebook/%s/view.html' % (worksheet_url,
                        studentId),
                    'text': title
                    }
                sheets.append(sheet)
        self.terms = [{'title': term.title, 'sheets': terms[term]}
                      for term in sorted(terms.keys())]

        self.statusMessages = []
        for k, v in sorted(self.context['messages'].items()):
            if not v.status_change:
                continue
            name = ', '.join(intervention.contactsName(v.sender))
            added = v.created.strftime('%x')
            message = {
                'url': absoluteURL(v, self.request),
                'text': _('Change of Status Message from ${sender} '
                          'sent ${date}',
                          mapping={'sender': name, 'date': added})
                }
            self.statusMessages.append(message)
        self.newStatusMessageURL = interventionURL + '/messages/+/addStatusMessage.html'
        self.allStatusMessagesURL = interventionURL + '/messages/allStatusMessages.html'


class EmailMixin(object):
    """Mixin class for getting messages for modal email sent notification."""

    @property
    def email(self):
        fail_message = _('The email could not be delivered to all recipients.')
        email_info = self.request.get('email')
        if email_info:
            messages = []
            email_container = IEmailContainer(ISchoolToolApplication(None))
            for info in email_info.split('|'):
                if '@' in info:
                    messages.append(translate(
                        format_message(
                            _('An email message was sent to: ${to_addresses}'),
                            mapping={'to_addresses': info}),
                        context=self.request))
                else:
                    messages.append(fail_message)
                    email = email_container.get(info, None)
                    if email is not None:
                        messages.append(translate(
                            format_message(
                                status_messages[email.status_code],
                                mapping=email.status_parameters),
                            context=self.request))
            return messages
        return ''


class FlourishInterventionStudentView(EmailMixin, flourish.page.Page):
    """Flourish View for managing a student's intervention."""

    @property
    def title(self):
        student = IContact(IPerson(self.context))
        return '%s %s' % (student.first_name, student.last_name)

    @property
    def subtitle(self):
        currentYear = ISchoolYear(self.context.__parent__)
        title = _(u'Interventions for ${year}',
                  mapping={'year': currentYear.title})
        return translate(title, context=self.request)

    @property
    def messages(self):
        messages = []
        for k, v in sorted(self.context['messages'].items()):
            messages.append({
                'creation_date': v.created,
                'url': absoluteURL(v, self.request),
                'from': ', '.join(intervention.contactsName(v.sender)),
                'subject': v.subject,
                'sent': v.created.strftime('%x'),
                })
        return sorted(messages, key=lambda m: m['creation_date'], reverse=True)

    @property
    def goals(self):
        goals = []
        for k, v in sorted(self.context['goals'].items()):
            name = v.goal
            if len(name) > 40:
                name = name[:37] + '...'
            goals.append({
                'url': absoluteURL(v, self.request),
                'name': name,
                'added': v.created.strftime('%x'),
                'due': v.timeline.strftime('%x'),
                'status': v.goal_met and _('CLOSED') or _('OPEN'),
                })
        return goals

    @property
    def canModify(self):
        return checkPermission('schooltool.edit', self.context)

    def learnerOf(self):
        """Get the sections the student is a member of."""
        results = []

        for item in IPerson(self.context).groups:
            if ISection.providedBy(item):
                results.append(item)
            else:
                group_sections = getRelatedObjects(item, URIGroup,
                                                   rel_type=URIMembership)
                for section in group_sections:
                    results.append(section)
        results.sort(key=lambda s: s.__name__)
        return results

    @property
    def sheets(self):
        studentId = IPerson(self.context).username
        currentYear = ISchoolYear(self.context.__parent__)
        sheets = []
        for section in self.learnerOf():
            if not canWrite(section, 'title'):
                continue
            term = ITerm(section)
            if ISchoolYear(term) != currentYear:
                continue
            activities = interfaces.IIndependentActivities(section, None)
            if activities is None:
                continue
            for worksheet in activities.values():
                if not worksheet.deployed:
                    continue
                course_title = ', '.join([course.title for course in
                                          section.courses])
                title = _('${worksheet_title} for ${course_title} - '
                          '${section_title}',
                          mapping={'worksheet_title': worksheet.title,
                                   'course_title': course_title,
                                   'section_title': section.title})
                worksheet_url = absoluteURL(worksheet, self.request)
                sheets.append({
                    'url': '%s/gradebook/%s/view.html' % (worksheet_url,
                        studentId),
                    'term': term.title,
                    'section': section.title,
                    'course': course_title,
                    'worksheet': worksheet.title,
                    })
        return sheets

    @property
    def schoolyears(self):
        results = []
        student = IPerson(self.context)
        app = ISchoolToolApplication(None)
        for year in ISchoolYearContainer(app).values():
            interventionSchoolYear = interfaces.IInterventionSchoolYear(year)
            interventionStudent = getMultiAdapter((student, year),
                interfaces.IInterventionStudent)

            result = {
                'url': absoluteURL(interventionStudent, self.request),
                'title': year.title,
                }
            results.append(result)
        return results

    def update(self):
        if 'schoolyear' in self.request:
            title = self.request['schoolyear']
            if title != ISchoolYear(self.context.__parent__).title:
                for year in self.schoolyears:
                    if year['title'] == title:
                        self.request.response.redirect(year['url'])


class FlourishInterventionStudentLinks(flourish.page.RefineLinksViewlet):
    """flourish Intervention Student add links viewlet."""


class InterventionStudentTertiaryNavigationManager(ViewletManager):

    template = InlineViewPageTemplate("""
        <ul tal:attributes="class view/list_class">
          <li tal:repeat="item view/items"
              tal:attributes="class item/class"
              tal:content="structure item/viewlet">
          </li>
        </ul>
    """)

    list_class = 'third-nav'

    @property
    def items(self):
        result = []
        schoolyears = ISchoolYearContainer(ISchoolToolApplication(None))
        active = ISchoolYear(removeSecurityProxy(self.context).__parent__)
        for schoolyear in schoolyears.values():
            url = '%s?schoolyear=%s' % (
                absoluteURL(self.context, self.request),
                schoolyear.__name__)
            result.append({
                'class': schoolyear.first == active.first and 'active' or None,
                'viewlet': u'<a href="%s">%s</a>' % (url, schoolyear.title),
                })
        return result


class FlourishInterventionStudentYearViewlet(flourish.viewlet.Viewlet,
                                             InterventionStudentView):
    template = InlineViewPageTemplate('''
    <form method="post"
          tal:attributes="action string:${context/@@absolute_url}">
      <select name="schoolyear" onchange="this.form.submit()">
        <tal:block repeat="year view/years">
          <option
              tal:attributes="value year/title;
                              selected year/selected"
              tal:content="year/title" />
        </tal:block>
      </select>
    </form>
    ''')

    @property
    def years(self):
        results = []
        student = IPerson(self.context)
        currentYear = removeSecurityProxy(
            interfaces.IInterventionSchoolYear(self.context))
        app = ISchoolToolApplication(None)
        for year in ISchoolYearContainer(app).values():
            interventionSchoolYear = interfaces.IInterventionSchoolYear(year)
            interventionStudent = getMultiAdapter((student, year),
                interfaces.IInterventionStudent)

            result = {
                'title': year.title,
                'selected': (interventionSchoolYear is currentYear and
                            'selected' or None),
                }
            results.append(result)
        return results

    def render(self, *args, **kw):
        return self.template(*args, **kw)


class FlourishRequestInterventionStudentReportView(RequestReportDownloadDialog):

    def nextURL(self):
        return absoluteURL(self.context, self.request) + '/intervention_student.pdf'


class SectionInterventionsView(object):
    """Tabbed section view showing links for adding or editing intervention data."""

    def __init__(self, context, request):
        self.context = context
        self.request = request
        self.heading = '%s - %s %s' % (', '.join([course.title for course in
                                               self.context.courses]),
                                       self.context.title,
                                       _("Interventions"))
        self.schoolyear = interfaces.IInterventionSchoolYear(
            ISchoolYear(self.context))
        activities = interfaces.IIndependentActivities(self.context, None)
        if activities is None:
            self.worksheets = []
        else:
            activities = removeSecurityProxy(activities)
            self.worksheets = [worksheet for worksheet in activities.values()
                               if worksheet.deployed]
        app = ISchoolToolApplication(None)
        self.activeSchoolYear = interfaces.IInterventionSchoolYear(app)

    def messageLinks(self, student):
        newMessageURL = '%s/messages/%s/+/addMessage.html' % (
            absoluteURL(self.context, self.request), student.__name__)
        allMessagesURL = '%s/messages/allMessages.html' % (
            absoluteURL(student, self.request))
        n_messages = len([m for m in student['messages'].values()
                          if not m.status_change])
        result = {
            'title': _('View Messages (${message_count})',
                       mapping={'message_count': n_messages}),
            'url': allMessagesURL,
            }
        results = [result]
        if self.schoolyear == self.activeSchoolYear:
            result = {
                'title': _('Write New'),
                'url': newMessageURL,
                }
            results.append(result)
        return (results)

    def goalLinks(self, student):
        student_url = absoluteURL(student, self.request)
        allGoalsURL = '%s/goals/allGoals.html' % student_url
        n_goals = len(student['goals'])
        return ({'title': _('View Goals (${goal_count})',
                            mapping={'goal_count': n_goals}),
                 'url': allGoalsURL},
                )

    def reportSheetLinks(self, student):
        studentId = student.__name__
        nexturl = absoluteURL(self.context, self.request) + \
            '/@@interventions.html'
        results = []
        for worksheet in self.worksheets:
            worksheet_url = absoluteURL(worksheet, self.request)
            result = {
                'title': worksheet.title,
                'url': '%s/gradebook/%s?nexturl=%s' % (worksheet_url,
                    studentId, nexturl)
                }
            results.append(result)
        return results

    @property
    def tabs(self):
        """Each tab is a tuple of tab_name, (tab_title, tab_link_factory)"""
        results = [
            ('messages', (_('Messages'), self.messageLinks)),
            ('goals', (_('Goals'), self.goalLinks)),
            ]
        if len(self.worksheets):
            result = ('sheets', (_('Report Sheets'), self.reportSheetLinks))
            results.append(result)
        return results


    def getActiveTabName(self):
        default_tab = 'messages'
        if len(self.worksheets):
            default_tab = 'sheets'
        return self.request.get('TAB', default_tab)

    def iterTabs(self):
        url = absoluteURL(self.context, self.request) + '/interventions.html'
        active_tab = self.getActiveTabName()
        for name, tab in self.tabs:
            title, link_factory = tab
            yield {
                'active': name == active_tab,
                'url': '%s?TAB=%s' % (url, name),
                'title': title
                }

    def listStudents(self):
        tab = dict(self.tabs).get(self.getActiveTabName())
        if tab is None:
            link_factory = lambda student: ()
        else:
            tab_title, link_factory = tab

        rows = []
        for student in self.context.members:
            interventionStudent = getMultiAdapter((student,
                ISchoolYear(self.context)), interfaces.IInterventionStudent)
            row = {
                'name': intervention.contactName(IContact(student)),
                'sortName': student.last_name + student.first_name,
                'url': absoluteURL(interventionStudent, self.request),
                'links': link_factory(interventionStudent),
                }
            rows.append(row)

        return sorted(rows, key=lambda row: row['sortName'])


class FlourishSectionInterventionsView(EmailMixin, flourish.page.Page,
                                       SectionInterventionsView):
    """Flourish tabbed section view showing links for adding or editing
       intervention data."""

    def __init__(self, context, request):
        SectionInterventionsView.__init__(self, context, request)

    @property
    def headings(self):
        headings = [_('Student')]
        if self.getActiveTabName() == 'messages':
            headings.append(_('Messages'))
            headings.append(_('Add'))
        elif self.getActiveTabName() == 'goals':
            headings.append(_('Goals'))
        else:
            headings.append(_('Report Sheets'))
        return headings

    def messageLinks(self, student):
        newMessageURL = '%s/messages/%s/addMessage.html' % (
            absoluteURL(self.context, self.request), student.__name__)
        allMessagesURL = '%s/messages/allMessages.html?nexturl=%s' % (
            absoluteURL(student, self.request), self.thisURL())
        n_messages = len([m for m in student['messages'].values()
                          if not m.status_change])
        results = [{
            'title': str(n_messages),
            'url': allMessagesURL,
            }]
        if self.schoolyear == self.activeSchoolYear:
            results.append({
                'title': '',
                'url': newMessageURL,
                })
        return results

    def goalLinks(self, student):
        student_url = absoluteURL(student, self.request)
        allGoalsURL = '%s/goals/allGoals.html?nexturl=%s' % (student_url,
            self.thisURL())
        n_goals = len(student['goals'])
        return [{
            'title': str(n_goals),
            'url': allGoalsURL,
            }]

    def reportSheetLinks(self, student):
        studentId = student.__name__
        results = []
        for worksheet in self.worksheets:
            worksheet_url = absoluteURL(worksheet, self.request)
            results.append({
                'title': worksheet.title,
                'url': '%s/gradebook/%s?nexturl=%s' % (worksheet_url,
                    studentId, self.thisURL())
                })
        return results

    def thisURL(self):
        url = absoluteURL(self.context, self.request)
        return url + '/interventions.html'


class SectionInterventionsTertiaryNavigationManager(
    flourish.page.TertiaryNavigationManager):

    template = InlineViewPageTemplate("""
        <ul tal:attributes="class view/list_class">
          <li tal:repeat="item view/items"
              tal:attributes="class item/class"
              tal:content="structure item/viewlet">
          </li>
        </ul>
    """)

    @property
    def items(self):
        result = []
        url = absoluteURL(self.context, self.request) + '/interventions.html'
        tabs = [
            ('messages', _('Messages')),
            ('goals', _('Goals')),
            ]
        activities = interfaces.IIndependentActivities(self.context, None)
        if activities is None:
            worksheets = []
        else:
            activities = removeSecurityProxy(activities)
            worksheets = [worksheet for worksheet in activities.values()
                          if worksheet.deployed]
        default_tab = 'messages'
        if len(worksheets):
            tabs.append(('sheets', _('Report Sheets')))
            default_tab = 'sheets'
        active_tab = self.request.get('TAB', default_tab)
        for tab, title in tabs:
            result.append({
                'class': tab == active_tab and 'active' or None,
                'viewlet': u'<a href="%s?TAB=%s">%s</a>' % (url, tab,
                           translate(title, context=self.request)),
                })
        return result


class InterventionMessageAddView(app.BaseAddView):
    """View for adding a message."""

    def __init__(self, context, request):
        super(InterventionMessageAddView, self).__init__(context, request)
        self.label = _("PLEASE REMEMBER: This information is part of the student's record.")

    def create(self, *args, **kw):
        self._sender = IContact(self.request.principal._person)
        self._recipients, body = args
        return self._factory(body)

    def add(self, message):
        """Add message to the student's messages."""
        context = self.context.context
        chooser = INameChooser(context)
        name = chooser.chooseName('', message)
        context[name] = message
        if self._sender:
            message.sender.add(self._sender)
        for recipient in self._recipients:
            message.recipients.add(IContact(recipient))
        sendmail.sendInterventionMessageEmail(message)
        return message

    def nextURL(self):
        """If section is in the context heirachcy, return to the section
           interventions view.  Otherwise return to the student's intervention
           center."""
        for parent in getParents(self.context):
            if ISection.providedBy(parent):
                return absoluteURL(parent, self.request) + '/interventions.html'
        interventionStudent = self.context.context.__parent__
        return absoluteURL(interventionStudent, self.request)


class IMessageAddForm(interfaces.IInterventionMessage):

    email = Bool(
        title=_(u"Email"),
        description=_(u"Send an email to the people selected above."),
        required=False,
        default=True)


class FlourishInterventionMessageAddView(flourish.form.AddForm):

    template = InheritTemplate(flourish.page.Page.template)
    label = None
    legend = _('Message Details')

    fields = field.Fields(IMessageAddForm)
    fields = fields.select('recipients', 'subject', 'body', 'email')

    @property
    def title(self):
        student = IContact(IPerson(self.context))
        return '%s %s' % (student.first_name, student.last_name)

    def updateWidgets(self):
        super(FlourishInterventionMessageAddView, self).updateWidgets()
        sender = IContact(self.request.principal._person)
        utility = getUtility(IEmailUtility)
        if not utility.enabled() or not sender.email:
            if False:
                self.widgets['email'].mode = z3c.form.interfaces.HIDDEN_MODE

    @button.buttonAndHandler(_('Submit'), name='add')
    def handleAdd(self, action):
        data, errors = self.extractData()
        if errors:
            self.status = self.formErrorsMessage
            return
        obj = self.createAndAdd(data)
        if obj is not None:
            if data.get('email'):
                email = sendmail.sendInterventionMessageEmail(obj)
                if email.status_code is None:
                    info = ', '.join([urllib.quote(to)
                                      for to in email.to_addresses])
                else:
                    info = email.__name__
                url = '%s?email=%s' % (self.nextURL(), info)
                self.request.response.redirect(url)
            else:
                self._finishedAdd = True

    @button.buttonAndHandler(_("Cancel"))
    def handle_cancel_action(self, action):
        self.request.response.redirect(self.nextURL())

    def updateActions(self):
        super(FlourishInterventionMessageAddView, self).updateActions()
        self.actions['add'].addClass('button-ok')
        self.actions['cancel'].addClass('button-cancel')

    def create(self, data):
        message = intervention.InterventionMessage(data['body'],
                                                   data['subject'])
        self._sender = IContact(self.request.principal._person)
        self._recipients = data['recipients']
        return message

    def add(self, message):
        """Add message to the student's messages."""
        chooser = INameChooser(self.context)
        name = chooser.chooseName('', message)
        self.context[name] = message
        if self._sender:
            message.sender.add(IContact(self._sender))
        for recipient in self._recipients:
            message.recipients.add(IContact(recipient))
        return message

    def nextURL(self):
        """If section is in the context heirachcy, return to the section
           interventions view.  Otherwise return to the student's intervention
           center."""
        for parent in getParents(self.context):
            if ISection.providedBy(parent):
                return absoluteURL(parent, self.request) + '/interventions.html'
        interventionStudent = self.context.__parent__
        return absoluteURL(interventionStudent, self.request)


class InterventionStatusMessageAddView(app.BaseAddView):
    """View for adding a message."""

    def create(self, *args, **kw):
        self._sender = IContact(self.request.principal._person)
        self._recipients, body = args
        status_change = True
        return self._factory(body, status_change=status_change)

    def add(self, message):
        """Add message to the student's messages."""
        context = self.context.context
        chooser = INameChooser(context)
        name = chooser.chooseName('', message)
        context[name] = message
        if self._sender:
            message.sender.add(self._sender)
        for recipient in self._recipients:
            message.recipients.add(IContact(recipient))
        sendmail.sendInterventionMessageEmail(message)
        return message

    def nextURL(self):
        """If section is in the context heirachcy, return to the section
           interventions view.  Otherwise return to the student's intervention
           center."""
        for parent in getParents(self.context):
            if ISection.providedBy(parent):
                return absoluteURL(parent, self.request) + '/interventions.html'
        interventionStudent = self.context.context.__parent__
        return absoluteURL(interventionStudent, self.request)


class InterventionMessageView(object):
    """View for viewing a message."""

    def __init__(self, context, request):
        self.context = context
        self.request = request
        sender = ', '.join(intervention.contactsName(context.sender))
        added = context.created.strftime('%x')
        mapping = {'sender': sender, 'date': added}
        if context.status_change:
            self.heading = _('Change of Status Message from: ${sender} '
                             'sent ${date}', mapping=mapping)
        else:
            self.heading = _('Message from: ${sender} sent ${date}',
                             mapping=mapping)
        self.recipients = ', '.join(intervention.contactsName(
            context.recipients))


class FlourishInterventionMessageView(flourish.page.Page):
    """Flourish view for viewing a message."""

    @property
    def title(self):
        student = IContact(IPerson(self.context))
        return '%s %s' % (student.first_name, student.last_name)

    def __init__(self, context, request):
        self.context = context
        self.request = request
        self.sender = ', '.join(intervention.contactsName(context.sender))
        self.added = context.created.strftime('%x')
        self.recipients = ', '.join(intervention.contactsName(
            context.recipients))

    @property
    def done(self):
        if 'nexturl' in self.request:
            return self.request['nexturl']
        return absoluteURL(self.context.__parent__.__parent__, self.request)


class InterventionMessagesView(object):
    """View for viewing all messages."""

    def __init__(self, context, request):
        self.context = context
        self.request = request
        self.messages = []
        for k, v in sorted(self.context.items()):
            if self.skipMessage(v):
                continue
            name = ', '.join(intervention.contactsName(v.sender))
            added = v.created
            heading = _('Message sent by ${sender} on ${date}',
                        mapping={'sender': name,
                                 'date': added.strftime('%x')})
            recipients = ', '.join(intervention.contactsName(v.recipients))
            message = {
                'creation_date': added,
                'heading': heading,
                'recipients': recipients,
                'subject': v.subject,
                'body': v.body,
            }
            self.messages.append(message)
        self.messages.sort(key=lambda m: m['creation_date'], reverse=True)

    def skipMessage(self, message):
        return message.status_change

    @property
    def heading(self):
        name = intervention.contactName(IContact(IPerson(self.context)))
        return _('Messages regarding ${student}', mapping={'student': name})


class FlourishInterventionMessagesView(flourish.page.Page):
    """Flourish view for viewing all messages."""

    @property
    def title(self):
        student = IContact(IPerson(self.context))
        return '%s %s' % (student.first_name, student.last_name)

    @property
    def subtitle(self):
        return _('Intervention Messages')

    @property
    def messages(self):
        messages = []
        for k, v in sorted(self.context.items()):
            self.sender = ', '.join(intervention.contactsName(v.sender))
            self.added = v.created.strftime('%x')
            self.recipients = ', '.join(intervention.contactsName(v.recipients))
            messages.append({
                'creation_date': v.created,
                'sender': ', '.join(intervention.contactsName(v.sender)),
                'added': v.created.strftime('%x'),
                'recipients': ', '.join(intervention.contactsName(
                                        v.recipients)),
                'subject': v.subject,
                'body': v.body,
            })
        return sorted(messages, key=lambda m: m['creation_date'], reverse=True)

    @property
    def done(self):
        if 'nexturl' in self.request:
            return self.request['nexturl']
        return absoluteURL(self.context.__parent__, self.request)


class InterventionStatusMessagesView(InterventionMessagesView):
    """View for viewing all change of status messages."""

    def skipMessage(self, message):
        return not message.status_change

    @property
    def heading(self):
        name = intervention.contactName(IContact(IPerson(self.context)))
        return _('Change of Status Messages regarding ${student}',
                 mapping={'student': name})


class MessagePersonLinks(flourish.page.RefineLinksViewlet):
    """Message Person links viewlet."""

    @property
    def title(self):
        student = removeSecurityProxy(IPerson(self.context))
        return "%s %s" % (student.first_name, student.last_name)


class MessagePersonInterventionsLink(flourish.page.LinkViewlet):

    @property
    def url(self):
        student = removeSecurityProxy(IPerson(self.context))
        return absoluteURL(student, self.request) + '/intervention'


class InterventionGoalAddView(app.BaseAddView):
    """View for adding a goal."""

    def create(self, *args, **kw):
        self._creator = IContact(self.request.principal._person)
        goal, timeline, self._persons_responsible = args
        return self._factory(goal, timeline,
                             kw['presenting_concerns'], kw['strengths'], kw['indicators'],
                             kw['intervention'], goal_met=kw['goal_met'],
                             follow_up_notes=kw['follow_up_notes'])

    def add(self, goal):
        """Add goal to the student's goals."""
        context = self.context.context
        chooser = INameChooser(context)
        name = chooser.chooseName('', goal)
        context[name] = goal
        goal.persons_responsible = self._persons_responsible
        if self._creator is not None:
            goal.creator.add(IContact(self._creator))
        sendmail.sendInterventionGoalAddEmail(goal)
        return goal

    def nextURL(self):
        interventionStudent = self.context.context.__parent__
        return absoluteURL(interventionStudent, self.request)


class IGoalAddForm(interfaces.IInterventionGoal):

    timeline = Date(
        title=_("Target date"),
        )

    email = Bool(
        title=_(u"Email"),
        description=_(u"Send an email to the people selected above."),
        required=False,
        default=True)


class SimpleFormAdapter(object):

    def __init__(self, context):
        self.__dict__['context'] = removeSecurityProxy(context)

    def __setattr__(self, name, value):
        setattr(self.context, name, value)

    def __getattr__(self, name):
        return getattr(self.context, name)


class FlourishInterventionGoalAddView(flourish.form.AddForm):

    template = InheritTemplate(flourish.page.Page.template)
    label = None
    legend = _('Goal Details')

    fields = field.Fields(IGoalAddForm)
    fields = fields.select('persons_responsible', 'presenting_concerns', 'goal',
                            'strengths', 'indicators', 'intervention',
                            'timeline', 'goal_met', 'follow_up_notes', 'email')

    @property
    def title(self):
        student = IContact(IPerson(self.context))
        return '%s %s' % (student.first_name, student.last_name)

    def updateWidgets(self):
        super(FlourishInterventionGoalAddView, self).updateWidgets()
        sender = IContact(self.request.principal._person)
        utility = getUtility(IEmailUtility)
        if not utility.enabled() or not sender.email:
            if False:
                self.widgets['email'].mode = z3c.form.interfaces.HIDDEN_MODE

    @button.buttonAndHandler(_('Submit'), name='add')
    def handleAdd(self, action):
        data, errors = self.extractData()
        if errors:
            self.status = self.formErrorsMessage
            return
        obj = self.createAndAdd(data)
        if obj is not None:
            if data.get('email'):
                info = []
                emails = sendmail.sendInterventionGoalAddEmail(obj)
                for email in emails:
                    if email.status_code is None:
                        info.append(', '.join([urllib.quote(to)
                                               for to in email.to_addresses]))
                    else:
                        info.append(email.__name__)
                url = '%s?email=%s' % (self.nextURL(), '|'.join(info))
                self.request.response.redirect(url)
            else:
                self._finishedAdd = True

    @button.buttonAndHandler(_("Cancel"))
    def handle_cancel_action(self, action):
        self.request.response.redirect(self.nextURL())

    def updateActions(self):
        super(FlourishInterventionGoalAddView, self).updateActions()
        self.actions['add'].addClass('button-ok')
        self.actions['cancel'].addClass('button-cancel')


    def create(self, data):
        creator = IContact(self.request.principal._person)
        goal = intervention.InterventionGoal(
            data['goal'], data['timeline'],
            data['presenting_concerns'], data['strengths'], data['indicators'],
            data['intervention'],
            goal_met=data['goal_met'], follow_up_notes=data['follow_up_notes'])
        self._persons_responsible = data['persons_responsible']
        self._creator = creator
        return goal

    def add(self, goal):
        """Add goal to the student's goals."""
        chooser = INameChooser(self.context)
        name = chooser.chooseName('', goal)
        self.context[name] = goal
        goal.persons_responsible = self._persons_responsible
        if self._creator is not None:
            goal.creator.add(IContact(self._creator))
        return goal

    def nextURL(self):
        student = interfaces.IInterventionStudent(IPerson(self.context))
        return  absoluteURL(student, self.request)


class InterventionGoalEditView(EditView):
    """View for editing a goal"""

    @property
    def title(self):
        student = IContact(IPerson(self.context))
        return '%s %s' % (student.first_name, student.last_name)

    def update(self):
        if 'CANCEL' in self.request:
            self.request.response.redirect(self.nextURL())
        else:
            status = EditView.update(self)
            if 'UPDATE_SUBMIT' in self.request and not self.errors:
                self.request.response.redirect(self.nextURL())
            return status

    def nextURL(self):
        return absoluteURL(self.context, self.request)


class FlourishInterventionGoalEditView(z3cform.EditForm, flourish.form.Form):

    template = InheritTemplate(flourish.page.Page.template)
    label = None
    legend = _('Goal Details')

    fields = field.Fields(IGoalAddForm)
    fields = fields.select('persons_responsible', 'presenting_concerns', 'goal',
                            'strengths', 'indicators', 'intervention',
                            'timeline', 'goal_met', 'follow_up_notes')

    @property
    def title(self):
        student = IContact(IPerson(self.context))
        return '%s %s' % (student.first_name, student.last_name)

    @button.buttonAndHandler(_('Submit'), name='apply')
    def handleApply(self, action):
        super(FlourishInterventionGoalEditView, self).handleApply.func(self, action)
        # XXX: hacky sucessful submit check
        if (self.status == self.successMessage or
            self.status == self.noChangesMessage):
            self.request.response.redirect(self.nextURL())

    @button.buttonAndHandler(_("Cancel"))
    def handle_cancel_action(self, action):
        self.request.response.redirect(self.nextURL())

    def updateActions(self):
        super(FlourishInterventionGoalEditView, self).updateActions()
        self.actions['apply'].addClass('button-ok')
        self.actions['cancel'].addClass('button-cancel')

    def nextURL(self):
        return absoluteURL(self.context, self.request)


class InterventionGoalView(object):
    """View for viewing a goal."""

    def __init__(self, context, request):
        self.context = context
        self.request = request
        self.timeline = context.timeline.strftime('%x')
        self.notified = ''
        if context.notified:
            self.notified = _('notification sent')
        self.persons_responsible = ', '.join(intervention.contactsName(
            context.persons_responsible))
        self.goal_met = _('No')
        if context.goal_met:
            self.goal_met = _('Yes')

    @property
    def heading(self):
        student = removeSecurityProxy(IPerson(self.context))
        name = intervention.contactName(IContact(student))
        added = self.context.created.strftime('%x')
        return _('Goal ${goal_name} for ${student} added ${date}',
                 mapping={'goal_name': self.context.__name__,
                          'student': name, 'date': added})


class FlourishInterventionGoalView(flourish.page.Page):
    """Flourish view for viewing a goal."""

    @property
    def title(self):
        student = IContact(IPerson(self.context))
        return '%s %s' % (student.first_name, student.last_name)

    def __init__(self, context, request):
        self.context = context
        self.request = request
        self.creator = ', '.join(intervention.contactsName(context.creator))
        self.created = context.created.strftime('%x')
        self.timeline = context.timeline.strftime('%x')
        self.goal_met = context.goal_met and _('Yes') or _('No')
        self.persons_responsible = ', '.join(intervention.contactsName(
            context.persons_responsible))

    @property
    def canModify(self):
        return canWrite(self.context, 'goal')

    @property
    def done(self):
        if 'nexturl' in self.request:
            return self.request['nexturl']
        if interfaces.IStudentMessagesGoalsProxy.providedBy(
            self.context.__parent__):
            person = IPerson(self.request.principal, None)
            if person is None:
                return ''
            return absoluteURL(person, self.request) + '/intervention_tab'
        return absoluteURL(self.context.__parent__.__parent__, self.request)


class InterventionGoalsView(object):
    """View for viewing all goals."""

    def __init__(self, context, request):
        self.context = context
        self.request = request
        self.goals = []
        for k, v in sorted(self.context.items()):
            added = v.created.strftime('%x')
            heading = _('Goal ${goal_name} added ${date}',
                        mapping={'goal_name': k, 'date': added})
            notified = ''
            if v.notified:
                notified = _('notification sent')
            persons_responsible = intervention.contactsName(
                v.persons_responsible)
            goal_met = _('No')
            if v.goal_met:
                goal_met = _('Yes')
            goal = {
                'heading': heading,
                'presenting_concerns': v.presenting_concerns,
                'goal': v.goal,
                'strengths': v.strengths,
                'indicators': v.indicators,
                'intervention': v.intervention,
                'timeline': v.timeline.strftime('%x'),
                'notified': notified,
                'persons_responsible': persons_responsible,
                'goal_met': goal_met,
                'follow_up_notes': v.follow_up_notes,
            }
            self.goals.append(goal)

    @property
    def heading(self):
        return _('Goals for: ${first_name} ${last_name}',
            mapping={'first_name': IContact(IPerson(self.context)).first_name,
                     'last_name': IContact(IPerson(self.context)).last_name})


class FlourishInterventionGoalsView(flourish.page.Page):
    """Flourish view for viewing all goals."""

    @property
    def title(self):
        student = IContact(IPerson(self.context))
        return '%s %s' % (student.first_name, student.last_name)

    @property
    def goals(self):
        goals = []
        for k, v in sorted(self.context.items()):
            persons_responsible = ', '.join(intervention.contactsName(
                v.persons_responsible))
            goals.append({
                'obj': v,
                'timeline': v.timeline.strftime('%x'),
                'goal_met': v.goal_met and _('Yes') or _('No'),
                'persons_responsible': ', '.join(intervention.contactsName(
                    v.persons_responsible)),
                'canModify': canWrite(v, 'goal')
            })
        return goals

    @property
    def done(self):
        if 'nexturl' in self.request:
            return self.request['nexturl']
        return absoluteURL(self.context.__parent__, self.request)


class GoalPersonLinks(flourish.page.RefineLinksViewlet):
    """Goal Person links viewlet."""

    @property
    def title(self):
        student = removeSecurityProxy(IPerson(self.context))
        return "%s %s" % (student.first_name, student.last_name)


class GoalPersonInterventionsLink(flourish.page.LinkViewlet):

    @property
    def url(self):
        student = removeSecurityProxy(IPerson(self.context))
        return absoluteURL(student, self.request) + '/intervention'


class NotifyGoalsView(object):
    """View for notifying persons responsible for goals that
       have come due"""

    def __init__(self, context, request):
        self.context = context
        self.request = request
        goalsNotified = sendmail.sendInterventionGoalNotifyEmails()
        self.goals = []
        for notified in goalsNotified:
            name = intervention.contactName(IContact(IPerson(notified)))
            goal = {
                'text': _('${student} goal ${goal_name}',
                          mapping={'student': name,
                                   'goal_name': notified.__name__}),
                'url': absoluteURL(notified, request)
                }
            self.goals.append(goal)


class MessagesCSVView(BrowserView):

    def __call__(self):
        csvfile = StringIO()
        writer = csv.writer(csvfile, quoting=csv.QUOTE_ALL)
        row = ['year', 'student', 'date', 'sender', 'recipients', 'body']
        writer.writerow(row)
        root = interfaces.IInterventionRoot(self.context)
        for year in root.values():
            for student in year.values():
                for message in student['messages'].values():
                    created = message.created.strftime('%Y-%m-%d')
                    sender =  [IPerson(c).username for c in message.sender]
                    recipients = ', '.join(intervention.contactsEmail(
                        message.recipients))
                    body = message.body.replace('\n', '\\n')
                    body = body.replace('\r', '\\r')
                    row = [year.__name__, student.__name__, created,
                           ', '.join(sender), recipients, body]
                    row = [item.encode('utf-8') for item in row]
                    writer.writerow(row)
        return csvfile.getvalue().decode('utf-8')


class GoalsCSVView(BrowserView):

    def __call__(self):
        csvfile = StringIO()
        writer = csv.writer(csvfile, quoting=csv.QUOTE_ALL)
        row = ['year', 'student', 'created', 'creator', 'presenting_concerns',
               'goal', 'strengths', 'indicators', 'intervention', 'timeline',
               'persons_responsible', 'goal_met', 'follow_up_notes', 'notified']
        writer.writerow(row)
        root = interfaces.IInterventionRoot(self.context)
        for year in root.values():
            for student in year.values():
                for goal in student['goals'].values():
                    created = goal.created.strftime('%Y-%m-%d')
                    creator =  [IPerson(c).username for c in goal.creator]
                    timeline = goal.timeline.strftime('%Y-%m-%d')
                    goal_met = unicode(goal.goal_met)
                    notified = unicode(goal.notified)
                    persons_responsible = ', '.join(
                        intervention.contactsEmail(
                        goal.persons_responsible))
                    row = [year.__name__, student.__name__,
                           created, ', '.join(creator),
                           goal.presenting_concerns, goal.goal,
                           goal.strengths, goal.indicators, goal.intervention,
                           timeline, persons_responsible, goal_met,
                           goal.follow_up_notes, notified]
                    clean_row = []
                    for item in row:
                        if item is None:
                            item = u''
                        item = item.replace('\n', '\\n')
                        item = item.replace('\r', '\\r')
                        clean_row.append(item.encode('utf-8'))
                    writer.writerow(clean_row)
        return csvfile.getvalue().decode('utf-8')


class MessagesGoalsCSVView(BrowserView):

    def __call__(self):
        messages = MessagesCSVView(self.context, self.request)()
        goals = GoalsCSVView(self.context, self.request)()

        zfile = StringIO()
        archive = zipfile.ZipFile(zfile, "w")
        messages_file = tempfile.mktemp('.csv')
        open(messages_file, 'w').write(messages.encode('utf-8'))
        archive.write(messages_file, 'messages.csv', zipfile.ZIP_DEFLATED)
        goals_file = tempfile.mktemp('.csv')
        open(goals_file, 'w').write(goals.encode('utf-8'))
        archive.write(goals_file, 'goals.csv', zipfile.ZIP_DEFLATED)
        archive.close()

        data = zfile.getvalue()
        response = self.request.response
        response.setHeader('Content-Type', 'application/zip')
        response.setHeader('Content-Length', len(data))
        return data

