# Copyright (c) 2005-2006 Simplistix Ltd
#
# This Software is released under the MIT License:
# http://www.opensource.org/licenses/mit-license.html
# See license.txt for more details.

import os
import rfc822

from AccessControl import ClassSecurityInfo
from DateTime import DateTime
from email.Header import Header
from email.MIMEMultipart import MIMEMultipart
from email.MIMEText import MIMEText
from email.Utils import make_msgid, formataddr, getaddresses

from App.class_init import default__class_init__ as InitializeClass
from App.Common import package_home
from MTMultipart import MTMultipart
from Products.PageTemplates.ZopePageTemplate import ZopePageTemplate
from Products.PageTemplates.PageTemplateFile import PageTemplateFile

from ZPublisher import HTTPResponse

# Configured using zope.conf in Zope 2.7.8, Zope 2.8.2, and above
default_encoding = getattr(HTTPResponse,'default_encoding','iso-8859-15')

class BaseMailTemplate:

    security = ClassSecurityInfo()

    _properties = ()

    ZScriptHTML_tryForm = None

    content_type = 'text/plain'

    mailhost = None

    security.declarePrivate('_process')
    def _process(self,kw):
        # sort out what encoding we're going to use
        encoding = kw.get('encoding',
                          self.getProperty('encoding',
                                           default_encoding))
        text = self.__class__.__bases__[1].__call__(self,**kw)
        # ZPT adds newline at the end, but it breaks backward compatibility.
        # So I remove it.
        if text.endswith('\n'):
            text = text[:-1]
        if not self.html() and isinstance(text, unicode):
            text = text.encode(encoding,'replace')
        # now turn the result into a MIMEText object
        msg = MIMEText(
            text.replace('\r',''),
            self.content_type.split('/')[1],
            encoding
            )
        # sort out what headers and addresses we're going to use
        headers = {}
        values = {}
        # headers from the headers property
        for header in getattr(self,'headers',()):
            name,value = header.split(':',1)
            headers[name]=value
        # headers from the headers parameter
        headers_param = kw.get('headers',{})
        headers.update(headers_param)
        # values and some specific headers
        for key,header in (('mfrom','From'),
                           ('mto','To'),
                           ('mcc','Cc'),
                           ('mbcc','Bcc'),
                           ('subject','Subject')):
            value = kw.get(key,
                           headers_param.get(header,
                                             getattr(self,
                                                     key,
                                                     headers.get(header))))
            if value is not None:
                values[key]=value

                if key == 'subject':
                    try:
                        # Try to keep header non encoded
                        value = Header(value)
                    except UnicodeDecodeError:
                        value = Header(value, "UTF-8")

                else:
                    dest_list = []
                    for name, email in getaddresses((value,)
                            if isinstance(value, basestring) else value):
                        try:
                            name = Header(name)
                        except UnicodeDecodeError:
                            name = Header(name, "UTF-8")
                        dest_list.append(formataddr((name.encode(), email)))
                    value = ", ".join(dest_list)

                headers[header]=value
        # check required values have been supplied
        errors = []
        for param in ('mfrom','mto'):
            if not values.get(param):
                errors.append(param)
        if errors:
            raise TypeError(
                'The following parameters were required by not specified: '+(
                ', '.join(errors)
                ))
        # add date header
        headers['Date']=DateTime().rfc822()
        # do not let the MTA to generate the Message-ID:
        # we want to have it stored in ERP5, for mail threading
        headers['Message-ID'] = make_msgid()
        # turn headers into an ordered list for predictable header order
        keys = headers.keys()
        keys.sort()
        return msg,values,[(key,headers[key]) for key in keys]

    security.declarePrivate('_send')
    def _send(self,mfrom,mto,msg):

        mailhost = self.restrictedTraverse(self.mailhost,None)
        if not getattr(mailhost,'meta_type',None) in (
            'Mail Host','Maildrop Host'
            ):
            raise RuntimeError(
                'Could not traverse to MailHost %r' % self.mailhost
                )

        mailhost._send(mfrom,mto,msg.as_string())

    security.declareProtected('View', 'send')
    def send(self,**kw):

        msg,values,headers = self._process(kw)

        for header,value in headers:
            msg[header]=value

        to_addrs = ()
        for key in ('mto', 'mcc', 'mbcc'):
            v = values.get(key)
            if v:
                if isinstance(v, basestring):
                    v = [rfc822.dump_address_pair(addr) for addr \
                            in rfc822.AddressList(v)]
                to_addrs += tuple(v)

        self._send(values['mfrom'], to_addrs, msg)

    security.declareProtected('View', '__call__')
    __call__ = send

    security.declareProtected('View', 'as_message')
    def as_message(self,**kw):
        msg,values,headers = self._process(kw)
        multipart_kw = {}
        #subtype = kw.get('subtype')
        #if subtype:
        #    multipart_kw['_subtype'] = subtype
        #boundary = kw.get('boundary')
        #if boundary:
        #    multipart_kw['boundary'] = boundary

        multipart = MTMultipart(self,
                                values['mfrom'],
                                values['mto'],
                                **multipart_kw)

        # set the encoding for the container
        #multipart.set_charset(msg.get_charset())

        for header,value in headers:
            multipart[header]=value

        multipart.attach(msg)

        return multipart

InitializeClass(BaseMailTemplate)