package org.aegee.runanddine.mail;

import java.io.UnsupportedEncodingException;
import java.util.Collection;
import java.util.Date;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

import org.aegee.runanddine.RunAndDineApplication;

/**
 * Service for sending mails
 */
public class MailService
{

	/**
	 * Singleton instance of MailService
	 */
	private static MailService instance;

	/**
	 * Sender mail address to be used
	 */
	private InternetAddress from;

	private MailService()
	{
		try
		{
			from = new InternetAddress(RunAndDineApplication.get().getServletContext().getInitParameter("mail_address"),
				RunAndDineApplication.get().getServletContext().getInitParameter("mail_name"));
		}
		catch (UnsupportedEncodingException ex)
		{
			Logger.getLogger(MailService.class.getName()).log(Level.SEVERE, null, ex);
		}
	}

	/**
	 * Get singleton instance of MailService
	 * 
	 * @return Singleton instance of MailService
	 */
	public static MailService getInstance()
	{
		if (instance == null)
		{
			instance = new MailService();
		}
		return instance;
	}

	/**
	 * Create and return new mail session
	 * 
	 * @return
	 */
	private Session getSession()
	{
		Authenticator authenticator = new Authenticator();

		Properties properties = new Properties();
		// properties.setProperty("mail.smtp.submitter", authenticator.getPasswordAuthentication().getUserName());
		properties.setProperty("mail.smtp.auth", "false");
		// properties.put("mail.smtp.socketFactory.port", "25");
		// properties.put("mail.smtp.socketFactory.class",
		// "javax.net.ssl.SSLSocketFactory");
		properties.setProperty("mail.smtp.host", "localhost");
		properties.setProperty("mail.smtp.port", "25");
		properties.setProperty("mail.smtp.ssl", "false");

		return Session.getInstance(properties, authenticator);
	}

	/**
	 * Send mail via MailService
	 * 
	 * @param mail
	 *            Mail to be sent
	 * @param listener
	 *            Listener to be notified about mailing status
	 */
	public void sendMail(final Mail mail, final MailServiceListener listener)
	{
		final Session session = getSession();
		new Thread()
		{

			@Override
			public void run()
			{
				try
				{
					MimeMessage msg = new MimeMessage(session);
					msg.setFrom(from);
					msg.setRecipients(Message.RecipientType.TO, mail.getTo());
					msg.setSubject(mail.getSubject());
					msg.setSentDate(new Date());
					msg.setText(mail.getContent());
					Transport.send(msg);
					if (listener != null)
					{
						listener.mailsSend();
					}
				}
				catch (MessagingException mex)
				{
					if (RunAndDineApplication.TEST)
					{
						RunAndDineApplication.debug(String.format("Subject: %s\nTo: %s\nContent:\n %s", mail.getSubject(),
							mail.getTo(), mail.getContent()));
					}
					if (listener != null)
					{
						listener.failure(mex);
					}
				}
			}
		}.start();
	}

	/**
	 * Send multiple mails at once
	 * 
	 * @param c
	 *            List of mails to be sent
	 * @param listener
	 *            Listener to be notified about mailing status
	 */
	public void sendMail(final Collection<Mail> c, final MailServiceListener listener)
	{
		final Session session = getSession();
		new Thread()
		{

			@Override
			public void run()
			{
				for (Mail mail : c)
				{
					try
					{
						MimeMessage msg = new MimeMessage(session);
						msg.setFrom(from);
						msg.setRecipients(Message.RecipientType.TO, mail.getTo());
						msg.setSubject(mail.getSubject());
						msg.setSentDate(new Date());
						msg.setText(mail.getContent());
						Transport.send(msg);
					}
					catch (MessagingException mex)
					{
						// will never admit its fails!
						if (RunAndDineApplication.TEST)
						{
							RunAndDineApplication.debug(String.format("Subject: %s\nTo: %s\nContent:\n %s",
								mail.getSubject(), mail.getTo(), mail.getContent()));
						}
					}
				}
				if (listener != null)
				{
					listener.mailsSend();
				}
			}
		}.start();
	}

	/**
	 * Authenticator for MailService
	 */
	private class Authenticator extends javax.mail.Authenticator
	{

		private PasswordAuthentication authentication;

		public Authenticator()
		{
			String username = RunAndDineApplication.get().getServletContext().getInitParameter("mail_user");
			String password = RunAndDineApplication.get().getServletContext().getInitParameter("mail_pw");
			authentication = new PasswordAuthentication(username, password);
		}

		@Override
		protected PasswordAuthentication getPasswordAuthentication()
		{
			return authentication;
		}
	}
}
