/**
 * 
 */
package org.biomoby.registry.rdfagent.util;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Date;
import java.util.Properties;

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

/**
 * This class is a mailer for the RDF agent. In it are methods to perform SMTP
 * mailing as well as mailing via 'mail' on unix machines.
 * 
 * @author Eddie created Feb 1, 2006
 */
public class Mailer {

	private String newline = System.getProperty("line.separator");

	private boolean standAlone = false;

	/**
	 * Constructor
	 * 
	 */
	public Mailer() {
		if (!Log.isLoggable()) {
			standAlone = true;
			Log.start(System.getProperty("user.dir"), Log.ALL, true,
					"Logger started by " + this.getClass().getName());
		}
	}

	/**
	 * 
	 * @param server
	 *            the SMTP mail server
	 * @param login
	 *            the SMTP login
	 * @param pass
	 *            the SMTP password used with login
	 * @param recipient
	 *            the mail recipient
	 * @param subject
	 *            the subject of the message
	 * @param body
	 *            the body of the message
	 * @param from
	 *            who the message is from
	 * @return true if the message was sent (doesn't imply that the message was
	 *         received), false otherwise
	 */
	public boolean sendSMTPMail(String server, String login, String pass,
			String recipient, String subject, String body, String from) {
		Properties prop = new Properties();
		prop.put("mail.smtp.host", server);
		Session session = Session.getDefaultInstance(prop, null);
		MimeMessage msg = new MimeMessage(session);
		try {
			msg.setFrom(new InternetAddress(from));
		} catch (AddressException e) {
			Log.exception(this.getClass().getName(), "sendSMTPMail", e);
			Log
					.severe("The mailers from address was invalid. Please ensure that it is correct.");
			return false;
		} catch (MessagingException e) {
			Log.exception(this.getClass().getName(), "sendSMTPMail", e);
			Log.severe(e.getLocalizedMessage());
			return false;
		}
		try {
			msg.addRecipient(Message.RecipientType.TO, new InternetAddress(
					recipient));
		} catch (AddressException e) {
			Log.exception(this.getClass().getName(), "sendSMTPMail", e);
			Log
					.severe("The mailers to address was invalid. Please ensure that it is correct");
			return false;
		} catch (MessagingException e) {
			Log.exception(this.getClass().getName(), "sendSMTPMail", e);
			Log.severe(e.getLocalizedMessage());
			return false;
		}
		try {
			msg.setSubject(subject);
		} catch (MessagingException e) {
			Log.exception(this.getClass().getName(), "sendSMTPMail", e);
			Log.severe("Couldn't set the subject of the mail message.");
			return false;
		}
		try {
			msg.setSentDate(new Date());
		} catch (MessagingException e) {
			Log.exception(this.getClass().getName(), "sendSMTPMail", e);
			Log.severe(e.getLocalizedMessage());
			return false;
		}
		try {
			msg.setText(body);
		} catch (MessagingException e) {
			Log.exception(this.getClass().getName(), "sendSMTPMail", e);
			Log.severe("");
			return false;
		}
		Transport transport;
		if (pass != null) {
			try {
				transport = session.getTransport("smtp");
			} catch (NoSuchProviderException e) {
				Log.exception(this.getClass().getName(), "sendSMTPMail", e);
				Log.severe("");
				return false;
			}
			try {
				transport.connect(server, login, pass);
			} catch (MessagingException e) {
				Log.exception(this.getClass().getName(), "sendSMTPMail", e);
				Log.severe(e.getLocalizedMessage());
				return false;
			}
		}
		try {
			Transport.send(msg);
		} catch (MessagingException e) {
			Log.exception(this.getClass().getName(), "sendSMTPMail", e);
			Log.severe(e.getLocalizedMessage());
			return false;
		}
		Log.info("Message sent via SMTP to " + recipient);
		return true;
	}

	/**
	 * 
	 * @param recipient
	 *            the recipients email address
	 * @param subject
	 *            the subject of the message
	 * @param body
	 *            the message to send to the mail recipient
	 * @return true if the message was sent, false otherwise.
	 *         <p>
	 *         <b>Note:</b> there are some instances where an exception is
	 *         caught during mailing of the message and the message may have
	 *         been sent, yet sendMail reports it as failing.
	 */
	public boolean sendMail(String recipient, String subject, String body) {

		String cmd = "echo \"" + body + "\" | mail" + " -s '" + subject + "' '"
				+ recipient + "'";
		File file = null;
		try {
			file = File.createTempFile("__script__", ".sh");
		} catch (IOException e) {
			Log.exception(this.getClass().getName(), "sendMail", e);
			Log
					.severe("Couldn't create the temp file needed to be used with 'mail'. No message was sent.");
			return false;
		}
		FileWriter fw = null;
		Log.info(file.getAbsolutePath());
		try {
			fw = new FileWriter(file);
		} catch (IOException e) {
			Log.exception(this.getClass().getName(), "sendMail", e);
			Log
					.severe("Couldn't create the file writer needed to be used with 'mail'. No message was sent.");
			Log.info(file.getAbsolutePath() + " has " + ((file.delete()) ? "" : "not ")
					+ "been deleted");
			return false;
		}
		try {
			fw.write(_shellScriptHeader + cmd);
		} catch (IOException e) {
			Log.exception(this.getClass().getName(), "sendMail", e);
			Log
					.severe("Couldn't write to the file needed to be used with 'mail'. No message was sent.");
			Log.info(file.getAbsolutePath() + " has " + ((file.delete()) ? "" : "not ")
					+ "been deleted");
			return false;
		}
		try {
			fw.close();
		} catch (IOException e) {
			Log.exception(this.getClass().getName(), "sendMail", e);
			Log
					.severe("Couldn't close the file (after writing to it) needed for use with 'mail'. No message was sent.");
			Log.info(file.getAbsolutePath() + " has " + ((file.delete()) ? "" : "not ")
					+ "been deleted");
			return false;
		}

		Process p;
		try {
			p = Runtime.getRuntime().exec("chmod +x " + file.getAbsolutePath());
		} catch (IOException e) {
			Log.exception(this.getClass().getName(), "sendMail", e);
			Log
					.severe("Couldn't chmod the script that sends mail. No message was sent.");
			Log.info(file.getAbsolutePath() + " has " + ((file.delete()) ? "" : "not ")
					+ "been deleted");
			return false;
		}
		try {
			p.waitFor();
		} catch (InterruptedException e) {
			Log.exception(this.getClass().getName(), "sendMail", e);
			Log
					.severe("Process that was performing a chmod was interrupted. No message was sent.");
			Log.info(file.getAbsolutePath() + " has " + ((file.delete()) ? "" : "not ")
					+ "been deleted");
			return false;
		}
		try {
			p = Runtime.getRuntime().exec(file.getAbsolutePath());
		} catch (IOException e) {
			Log.exception(this.getClass().getName(), "sendMail", e);
			Log
					.severe("Couldn't execute the script that sends mail. No message was sent.");
			Log.info(file.getAbsolutePath() + " has " + ((file.delete()) ? "" : "not ")
					+ "been deleted");
			return false;
		}
		InputStream stderr = p.getErrorStream();
		InputStreamReader isr = new InputStreamReader(stderr);
		BufferedReader br = new BufferedReader(isr);
		String line = null;
		try {
			while ((line = br.readLine()) != null) {

			}
		} catch (IOException e) {
			Log.exception(this.getClass().getName(), "sendMail", e);
			Log
					.severe("I/O exception while sending mail. Not sure if the message was sent.");
			Log.info(file.getAbsolutePath() + " has " + ((file.delete()) ? "" : "not ")
					+ "been deleted");
			return false;
		}
		try {
			p.waitFor();
		} catch (InterruptedException e) {
			Log.exception(this.getClass().getName(), "sendMail", e);
			Log
					.severe("Process that was sending mail was interrupted. Not sure if the message was sent.");
			Log.info("_script_.sh has " + ((file.delete()) ? "" : "not ")
					+ "been deleted");
			return false;
		}
		
		if (!file.delete())
			Log.info(file.getAbsolutePath() + " has not been deleted" 
					+ newline
					+ "The exit value of the spawned process was : "
					+ p.exitValue() 
					+ newline 
					+ "Message has been sent to "
					+ recipient);
		return true;
	}

	/*
	 * Stop the logger if stand alone (non-Javadoc)
	 * 
	 * @see java.lang.Object#finalize()
	 */
	protected void finalize() throws Throwable {

		if (standAlone)
			Log.stop("Logger stopped by " + this.getClass().getName());
		super.finalize();
	}

	private final String _shellScriptHeader = "#!/bin/sh"
			+ System.getProperty("line.separator");
	
}
