package lu.tudor.santec.gecamed.core.ejb.session.beans;

import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import javax.annotation.security.RolesAllowed;
import javax.ejb.Remote;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Transient;

import lu.tudor.santec.gecamed.core.ejb.entity.beans.Autocompletion;
import lu.tudor.santec.gecamed.core.ejb.session.interfaces.AutocompletionInterface;

import org.apache.log4j.Level;
import org.apache.log4j.Logger;

@Remote({AutocompletionInterface.class})
@Stateless
public class AutocompletionBean extends GECAMedSessionBean implements AutocompletionInterface
{
    @PersistenceContext (unitName="gecam")
	EntityManager em;
    
    
    /** the logger Object for this class */
	private static Logger logger = Logger.getLogger(AutocompletionBean.class.getName());
    

	@RolesAllowed("gecam")
	public Autocompletion updateCompletion(Autocompletion autocompletion)
	{
		return em.merge(autocompletion);
	}
	

	@RolesAllowed("gecam")
	public List<Autocompletion> updateCompletions (Collection<Autocompletion> autocompletions)
	{
		List<Autocompletion> 		storedACs;
		List<Autocompletion> 		completionsList;
		Map<String, Autocompletion> completionsMap;
		Map<String, Boolean> 		contextMap;
		String 						hash;
		Boolean 					contextExists;
		int 						importedCompletions  = 0;
		int 						duplicateCompletions = 0;
		int 						errors 				 = 0;
		
		completionsMap 	= new HashMap<String, Autocompletion>();
		contextMap 		= new HashMap<String, Boolean>();
		storedACs 		= new LinkedList<Autocompletion>();
		
		for (Autocompletion ac : autocompletions)
		{
			try
			{
				// check if the completions of this context are already loaded
				contextExists 	= contextMap.get(ac.getContext());
				
				// if the context does not yet exist, load all completions of the context
				if (contextExists == null)
				{
					// get all completions of this context
					completionsList = getCompletions(ac.getContext());
					
					// if the contextList is null or empty, there is no such context stored in the DB ...
					if (completionsList != null)
						for (Autocompletion completion : completionsList)
							completionsMap.put(completion.getHashString(), completion);
					
					// ... mark the context as loaded, anyway.
					contextMap.put(ac.getContext(), Boolean.TRUE);
				}
				
				hash = ac.getHashString();
				if (completionsMap.get(hash) == null)
				{
					// this completion does not yet exist
					ac = em.merge(ac);
					storedACs.add(ac);
					completionsMap.put(hash, ac);
					importedCompletions++;
				}
				else
					duplicateCompletions++;
			}
			catch (Throwable e)
			{
				logger.log(Level.ERROR, e.getMessage(), e);
				errors++;
			}
		}
		
		logger.log(Level.INFO, importedCompletions + " auto completions successfully imported. " +
				duplicateCompletions + " duplicates detected and ignored. " +
				(errors > 0 ? errors + " auto completions couldn't be imported, because of an error." : ""));
		
		return storedACs;
	}
	
	
	@Transient
	public void removeDuplicateEntries ()
	{
		List<Autocompletion> 	completions = getAllCompletions();
		Map<String, Boolean> 	checkMap 	= new HashMap<String, Boolean>();
		String 					hash;
		
		for (Autocompletion ac : completions)
		{
			hash = ac.getHashString();
			if (checkMap.get(hash) == null)
				 checkMap.put(hash, Boolean.TRUE);
			else removeCompletion(ac);
		}
	}
	

	@RolesAllowed("gecam")
	public Autocompletion addCompletion(String context, String inputText,
			String replacementText, Integer userId)
	{
		try {
			Autocompletion ac = new Autocompletion();
			ac.setContext(context);
			ac.setReplacementText(replacementText);
			ac.setInputText(inputText);
			ac.setUserId(userId);
			
			return em.merge(ac);
		} 
		catch (Exception e)
		{
			logError(e);
			return null;
		}
	}
	

	@RolesAllowed("gecam")
	public Autocompletion addCompletion(String context, String replacementText,
			Integer userId)
	{
		return addCompletion(context, null, replacementText, userId);
	}
	

	@RolesAllowed("gecam")
	public boolean removeCompletion(Integer id)
	{
		if (id == null)
		{
//			log(Level.INFO, "The ID of the Autocompletion to remove is NULL!");
			return false;
		}
		
		try {
			em.remove(em.find(Autocompletion.class, id));
			return true;
		} 
		catch (Exception e) 
		{
			logError(e);
			return false;
		}
	}
	

	@RolesAllowed("gecam")
	public boolean removeCompletion(Autocompletion autocompletion)
	{
		if (autocompletion == null)
		{
			log(Level.INFO, "Autocompletion to remove is NULL!");
			return false;
		}
		return removeCompletion(autocompletion.getId());
	}
	

	@SuppressWarnings("unchecked")
	@RolesAllowed("gecam")
	public List<Autocompletion> searchCompletions (String searchText, String context, Integer userId)
	{
		List<Autocompletion> results = null;
		String text = new StringBuffer("%")
				.append(searchText.trim().toUpperCase())
				.append("%").toString();
		
		try {
			results = em.createNamedQuery(Autocompletion.SEARCH_COMPLETIONS)
					.setParameter("userId", 		userId)
					.setParameter("context",		context)
					.setParameter("searchText", 	text)
					.getResultList();
		} 
		catch (Exception e)
		{
			logError(e);
		}
		
		return results;
	}
	
	
	@SuppressWarnings("unchecked")
	@RolesAllowed("gecam")
	public List<String> getContexts()
	{
		try 
		{
			List<String> result = em.createNamedQuery(Autocompletion.GET_CONTEXTS)
					.getResultList();
			return result;
		}
		catch (Exception e)
		{
			logError(e);
			return null;
		}
	}
	
	
	@RolesAllowed("gecam")
	public Autocompletion getCompletion (String inputText, String replacementText, String context, Integer userId)
	{
		Autocompletion	completion = null;
		List<?>			result;
		
		if (inputText != null
				&& inputText.equals(replacementText))
			inputText = null;
		
		try 
		{
			result	= em.createNamedQuery(Autocompletion.GET_SINGLE_COMPLETION)
					.setParameter("userId", 		userId)
					.setParameter("context", 		context)
					.setParameter("inputText", 		inputText)
					.setParameter("replacementText",replacementText)
					.getResultList();
			if (result != null && result.size() > 0)
				completion	= (Autocompletion) result.get(0);
		}
		catch (Exception e)
		{
			logError(e);
		}
		
		return completion;
	}
	

	@SuppressWarnings("unchecked")
	@RolesAllowed("gecam")
	public List<Autocompletion> getCompletions (String context)
	{
		List<Autocompletion> results = null;
		
		try {
			results = em.createNamedQuery(Autocompletion.GET_COMPLETIONS_BY_CONTEXT)
					.setParameter("context", context)
					.getResultList();
		} 
		catch (Exception e)
		{
			logError(e);
		}
		
		return results;
	}
	

	@SuppressWarnings("unchecked")
	@RolesAllowed("gecam")
	public List<Autocompletion> getCompletions(String context, Integer userId)
	{
		List<Autocompletion> results = null;
		
		try {
			results = em.createNamedQuery(Autocompletion.GET_COMPLETIONS_BY_CONTEXT_AND_ID)
					.setParameter("userId",  userId)
					.setParameter("context", context)
					.getResultList();
		} 
		catch (Exception e)
		{
			logError(e);
		}
		
		return results;
	}
	
	
	@SuppressWarnings("unchecked")
	@RolesAllowed("gecam")
	public List<Autocompletion> getAllCompletions ()
	{
		List<Autocompletion> results = null;
		
		try {
			results = em.createNamedQuery(Autocompletion.GET_ALL_COMPLETIONS)
					.getResultList();
		} 
		catch (Exception e)
		{
			logError(e);
		}
		
		return results;
	}
	
	
	private void logError (Exception e)
	{
		log(Level.ERROR, e.getMessage(), e);
	}
}
