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

import java.io.Reader;
import java.util.Collection;

import org.apache.abdera.parser.ParseException;

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;

/**
 * An atom deserializer that creates, renames or deletes 
 * contact groups, using data from atom entries.
 * 
 * @author fpicalausa
 *
 */
public class GroupDeserializer {
	private final Contacts contacts;
	private String group;
	private boolean hasGroup;
	
	/**
	 * Construct a new GroupDeserializer interacting with the specified
	 * contact list, and capable of creating a new group or updating 
	 * the one given in parameter.
	 */
	private GroupDeserializer(final Contacts contacts, final String group, boolean hasGroup) {
		super();
		this.contacts = contacts;
		
		if (hasGroup && group == Contacts.GROUP_ALLCONTACTS) {
			throw new IllegalArgumentException("Cannot update the default group");
		}
		else {
			ContactSerializer.checkGroup(group);
		}
		
		this.hasGroup = hasGroup;
		this.group = group;
	}
	
	/**
	 * Construct a new GroupDeserializer interacting with the specified
	 * contact list, and updating the given group.
	 * @param contacts The contact list with which to interact.
	 * @param group The group to be updated. 
	 * @throws NotFoundException if the specified group is not a valid group
	 */
	public GroupDeserializer(final Contacts contacts, final String group) 
		throws NotFoundException {
		this(contacts, group, true);
	}
	
	/**
	 * Construct a new GroupDeserializer interacting with the specified
	 * contact list, and ready to create a new group.
	 * @param group The group to be updated.
	 */
	public GroupDeserializer(final Contacts contacts) {
		this(contacts, Contacts.GROUP_ALLCONTACTS, false);
	}
	
	/**
	 * Returns the group built from information of the given entry,
	 * or as part of the constructor if no update has been issued.
	 * @return the group built from information of the given entry,
	 * or as part of the constructor if no update has been issued.
	 */
	public String getGroup() {
		return group;
	}

	/**
	 * Update the current group or create a new one, 
	 * with the information contained in an atom entry
	 * that can be read from the given reader.
	 * @param data The reader from which the atom entry containing
	 * the new information about the group is to be read.
	 * @throws MalformedRequestException if the given entry is
	 * not correct.
	 */
	public void updateGroup(final Reader data) throws MalformedRequestException {
		String group; 
		try {
			group = AtomHelpers.parseEntry(data).getTitle();
		
			if (group == null || !Contact.validGroupName(group)) {
				throw new MalformedRequestException("Group name cannot be blank");
			}
		}
		catch (ParseException e) {
			throw new MalformedRequestException(e);
		}
		
		if (hasGroup) {
			//Rename the group by removing every contact from the group
			// and moving them to the new group
			for (IdentifiedContact c: destroyGroup()) {
				contacts.addContactToGroup(c, group);
			}
		}
		else {
			//"Create" the group
			this.hasGroup = true;
		}
		this.group = group;
	}
	
	/**
	 * Destroy the current group.
	 * @return The list of contacts that were contained in the current group.
	 */
	public Collection<IdentifiedContact> destroyGroup() {
		Collection<IdentifiedContact> groupContacts = contacts.getContacts(group);
		for (IdentifiedContact c: groupContacts) {
			contacts.removeFromGroup(c, group);
		}
		return groupContacts;
	}
}
