/********************************************************************
 * Copyright © 2004 VHA. All rights reserved
 ********************************************************************/
// Package
package gov.va.med.fw.mail;

// Java classes
import gov.va.med.fw.service.AbstractComponent;
import gov.va.med.fw.util.StringUtils;

import java.io.InputStream;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;

import org.apache.commons.lang.Validate;
import org.springframework.core.io.Resource;
import org.springframework.mail.MailException;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMailMessage;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.mail.javamail.MimeMessagePreparator;

/**
 * Provides methods to send e-mail messages sychronously.  Refer to a junit test
 * MailServiceTest class for sample usages of this class </br>
 *  
 *
 * Project: Framework</br>
 * Created on: 11:24:21 AM </br>
 *
 * @author DNS   LEV
 */
public class SynchronousMailService extends AbstractComponent implements MailService {

	/**
	 * An instance of serialVersionUID
	 */
	private static final long serialVersionUID = -2613270897112223669L;

	/**
	 * An instance of mailSender
	 */
	private JavaMailSender mailSender = null;
	
	/**
	 * A default constructor
	 */
	public SynchronousMailService() {
		super();
	}

	/**
	 * @see gov.va.med.fw.service.AbstractComponent#afterPropertiesSet()
	 */
	public void afterPropertiesSet() throws Exception {
		super.afterPropertiesSet();
		Validate.notNull( this.mailSender, "A mail sender is required." );
	}

	/**
	 * @see org.springframework.mail.javamail.JavaMailSender#createMimeMessage()
	 */
	public MimeMessage createMimeMessage() {
		return mailSender.createMimeMessage();
	}

	/**
	 * @see org.springframework.mail.javamail.JavaMailSender#createMimeMessage(java.io.InputStream)
	 */
	public MimeMessage createMimeMessage(InputStream contentStream) throws MailException {
		return mailSender.createMimeMessage(contentStream);
	}

	/**
	 * @see org.springframework.mail.javamail.JavaMailSender#send(javax.mail.internet.MimeMessage)
	 */
	public void send(MimeMessage mimeMessage) throws MailException {
		mailSender.send(mimeMessage);
	}

	/**
	 * @see org.springframework.mail.javamail.JavaMailSender#send(javax.mail.internet.MimeMessage[])
	 */
	public void send(MimeMessage[] mimeMessages) throws MailException {
		mailSender.send(mimeMessages);
	}

	/**
	 * @see org.springframework.mail.javamail.JavaMailSender#send(org.springframework.mail.javamail.MimeMessagePreparator)
	 */
	public void send(MimeMessagePreparator mimeMessagePreparator) throws MailException {
		mailSender.send(mimeMessagePreparator);
	}

	/**
	 * @see org.springframework.mail.javamail.JavaMailSender#send(org.springframework.mail.javamail.MimeMessagePreparator[])
	 */
	public void send(MimeMessagePreparator[] mimeMessagePreparators) throws MailException {
		mailSender.send(mimeMessagePreparators);
	}

	/**
	 * @see org.springframework.mail.MailSender#send(org.springframework.mail.SimpleMailMessage)
	 */
	public void send(SimpleMailMessage simpleMessage) throws MailException {
		mailSender.send(simpleMessage);
	}

	/**
	 * @see org.springframework.mail.MailSender#send(org.springframework.mail.SimpleMailMessage[])
	 */
	public void send(SimpleMailMessage[] simpleMessages) throws MailException {
		mailSender.send(simpleMessages);
	}

	/**
	 * @see gov.va.med.fw.mail.MailService#send(java.lang.String, org.springframework.mail.SimpleMailMessage)
	 */
	public void send( String text, final SimpleMailMessage template ) throws MailException {

        // Check for valid input arguments
		Validate.notNull( template, "A message template must not be null" );

        final String formattedText = preserveCarriageReturns(text);

        // Prepare a message with an attached report
		MimeMessagePreparator preparator = new MimeMessagePreparator() {
         public void prepare(MimeMessage mimeMessage) throws MessagingException {
         	MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true, "UTF-8");         	
         	MimeMailMessage message = new MimeMailMessage( helper );
         	
         	// Copy all message properties from a template to a message
         	template.copyTo( message );
         	
         	// Set a message content
         	message.setText( formattedText );
         }
		};
		
		mailSender.send( preparator );
	}

    /**
	 * @see gov.va.med.fw.mail.MailService#send(java.lang.String, java.lang.String, org.springframework.mail.SimpleMailMessage)
	 */
	public void send( String text, String attachment, SimpleMailMessage template) throws MailException {
		
		// Check for valid input arguments
		Validate.notNull( attachment, "A message attachment must not be null" );
		
		Resource resource = this.getApplicationContext().getResource( attachment );
		this.send( preserveCarriageReturns(text), resource, template );
	}

	/**
	 * @see gov.va.med.fw.mail.MailService#send(java.lang.String, org.springframework.core.io.Resource, org.springframework.mail.SimpleMailMessage)
	 */
	public void send( String text, final Resource resource, final SimpleMailMessage template ) throws MailException {
		
		// Check for valid input arguments
		Validate.notNull( resource, "A message attachment must not be null" );
		Validate.notNull( template, "A message template must not be null" );

        final String formattedText = preserveCarriageReturns(text);

        // Prepare a message with an attached report
		MimeMessagePreparator preparator = new MimeMessagePreparator() {
         public void prepare(MimeMessage mimeMessage) throws MessagingException {
         	MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true, "UTF-8");         	
         	MimeMailMessage message = new MimeMailMessage( helper );
         	template.copyTo( message );
         	
         	// Attach a message's attachment
         	if( resource.exists() ) {
            	helper.addAttachment( resource.getFilename(), resource );
         	}
         	
         	// Set a message text
         	message.setText( formattedText );
         }
		};
		
		// Send a message
		mailSender.send( preparator );
	}
	
	/**
	 * @see gov.va.med.fw.mail.MailService#send(java.lang.String, org.springframework.core.io.Resource, org.springframework.mail.SimpleMailMessage)
	 */
	public void send( String text, final Resource resource, final SimpleMailMessage template, final String name ) throws MailException {
		
		// Check for valid input arguments
		Validate.notNull( resource, "A message attachment must not be null" );
		Validate.notNull( template, "A message template must not be null" );

        final String formattedText = preserveCarriageReturns(text);

        // Prepare a message with an attached report
		MimeMessagePreparator preparator = new MimeMessagePreparator() {
         public void prepare(MimeMessage mimeMessage) throws MessagingException {
         	MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true, "UTF-8");         	
         	MimeMailMessage message = new MimeMailMessage( helper );
         	template.copyTo( message );
         	
         	// Attach a message's attachment
         	if( resource.exists() ) {
            	helper.addAttachment( name, resource );
         	}
         	
         	// Set a message text
         	message.setText( formattedText );
         }
		};
		
		// Send a message
		mailSender.send( preparator );
	}
	/**
	 * @param mailSender The mailSender to set.
	 */
	public void setMailSender(JavaMailSender mailSender) {
		this.mailSender = mailSender;
	}

   /** 
     * Adds a tab character before each carriage return which will cause Microsoft Outlook 
     * to not "remove extra line breaks".  Also, convert "\r\n" into "\n" since only "\n" is needed 
     * in e-mail messages to keep carriage return formatting in tact.  Otherwise, extra carriage returns 
     * might result when the tab character is inserted as well (i.e. we don't want \r\t\n). 
     * 
     * @param text the raw text. 
     * @return the raw text with tabs added. 
     */ 
    public static String preserveCarriageReturns(String text)
    {
        if (StringUtils.isNotEmpty(text))
        {
        	text = text.replaceAll("\r\n", "\n");  // standardizes line separators
            return text.replaceAll("\n", "\t\n");
        }
        else
        {
            return text;
        }
    }
}