package org.gcube.portlets.user.speciesdiscovery.server.persistence.dao;

import java.util.List;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;

import org.gcube.common.core.utils.logging.GCUBELog;

public abstract class AbstractPersistence<T> {
	
	protected EntityManagerFactory entityManagerFactory;
	
	public final String AND = "AND";
	
	protected GCUBELog logger = new GCUBELog(AbstractPersistence.class);
	
	AbstractPersistence(EntityManagerFactory factory){
		this.entityManagerFactory = factory;
	}
	/**
	 * 
	 * @param item
	 * @return
	 */
	public boolean insert(T item){
		EntityManager em = createNewManager();
		try {
			
			em.getTransaction().begin();	
			em.persist(item);
			em.getTransaction().commit();
		
		} catch (Exception e) {
			
			logger.error("Error in insert: "+e.getMessage(), e);
		 }
		  finally {
		      if (em.getTransaction().isActive())
		          em.getTransaction().rollback();
		      em.close();
		 }
		
		return true;
	};
	
	
	/**
	 * 
	 * @param item
	 * @return
	 */
	public T update(T item){
		EntityManager em = createNewManager();
		try {

			em.getTransaction().begin();	
			item = em.merge(item);
			em.getTransaction().commit();
			
		} catch (Exception e) {
			logger.error("Error in update: "+e.getMessage(), e);
		 }
		  finally {
		      if (em.getTransaction().isActive())
		          em.getTransaction().rollback();
		      em.close();
		 }
		
		return item;
	}
	
	/**
	 * 
	 * @param item
	 * @return
	 */
	public boolean remove(T item, boolean transaction){
		EntityManager em = createNewManager();
		try {

			if(transaction){
				em.getTransaction().begin();
				em.remove(item);
				em.getTransaction().commit();
			}
			else
				em.remove(item);
		
		} catch (Exception e) {
			logger.error("Error in remove: "+e.getMessage(), e);
		 }
		  finally {
		      if (em.getTransaction().isActive())
		          em.getTransaction().rollback();
		      em.close();
		 }
		
		
		return true;
	}
	
	/**
	 * 
	 * @return
	 */
	public abstract int removeAll();
	
	/**
	 * 
	 * @param filerMap 
	 * @return
	 */
	public abstract List<T> getList();
	
	/**
	 * 
	 * @return
	 */
	public abstract List<T> getList(int startIndex, int offset) throws Exception;
		
	/**
	 * 
	 * @return
	 */
	public abstract int countItems();
	
	/**
	 * 
	 * @param employeeId
	 * @return
	 */
	public abstract T getItemByKey(Integer id);
	/**
	 * 
	 * @param builder
	 * @return
	 */
	public abstract List<T> executeCriteriaQuery(CriteriaQuery<Object> criteriaQuery);
	
	
	/**
	 * 
	 * @return
	 */
	public EntityManagerFactory getEntityManagerFactory() {
		return entityManagerFactory;
	}
	
	/**
	 * 
	 * @return
	 */
	public EntityManager createNewManager(){
		if(entityManagerFactory!=null)
			return entityManagerFactory.createEntityManager();
		
		return null;
	}
	/**
	 * 
	 * @return
	 */
	public abstract CriteriaBuilder getCriteriaBuilder();
	
	
	/**
	 * 
	 * @return
	 */
	public abstract List<T> executeTypedQuery(CriteriaQuery<Object> cq, int startIndex, int offset);
	
	/**
	 * 
	 * @param cq
	 * @return
	 */
	public abstract Root<T> rootFrom(CriteriaQuery<Object> cq);
	
	/**
	 * 
	 * @param filterMap
	 * @param startIndex
	 * @param offset
	 * @return
	 */
	public abstract List<T> getList(Map<String, String> filterMap, int startIndex, int offset);
	

	/**
	 * 
	 * @param idField
	 * @return
	 */
	public abstract int deleteItemByIdField(String idField);
	
	
}
