package org.hibernate.jpa.test.criteria;

import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.Collections;

import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;

import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
import org.junit.Assert;
import org.junit.Test;


public class InheritedCollectionTestV1 extends BaseEntityManagerFunctionalTestCase {

	@Override
	protected Class<?>[] getAnnotatedClasses() {
		return new Class<?>[] {Role.class, UserBase.class, Customer.class, Supporter.class};
	}
	
	@Test
	public void test1() {
		Role customerRole = createRole("customerLevel1");
		System.out.println("created role:" + customerRole.id);
		Customer c1 = createCustomer("c1", customerRole);
		Customer c2 = createCustomer("c2", customerRole);
		
		List<Customer> resultList = findCustomerByRole(customerRole);
		System.out.println("****resultList=" + resultList);
		Assert.assertTrue(resultList.contains(c1));
		Assert.assertTrue(resultList.contains(c2));
	}
	
	public List<Customer> findCustomerByRole(Role role) {
		EntityManager em = createEntityManager(Collections.emptyMap());
		CriteriaBuilder cb = em.getCriteriaBuilder();
		CriteriaQuery<Customer> cq = cb.createQuery(Customer.class);
		
		// search customer with role
		System.out.println(">>>findCustomerByRole");
		Root<Customer> root = cq.from( Customer.class );
		cq.select(root)
		.where( cb.isMember(role, root.<Set<Role>>get( "roles" )));
		System.out.println("<<<");
		
		TypedQuery<Customer> query = em.createQuery( cq );
		return query.getResultList();
	}
	
	public Customer createCustomer(String name, Role role) {
		EntityManager em = createEntityManager(Collections.emptyMap());
		EntityTransaction tx = em.getTransaction();
		tx.begin();
		
		Customer c = new Customer();
		c.name = name;
		c.companyName = name + ".companyName";
		
		c.roles.add(role);
		
		c = em.merge(c);
		tx.commit();
		return c;
	}
	
	private Role createRole(String name) {
		EntityManager em = createEntityManager(Collections.emptyMap());
		EntityTransaction tx = em.getTransaction();
		tx.begin();
		
		Role r = new Role();
		r.name = name;
		
		r =  em.merge(r);
		tx.commit();
		return r;
	}
	
	@Entity(name="Role")
	public static class Role {
		@Id
		@GeneratedValue
		Integer id;
		
		String name;
		
		protected Role() {
		}
		
		protected Role(String name) {
			this.name = name;
		}
	}

	@Entity(name="UserBase")
	public static class UserBase {
		@Id
		@GeneratedValue
		Integer id;
		
		String name;
				
		@ManyToMany
		Set<Role> roles = new HashSet<Role>();

		@Override
		public int hashCode() {
			final int prime = 31;
			int result = 1;
			result = prime * result + ((id == null) ? 0 : id.hashCode());
			result = prime * result + ((name == null) ? 0 : name.hashCode());
			return result;
		}

		@Override
		public boolean equals(Object obj) {
			if (this == obj)
				return true;
			if (obj == null)
				return false;
			if (getClass() != obj.getClass())
				return false;
			UserBase other = (UserBase) obj;
			if (id == null) {
				if (other.id != null)
					return false;
			} else if (!id.equals(other.id))
				return false;
			if (name == null) {
				if (other.name != null)
					return false;
			} else if (!name.equals(other.name))
				return false;
			return true;
		}

	}
	
	@Entity(name="Customer")
	public static class Customer extends UserBase{
		String companyName;
	}
	
	@Entity(name="Supporter")
	public static class Supporter extends UserBase {
		String productName;
	}
}
