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

import be.ac.ulb.code.wit.contacts.Contact;
import be.ac.ulb.code.wit.contacts.Contacts;
import be.ac.ulb.code.wit.contacts.Contacts.IdentifiedContact;
import be.ac.ulb.code.wit.resources.ServicePaths;
import be.ac.ulb.code.wit.resources.serializers.helpers.ContactSerializer;
import be.ac.ulb.code.wit.resources.serializers.helpers.NotFoundException;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;

public class JsonContactSerializer extends ContactSerializer {
	private final JsonNodeFactory factory = JsonNodeFactory.instance;

	public JsonContactSerializer(Contacts contacts, String group)
			throws NotFoundException {
		super(contacts, group);
	}

	/**
	 * Creates an atom entry representing a contact.
	 * 
	 * @param identifiedContact
	 *            The contact to be serialized as an atom entry.
	 * @param summary
	 *            Whether only a summary of the information (to include into a
	 *            feed) is to be generated.
	 * @return an atom entry representing the given contact.
	 */
	private JsonNode makeEntry(final IdentifiedContact identifiedContact,
			final boolean summary) {
		final ObjectNode root = factory.objectNode();
		final Contact contact = identifiedContact.getContact();
		final String contactId = Integer.toString(identifiedContact
				.getContactId());

		root.put("displayname", contact.getDisplayName());
		root.put("id", ServicePaths.getURI(ServicePaths.CONTACT, "contactid",
				contactId));
		root.put("href", getContactURL(identifiedContact, true, false)
				.toString());
		root.put("canonical-href", getContactURL(identifiedContact, true, true)
				.toString());
		root.put("email", contact.getEmail());
		ArrayNode groups = factory.arrayNode();
		for (String contactGroup : contacts.getContactGroups(identifiedContact)) {
			ObjectNode group = factory.objectNode();

			group.put("group", contactGroup);
			group.put("href", ServicePaths.getURI(ServicePaths.GROUP_CONTACTS,
					true, "group", contactGroup));
			group.put("contact-href",
					getContactURL(identifiedContact, true, contactGroup)
							.toString());

			groups.add(group);
		}
		root.put("groups", groups);

		if (!summary) {
			root.put("firstname", contact.getFirstName());
			root.put("lastname", contact.getLastName());
		}

		return root;
	}

	/**
	 * Make a String representation of a contact, as an atom entry.
	 * 
	 * @param contact
	 *            The contact to be represented as an atom entry.
	 * @return a String representation of the given contact, as an atom entry.
	 */
	@Override
	public String makeStringEntry(IdentifiedContact contact) {
		return JsonHelpers.treeToString(makeEntry(contact, false));
	}

	/**
	 * Creates an atom entry representing a contact as part of a feed
	 */
	private JsonNode makeFeedEntry(IdentifiedContact contact) {
		return makeEntry(contact, true);
	}

	private JsonNode buildGroupFeedNode(ArrayNode contacts) {
		if (group == Contacts.GROUP_ALLCONTACTS)
			return contacts;

		ObjectNode groupRoot = factory.objectNode();
		groupRoot.put("group", group);
		groupRoot.put("contacts", contacts);
		return groupRoot;
	}

	/**
	 * Generates an atom feed containing every contacts in the context group.
	 * 
	 * @return an atom feed containing every contacts in the context group.
	 */
	@Override
	public String makeFeed() {
		final ArrayNode contacts = factory.arrayNode();

		for (IdentifiedContact contact : this.contacts.getContacts(group)) {
			contacts.add(makeFeedEntry(contact));
		}

		return JsonHelpers.treeToString(buildGroupFeedNode(contacts));
	}
}
