#
# 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, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#

from datetime import date

import z3c.form.field
from zope.component import getUtility
from zope.traversing.browser.absoluteurl import absoluteURL
from zope.i18n import translate

from schooltool.email.interfaces import IEmailUtility
from schooltool.email.mail import Email

from schooltool.intervention import InterventionGettext as _
from interfaces import IInterventionGoal
import intervention


class EmailMessage(object):
    """Object that knows whether it is valid to send an email message to
       the email server given the set values."""

    def __init__(self, sender, recipients, subject, body):
        self.sender = sender
        self.recipients = recipients
        self.subject = subject
        self.body = body

    def isValid(self):
        if not self.sender or not self.sender.strip():
            return False
        if not [addr for addr in self.recipients if addr and addr.strip()]:
            return False
        if not self.body or not self.body.strip():
            return False
        if not self.subject or not self.subject.strip():
            return False
        return True

    def send(self):
        if self.isValid():
            sendEmail(self.sender, self.recipients, self.subject, self.body)


def sendInterventionMessageEmail(obj, event):
    """Send email corresponding to the intervention message just added."""

    person = intervention.convertIdToPerson(obj.sender)
    sender = intervention.convertIdToEmail(obj.sender)
    sender_name = intervention.convertIdToName(person.username)
    recipients = intervention.convertIdsToEmail(obj.recipients)
    name = intervention.convertIdToName(obj.student.username)
    mapping = {'student': name}
    if obj.status_change:
        subject = translate(_('INTERVENTION STATUS CHANGE: ${student}',
                              mapping=mapping),
                            context=intervention.getRequest())
    else:
        subject = translate(_('INTERVENTION MESSAGE: ${student}',
                              mapping=mapping),
                            context=intervention.getRequest())
    body = translate(_('${sender} writes:', mapping={'sender': sender_name}),
                     context=intervention.getRequest())
    body += '\n\n%s' % obj.body
    EmailMessage(sender, recipients, subject, body).send()


def sendInterventionGoalAddEmail(obj, event):
    """Send email corresponding to the intervention goal just added."""

    if obj.creator:
        sender = intervention.convertIdToEmail(obj.creator)
    else:
        sender = intervention.convertIdToEmail('manager')

    name = intervention.convertIdToName(obj.student.username)
    subject = translate(_('INTERVENTION GOAL ADDED: ${student}',
                          mapping={'student': name}),
                        context=intervention.getRequest())

    responsible = [id for id in obj.persons_responsible
                   if not id.split(':')[0] == obj.student.username]
    notified = [id for id in obj.persons_responsible
                if id.split(':')[0] == obj.student.username]

    if responsible:
        recipients = intervention.convertIdsToEmail(responsible)
        body = buildInterventionGoalAddBody(obj)
        EmailMessage(sender, recipients, subject, body).send()

    if notified:
        recipients = intervention.convertIdsToEmail(notified)
        body = buildInterventionGoalAddBody(obj, False)
        EmailMessage(sender, recipients, subject, body).send()


def buildInterventionGoalAddBody(obj, staff=True):
    name = intervention.convertIdToName(obj.student.username)
    body = translate(_('The following goal was added for ${student}:',
                       mapping={'student': name}),
                     context=intervention.getRequest())
    body += '\n'
    fields = z3c.form.field.Fields(IInterventionGoal)
    fields = fields.omit('__name__', '__parent__', 'goal_met',
                         'follow_up_notes', 'notified', 'creator', 'created',
                         'at_one_time_responsible')
    for k, v in fields.items():
        body += '\n%s\n%s\n\n' % (v.field.title, '-' * len(v.field.title))
        text = obj.__getattribute__(k)
        if k == 'persons_responsible':
            text = '\n'.join(intervention.convertIdsToNames(obj.persons_responsible))
        elif k == 'timeline':
            text = obj.timeline.strftime('%x')
        body += '%s\n' % text
    if staff:
        url = absoluteURL(obj.__parent__.__parent__, intervention.getRequest())
        intervention_center = translate(_('Intervention Center'),
                                        context=intervention.getRequest())
        body += '\n%s\n%s\n' % (intervention_center, '-' * len(intervention_center))
        body += '\n%s\n' % url
    return body


def sendInterventionGoalNotifyEmails():
    """Loop through all goals for the current school year and send
       email to the persons responsible for the goal if:

       1) the goal's timeline is on or before today.
       2) an email for the goal has never been sent.
    """

    request = intervention.getRequest()
    now = date.today()
    goalsNotified = []
    interventionSchoolYear = intervention.getInterventionSchoolYear()
    for interventionStudent in interventionSchoolYear.values():
        for interventionGoal in interventionStudent['goals'].values():
            if interventionGoal.timeline <= now and not interventionGoal.notified:
                notifyInterventionGoal(interventionGoal, request)
                goalsNotified.append(interventionGoal)
    return goalsNotified


def notifyInterventionGoal(interventionGoal, request):
    """Send email to the persons responsible for the given goal."""

    sender = intervention.convertIdToEmail('manager')
    student = interventionGoal.student
    persons = [id for id in interventionGoal.persons_responsible
               if not id.split(':')[0] == student.username]
    recipients = intervention.convertIdsToEmail(persons)
    name = intervention.convertIdToName(student.username)
    subject = translate(_('INTERVENTION GOAL DUE: ${student}',
                          mapping={'student': name}),
                        context=request)
    name = intervention.convertIdToName(student.username)
    url = absoluteURL(interventionGoal, request) + '/@@editGoal.html'
    body = translate(_("Please follow the link below to update the follow "
                       "up notes and, if appropriate, the goal met status "
                       "of the intervention goal for ${student}.",
                       mapping={'student': name}),
                     context=request)
    body += '\n\n%s\n' % url

    message = EmailMessage(sender, recipients, subject, body)
    if message.isValid():
        message.send()
        interventionGoal.notified = True


def sendEmail(sender, recipients, subject, body):
    """send email through the schooltool email utility."""

    email = Email(sender, recipients, body, subject)
    utility = getUtility(IEmailUtility)
    if not utility.enabled():
        return
    utility.send(email)


class TestMailDelivery(object):
    """Email delivery utility used for testing"""

    def enabled(self):
        return True

    def send(self, email):
        print 'From:', email.from_address
        print 'To:', ', '.join(email.to_addresses)
        print 'Subject:', email.subject
        print email.body

