package be.ac.ulb.code.wit.resources.serializers;

import java.io.IOException;
import java.io.Reader;
import java.io.StringWriter;

import javax.xml.namespace.QName;

import org.apache.abdera.Abdera;
import org.apache.abdera.model.Base;
import org.apache.abdera.model.Document;
import org.apache.abdera.model.Element;
import org.apache.abdera.model.Entry;
import org.apache.abdera.parser.ParseException;
import org.apache.abdera.parser.Parser;
import org.apache.commons.lang3.SerializationException;

/**
 * Various helper functions to help building and parsing contact-list specific
 * atompub documents.
 * 
 * @author fpicalausa
 *
 */
public final class AtomHelpers {
	/**
	 * The namespace for our elements and relations
	 */
	public static final String NAMESPACE = "http://www.example.org/code-wit/infoh511/contacts/";
	
	/**
	 * Definition of the name of extension elements used in atom entries
	 */
	public static class ExtensionElements {
		private ExtensionElements() {}
		public static final String PREFIX = "contact";
		public static final String CONTACT_FIRSTNAME = "firstname";
		public static final String CONTACT_LASTNAME = "lastname";
		public static final String CONTACT_EMAIL = "email";
	}

	/**
	 * Definition of the relations used in atom links
	 */
	public static class Relations {
		private Relations() {}
		public static final String GROUP = AtomHelpers.NAMESPACE + "rels#group";
		public static final String GROUP_ITEM = AtomHelpers.NAMESPACE + "rels#group-item";
		public static final String EDIT = "edit";
		public static final String SELF = "self";
	}

	private AtomHelpers() {}
	
	/**
	 * Build a QName object for a given extension element
	 * @param localname The local name of the extension element
	 * @return A QName with the proper namespace and prefix
	 * 		   for an extension element, and the given localname.
	 */
	public static QName getExtensionElementName(final String localname) {
		return new QName(AtomHelpers.NAMESPACE, localname, AtomHelpers.ExtensionElements.PREFIX);
	}
	
	/**
	 * Build a new extension Element with the given localname.
	 * @param localname The local name of the extension element
	 * @return An Element with the proper namespace and prefix
	 * 		   for an extension element, and the given localname.
	 */
	public static Element createExtensionElement(final String localname) {
		return Abdera.getInstance().getFactory()
				.newElement(getExtensionElementName(localname));
	}
	
	/**
	 * Build a new extension Element with the given localname and with
	 * the specified textual contend.
	 * @param localname The local name of the extension element
	 * @param content The textual content of the element
	 * @return An Element with the proper namespace and prefix
	 * 		   for an extension element, the specified localname,
	 * 		   and the specified content.
	 */
	public static Element createExtensionElement(final String localname, final String content) {
		final Element element = createExtensionElement(localname);
		element.setText(content);
		return element;
	}
	
	/**
	 * Extracts the text contained in an extension element of an Atom Entry.
	 * @param entry The atom Entry containing the extension element.
	 * @param localname The name of the extension element whose text is to be retrieved.
	 * @return The text contained in the specified extension element or null if the
	 * 			specified element does not occur.
	 */
	public static String getExtensionElementText(final Entry entry, final String localname) {
		final QName name = getExtensionElementName(localname);
		final Element element = entry.getExtension(name);
		return element == null ? null : element.getText().trim();
	}

	/**
	 * Transforms an Atom Object into a String atom representation. 
	 * @param atomElement The Atom Object to be converted into a String.
	 * @return An Atom compatible String representation of the given Object. 
	 */
	public static String stringify(final Base atomElement) {
		final StringWriter writer = new StringWriter();
		try {
			atomElement.writeTo(writer);
		} catch (IOException e) { 
			throw new SerializationException(e);
		}
		
		return writer.toString();
	}

	/**
	 * Extract an Atom Entry from the given reader. 
	 * @param data The reader on which an Atom entry is to be read and transformed into an Object.
	 * @return An Entry representation of the Atom entry read on the specified reader.
	 */
	public static Entry parseEntry(final Reader data) throws ParseException {
		final Parser parser = Abdera.getInstance().getFactory()
				.newParser();
		final Document<Entry> document = parser.parse(data);
		return document.getRoot();
	}
}
