package woko.mail;

import woko.Woko;
import woko.util.WLogger;

import javax.mail.*;
import javax.mail.event.TransportEvent;
import javax.mail.event.TransportListener;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.io.InputStream;
import java.util.*;

public class SmtpMailService extends MailServiceBase {

    private static final WLogger logger = WLogger.getLogger(SmtpMailService.class);

    private String encoding = "utf-8";

    private final List<TransportListener> transportListeners = new ArrayList<TransportListener>();

    public SmtpMailService(String appUrl,
                           String fromEmailAddress,
                           Map<String, MailTemplate> templates) {
        super(appUrl, fromEmailAddress, templates);
        logger.info("Created with appUrl=" + appUrl +", fromEmailAddress=" + fromEmailAddress + ", " + templates.size() + " templates");
    }

    public SmtpMailService setEncoding(String encoding) {
        this.encoding = encoding;
        return this;
    }

    public SmtpMailService addTransportListener(TransportListener l) {
        transportListeners.add(l);
        return this;
    }

    public SmtpMailService removeTransportListener(TransportListener l) {
        transportListeners.remove(l);
        return this;
    }

    @Override
    public void sendMail(Woko woko, final String to, final Locale locale, final MailTemplate template, final Map<String, Object> binding) {

        logger.debug("Sending email to " + to + " using template " + template + " and locale " + locale + ", binding=" + binding);

        String from = getFromEmailAddress();
        Properties props = getMailSessionProperties();

        String smtpAuthProp = props.getProperty("mail.smtp.auth", "false");
        boolean smtpAuth = Boolean.parseBoolean(smtpAuthProp);
        try {
            Session session = smtpAuth ?
                Session.getDefaultInstance(props, createAuthenticator(props)) :
                Session.getDefaultInstance(props);
            MimeMessage message = new MimeMessage(session);
            message.setFrom(new InternetAddress(from));
            message.addRecipient(Message.RecipientType.TO, new InternetAddress(to));
            message.setSubject(template.processSubject(woko, locale, binding), encoding);
            message.setContent(template.processBody(woko, locale, binding),
                    "text/html; charset=" + encoding);
            message.setSentDate(new Date());

            Transport t = session.getTransport();
            // add our logging listener
            t.addTransportListener(new TransportListener() {
                @Override
                public void messageDelivered(TransportEvent e) {
                    logger.debug("Email delivered to " + to + " using template " + template + " and locale " + locale + ", binding=" + binding);
                }

                @Override
                public void messageNotDelivered(TransportEvent e) {
                    logger.error("Email NOT delivered to " + to + " using template " + template + " and locale " + locale + ", binding=" + binding + ", transportEvent=" + e);
                }

                @Override
                public void messagePartiallyDelivered(TransportEvent e) {
                    logger.error("Email PARTIALLY delivered to " + to + " using template " + template + " and locale " + locale + ", binding=" + binding + ", transportEvent=" + e);
                }
            });
            // add user supplied listeners
            for (TransportListener l : transportListeners) {
                t.addTransportListener(l);
            }

            t.connect();
            try {
                t.sendMessage(message, message.getRecipients(Message.RecipientType.TO));
            } finally {
                t.close();
            }
        } catch(Exception e) {
            logger.error("Caught exception while sending email" + to + " using template " + template + " and locale " + locale + ", binding=" + binding, e);
            throw new RuntimeException(e);
        }
    }

    protected Authenticator createAuthenticator(Properties mailSessionProperties) {
        return new SmtpAuthenticator(
                mailSessionProperties.getProperty("mail.smtp.username"),
                mailSessionProperties.getProperty("mail.smtp.password"));
    }

    private class SmtpAuthenticator extends Authenticator {

        private final String username;
        private final String password;

        private SmtpAuthenticator(String username, String password) {
            logger.info("Using authentication (username=" + username + ")");
            this.username = username;
            this.password = password;
        }

        @Override
        protected PasswordAuthentication getPasswordAuthentication() {
            return new PasswordAuthentication(username, password);
        }
    }

    public static final String PROPERTY_FILE = "/woko.mail.properties";

    protected Properties getMailSessionProperties() {
        Properties properties = new Properties();
        InputStream is = SmtpMailService.class.getResourceAsStream(PROPERTY_FILE);
        if (is==null) {
            String msg = "Could not find property file " + PROPERTY_FILE + " in the CLASSPATH.";
            logger.error(msg);
            throw new IllegalStateException(msg);
        }
        try {
            properties.load(is);
            return properties;
        } catch (Exception e) {
            String msg = "Unable to load properties from " + PROPERTY_FILE;
            logger.error(msg, e);
            throw new RuntimeException(msg, e);
        }
    }

}

@@ -162,16 +162,61 @@
 stener;%0A
+import javax.mail.internet.AddressException;%0A
 import j
@@ -251,16 +251,16 @@
 ddress;%0A
-
 import j
@@ -1367,24 +1367,1316 @@
 his;%0A    %7D%0A%0A
+    /**%0A     * Create and return the message. Can be overriden to create the message differently%0A     * or add to the one returned by this implementation.%0A     * @param woko%0A     * @param from%0A     * @param to%0A     * @param locale%0A     * @param template%0A     * @param binding%0A     * @param session%0A     * @return the message%0A     * @throws MessagingException%0A     */%0A    protected MimeMessage createMimeMessage(Woko woko,%0A                                            String from,%0A                                            String to,%0A                                            Locale locale,%0A                                            MailTemplate template,%0A                                            Map%3CString, Object%3E binding,%0A                                            Session session) throws MessagingException %7B%0A        MimeMessage message = new MimeMessage(session);%0A        message.setFrom(new InternetAddress(from));%0A        message.addRecipient(Message.RecipientType.TO, new InternetAddress(to));%0A        message.setSubject(template.processSubject(woko, locale, binding), encoding);%0A        message.setContent(template.processBody(woko, locale, binding),%0A                %22text/html; charset=%22 + encoding);%0A        message.setSentDate(new Date());%0A        return message;%0A    %7D%0A%0A
     @Overrid
@@ -3402,36 +3402,38 @@
 ssage message = 
-new 
+create
 MimeMessage(sess
@@ -3432,422 +3432,58 @@
 age(
-session);%0A            message.setFrom(new InternetAddress(from));%0A            message.addRecipient(Message.RecipientType.TO, new InternetAddress(to));%0A            message.setSubject(template.processSubject(woko, locale, binding), encoding);%0A            message.setContent(template.processBody(woko, locale, binding),%0A                    %22text/html; charset=%22 + encoding);%0A            message.setSentDate(new Date()
+woko, from, to, locale, template, binding, session
 );%0A%0A

fix #212 : protected woko.mail.SmtpMailService#createMimeMessage, allows for easier override.