package data;

import java.io.Serializable;

import javax.annotation.PreDestroy;
import javax.ejb.Stateful;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.enterprise.context.Conversation;
import javax.enterprise.context.ConversationScoped;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.component.UIInput;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.inject.Named;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceContextType;

import model.Country;
import model.Person;

/**
 * Implements Gateway, an Adam Bien pattern whose purpose is to expose
 * an Entity (and its relations) to the Client/Web tier, rather like a Seam2 "Home Object"
 * @author Ian Darwin
 */
@Stateful@Named@ConversationScoped
public class PersonHome implements Serializable {

	private static final long serialVersionUID = -2284578724132631798L;

	@Inject Conversation conv;

	// Must be Long (not long) so we can check for null
	private Long id;
	private Person instance = new Person();

	@PersistenceContext(type=PersistenceContextType.EXTENDED) EntityManager em;

	public PersonHome() {
		System.out.println("MemberHome.MemberHome()");
	}

	@TransactionAttribute(TransactionAttributeType.REQUIRED)
	public void wire() {
		if (conv.isTransient()) {
			conv.begin();
		}
		System.out.println("Wire(): " + id);
		if (id == null) {
			instance = new Person();
			return;
		}
		instance = em.find(Person.class, id);
		if (instance == null) {
			System.err.println("Person not found by id! " + id);
		}
	}
	public void wire(Long id) {
		System.out.println("MemberHome.wire(" + id + ")");
		setId(id);
		wire();
	}

	@TransactionAttribute(TransactionAttributeType.REQUIRED)
	public String update() {
		System.out.println("MemberHome.update()");
		em.merge(instance);
		return "PersonList.web";
	}
	
	public void create() {
		// Nothing to do, instance is pre-created
	}

	@TransactionAttribute(TransactionAttributeType.REQUIRED)
	public String save() {
		System.out.println("MemberHome.save()");
		em.persist(instance);
		conv.end();
		return "PersonList.web";
	}

	public void newInstance() {
		System.out.println("MemberHome.newInstance()");
		instance = new Person();
	}

	public Long getId() {
		return id;
	}
	public void setId(Long id) {
		System.out.println("MemberHome.setId(" + id + ")");
		this.id = id;
	}
	
	public Person getInstance() {
		System.out.println("MemberHome.getInstance(): " + instance);
		return instance;
	}
	public void setInstance(Person instance) {
		this.instance = instance;
	}
	
	public String cancel() {
		conv.end();
		return "PersonList";
	}

	public void remove() {
		System.out.println("MemberHome.remove()");
		conv.end();
	}

	@PreDestroy
	public void bfn() {
		System.out.println("MemberHome.bfn()");
	}

	/**
	 * Simple validation of a method in a "home"-type object
	 * that can validate based on related state
	 */
	public void validatePostCode(FacesContext jsfContext,
            UIComponent toValidate, 
            Object userInputValue) {
		
		boolean valid = true;
		String postCode = (String) userInputValue, message = "??";
		Country country = instance.getCountry();
		if (country == null) {
			country = Country.CA;
		}
		switch(country) {
		case CA:
			valid = postCode.matches("\\w\\d\\w ?\\d\\w\\d");
			message = "PostCode must match ANA NAN pattern";
			break;
		case US:
			valid = postCode.matches("\\d{5}(-\\d{4})?");
			message = "Zip Code must be 5 digits, optional -4 digits";
		case ZZ:
			break;
		default:
			throw new IllegalStateException("Unknown country");
		}
		if (!valid) {
			jsfContext.addMessage(
					toValidate.getClientId(jsfContext), 
					new FacesMessage(message));
	        ((UIInput) toValidate).setValid(false);
	        return;
		}
	}
}

@@ -886,14 +886,16 @@
 eful
+ 
 @Named
+ 
 @Con
@@ -961,16 +961,72 @@
 able %7B%0A%0A
+%09private static final String LIST_PAGE = %22PersonList%22;%0A%0A
 %09private
@@ -2012,32 +2012,25 @@
 %09return 
-%22PersonList.web%22
+LIST_PAGE
 ;%0A%09%7D%0A%09%0A%09
@@ -2276,24 +2276,17 @@
 urn 
-%22PersonList.web%22
+LIST_PAGE
 ;%0A%09%7D
@@ -2739,68 +2739,309 @@
 %0A%09%0A%09
-public String cancel() %7B%0A%09%09conv.end();%0A%09%09return %22PersonList%22
+/** Close an editing operation: just end conversation,%0A%09 * return List page.%0A%09 * @return The List Page%0A%09 */%0A%09public String cancel() %7B%0A%09%09conv.end();%0A%09%09return LIST_PAGE;%0A%09%7D%0A%09%0A%09/** Like Cancel but for e.g., View page, no conv end.%0A%09 * @return The List Page%0A%09 */%0A%09public String done() %7B%0A%09%09return LIST_PAGE
 ;%0A%09%7D

Add done() method, just return list page (new constant) to preserve MVC