/**
 * 
 */
package org.yacos.core.users;


import java.util.List;

import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.yacos.core.article.Article;
import org.yacos.core.conferences.Conference;
import org.yacos.core.exceptions.PKAlreadyUsedException;
import org.yacos.core.exceptions.UserEMailAlreadyExistsException;
import org.yacos.core.system.InvitationToken;
import org.yacos.core.system.InvitationTokenPK;
import org.yacos.core.users.Role.RoleType;

/**
 * @author christiancorsano
 *
 */
@Stateless
public class UserManagerBean implements IUserManager{
	@PersistenceContext
	EntityManager em;
	
	@SuppressWarnings("unchecked")
	public List<User> getUsers(){
		Query query = em.createQuery("from User");
		return query.getResultList();
	}
	
	/**
	 * Adds a user into the system 
	 * throw PKAlreadyUsedException if login exist in the DB 
	 * @param user
	 */
	public User addUser(String login, String password, String firstName,
			String lastName, String organization, String email)
				throws PKAlreadyUsedException,UserEMailAlreadyExistsException{
		
		if (!this.exists(login)){
			if(this.getByEmail(email) != null){
				throw new UserEMailAlreadyExistsException(email);
			}
			
			User user = new User(login, password, firstName, lastName, organization, email);
			em.persist(user);
			em.flush();
			
			// Existing InvitationToken handling
			List<InvitationToken> tokens = getInvitationTokensForEmail(user.getEmail());
			for(InvitationToken token : tokens){
				useInvitationTokenOnUser(login, token.getId());
			}
			
			return user;
		}
		else{ throw new PKAlreadyUsedException(); }
	}
	
	/**
	 * Removes a user from the system
	 * @param user
	 */
	public void removeUser(String login){
		User persistedUser = em.find(User.class, login);
		em.remove(persistedUser);
	}

	public User getUser(String login) {
		return em.find(User.class, login);
	}
	
	public User getByEmail(String email){
		try {
			Query query = em.createQuery("from User where email=?");
			query.setParameter(1, email);
			return (User) query.getSingleResult();
		} catch (NoResultException e) {
			return null;
		}
	}
	
	public void UpdateUser(User user){
		em.merge(user);
	}
	
	public Boolean exists(String login){
		return (this.getUser(login)!= null); 
	}

	@SuppressWarnings("unchecked")
	public List<User> getUsers(int conf_id) {
		Query query = em.createQuery("select user from Role role where role.conference = ?");
		Conference conference = em.find(Conference.class, conf_id);
		query.setParameter(1, conference);
		return query.getResultList();
	}

	@SuppressWarnings("unchecked")
	public List<User> getUsers(int conf_id,RoleType type) {
		Query query = em.createQuery("select user from User user, Role role where user.login = role.user and role.type = ? and role.conference = ?)");
		query.setParameter(1, type); 
		Conference conference = em.find(Conference.class, conf_id);
		query.setParameter(2, conference);
		return query.getResultList();
	}
	
	@SuppressWarnings("unchecked")
	public List<User> getPCMemberForArticle(Integer articleId){
		//select p from Paper p join p.referees r where r.login=:aLogin and p.conference=:aConf		
		Query query = em.createQuery("select a.pcMembers from Article a where a.id=?");
		query.setParameter(1, articleId);
		return query.getResultList();
	}

	@SuppressWarnings("unchecked")
	public List<User> getRefereesOFPCMemberForArticle(String PCMemberLogin, Integer articleId){
		Query query = em.createQuery("select user from User user, Articles_referees_map a WHERE a.user_id = user.login and a.article_id = ?");
		query.setParameter(1, articleId);
		query.setParameter(2, PCMemberLogin);
		return query.getResultList();
	}
	
	/*
	 * 
	 * methodes de Roles
	 */
	
	public List<Role> getRoles() {
		// TODO Auto-generated method stub
		return null;
	}

	public void addRoleForConference(String login, RoleType role, Integer conferenceId) {
		User user = em.find(User.class, login);
		Conference conference = em.find(Conference.class, conferenceId);
		
		Role newRole = new Role();
		newRole.setUser(user);
		newRole.setConference(conference);
		newRole.setType(role);
		em.persist(newRole);
	}

	public void removeRole(String userLogin, RoleType roleType, int conferenceId) {
		User user = em.find(User.class, userLogin);
		Conference conference = em.find(Conference.class, conferenceId);
		Role role = em.find(Role.class, new RolePK(user,roleType,conference));
		em.remove(role);
	}
	
	@SuppressWarnings("unchecked")
	public List<InvitationToken> getInvitationTokensForEmail(String email) {
		Query query = em.createQuery("from InvitationToken where email=?");
		query.setParameter(1, email);
		return query.getResultList();
	}

	public void useInvitationTokenOnUser(String userLogin,
			InvitationTokenPK tokenId) {
		InvitationToken token = em.find(InvitationToken.class,tokenId);
		addRoleForConference(userLogin, token.getRole(), token.getConference().getId());
		em.remove(token);
	}

	public boolean hasRoleForConference(String userLogin, RoleType roleType,
			Integer conferenceId) {
		User user = getUser(userLogin);
		Conference conf = em.find(Conference.class, conferenceId);
		RolePK pk = new RolePK(user,roleType,conf);
		Role role = em.find(Role.class, pk);
		return role != null;
	}

	@SuppressWarnings("unchecked")
	public List<Role> getRolesForUser(String userLogin) {
		User user = getUser(userLogin);
		Query aQuery = em.createQuery("from Role where user=?");
		aQuery.setParameter(1, user);
		return aQuery.getResultList();
	}
	
	
}
