/*
 * Copyright (c) 2006 - 2007 Aduna.
 * All rights reserved.
 * 
 * Licensed under the Open Software License version 3.0.
 */
package org.semanticdesktop.aperture.extractor.mime;

import java.util.Date;

import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.internet.InternetAddress;

import org.ontoware.rdf2go.exception.ModelException;
import org.ontoware.rdf2go.model.Model;
import org.ontoware.rdf2go.model.node.Literal;
import org.ontoware.rdf2go.model.node.Resource;
import org.ontoware.rdf2go.model.node.URI;
import org.ontoware.rdf2go.vocabulary.RDF;
import org.semanticdesktop.aperture.rdf.RDFContainer;
import org.semanticdesktop.aperture.util.UriUtil;
import org.semanticdesktop.aperture.vocabulary.NCO;
import org.semanticdesktop.aperture.vocabulary.NMO;

/**
 * Utility methods for JavaMail.
 */
public class MailUtil {

	/**
	 * Adds the information about dates pertaining to the given message. In compliance with the previous
     * versions of this method, it adds the current date as the received date of the message if neither
     * the sent date nor the received date are specified.
     * @param message the message
     * @param container the container where the metadata should be stored
	 */
	public static void getDates(Message message, RDFContainer container) throws MessagingException {
		Date sentDate = message.getSentDate();
        if (sentDate != null) {
            container.add(NMO.sentDate, sentDate);
        }
        Date receivedDate = message.getReceivedDate();
        if (receivedDate != null) {
            container.add(NMO.receivedDate, receivedDate);
        }
        if (sentDate == null && receivedDate == null) {
            container.add(NMO.receivedDate, new Date());
        }
	}

	/**
	 * Add statements modeling the specified address metadata to the RDFContainer, using the specified
	 * predicate to connect the address resource to the mail resource.
	 * 
	 * @param address The InternetAddress that will be encoded in the RDF model.
	 * @param predicate The property URI that will be used to connect the address metadata to the mail
	 *            resource.
	 * @param metadata The RDFContainer that will receive the RDF statements and whose described URI is
	 *            expected to represent the mail resource.
	 */
	public static void addAddressMetadata(InternetAddress address, URI predicate, RDFContainer metadata) throws ModelException {
		// fetch the name
		String name = address.getPersonal();
		if (name != null) {
			name = name.trim();
		}

		// fetch the email address
		String emailAddress = address.getAddress();
		if (emailAddress != null) {
			emailAddress = emailAddress.trim();
		}

		// proceed when at least one has a reasonable value
		if (hasRealValue(name) || hasRealValue(emailAddress)) {
			// create a URI for this address
            Model model = metadata.getModel();
			URI contact = model.createURI(getPersonURI(emailAddress, name));

			// connect the person resource to the mail resource
			model.addStatement(contact, RDF.type, NCO.Contact);

			// add name and address details
			if (hasRealValue(name)) {
				Literal literal = metadata.getValueFactory().createLiteral(name);
				model.addStatement(contact, NCO.fullname, literal);
			}

			if (hasRealValue(emailAddress)) {
				Literal literal = metadata.getValueFactory().createLiteral(emailAddress);
                Resource emailResource = UriUtil.generateRandomResource(model);
				model.addStatement(contact, NCO.hasEmailAddress, emailResource);
                model.addStatement(emailResource, RDF.type, NCO.EmailAddress);
                model.addStatement(emailResource, NCO.emailAddress, literal);
			}
            
            metadata.add(predicate, contact);
		}
	}

	/**
	 * Derive a URI for a person based on an email address and a name that can be used in an RDF graph. At
	 * least one of these properties has to have a real value.
	 * 
	 * @param email The email address of the person (optional).
	 * @param name The name of the person (optional).
	 * @return A URI String that can be used to model the person.
	 * @throws IllegalArgumentException when both the email address and the name do not have reasonable
	 *             values.
	 */
	public static String getPersonURI(String email, String name) throws IllegalArgumentException {
		if (hasRealValue(email)) {
			return "email:" + email;
		}
		else if (hasRealValue(name)) {
			return "emailperson:" + name;
		}
		else {
			throw new IllegalArgumentException("no valid email or name, email = " + email + ", name = "
					+ name);
		}
	}

	/**
	 * Determines whether the string is non-null and not equal to an empty string.
	 */
	private static boolean hasRealValue(String string) {
		return string != null && string.length() > 0;
	}
}
