/*******************************************************************************
 * This file is part of GECAMed.
 * 
 * GECAMed is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License (L-GPL) as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * GECAMed is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License (L-GPL)
 * along with GECAMed.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * GECAMed is Copyrighted by the Centre de Recherche Public Henri Tudor (http://www.tudor.lu)
 * (c) CRP Henri Tudor, Luxembourg, 2008
 *******************************************************************************/
package lu.tudor.santec.gecamed.patient.ejb.session.beans;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;

import javax.ejb.EJB;
import javax.ejb.Remote;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import lu.tudor.santec.gecamed.core.ejb.entity.beans.log.LogType;
import lu.tudor.santec.gecamed.patient.ejb.entity.beans.Allergens;
import lu.tudor.santec.gecamed.patient.ejb.entity.beans.Allergies;
import lu.tudor.santec.gecamed.patient.ejb.entity.beans.Antecedents;
import lu.tudor.santec.gecamed.patient.ejb.entity.beans.Incident;
import lu.tudor.santec.gecamed.patient.ejb.entity.beans.IncidentEntry;
import lu.tudor.santec.gecamed.patient.ejb.entity.beans.PatientDatas;
import lu.tudor.santec.gecamed.patient.ejb.session.interfaces.HistoryManager;
import lu.tudor.santec.gecamed.patient.ejb.session.interfaces.IPatientPermissions;
import lu.tudor.santec.gecamed.patient.ejb.session.interfaces.IncidentManager;
import lu.tudor.santec.gecamed.patient.ejb.session.interfaces.PatientAdminInterface;
import lu.tudor.santec.gecamed.patient.utils.PatientUpdateObject;
import lu.tudor.santec.gecamed.usermanagement.ejb.session.interfaces.LoginInterface;
import lu.tudor.santec.gecamed.waitingroom.gui.WaitingroomModule;

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

	//***************************************************************************
	//* Interface Definition and Members                                        *
	//***************************************************************************


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

	    @EJB
	    LoginInterface login;
	    
	    @EJB
	    IncidentManager incidentManager;
	    
	    @EJB
	    PatientAdminInterface patientAdmin;

	//***************************************************************************
	//* Class Body                                                              *
	//***************************************************************************
	//    getAntecedentsByPatientID
	//---------------------------------------------------------------------------
	@SuppressWarnings("unchecked")
	public Collection<Antecedents> getAntecedentsByPatientID (Integer patientID) throws Exception {
		/* ================================================== */
		Collection<Antecedents> 	antecedents = new ArrayList<Antecedents>();

		if (this.login.userHasPermission(IPatientPermissions.VIEW_HISTORY) ||
				this.login.userHasPermission(IPatientPermissions.EDIT_HISTORY)) {
			// fetch all antecedents
			antecedents = em.createNamedQuery ("getAntecedentsByPatientID")
					.setParameter ("patientID", patientID)
					.setParameter("uid", login.getCurrentUserID())
					.getResultList();
			return antecedents;
		}
		// no rights, no antecedents
		return antecedents;
		/* ================================================== */
		}
	//---------------------------------------------------------------------------

	/* (non-Javadoc)
	 * @see lu.tudor.santec.gecamed.patient.ejb.session.interfaces.HistoryInterface#saveAntecedents(lu.tudor.santec.gecamed.patient.ejb.entity.beans.v1.Antecedents)
	 */
	public Antecedents saveAntecedents(Antecedents antecedents) throws Exception {
		antecedents.setCreated(new Date());
		antecedents.setCreatedBy(login.getCurrentUserID());
		return em.merge (antecedents);
	}
	//---------------------------------------------------------------------------

	/* (non-Javadoc)
	 * @see lu.tudor.santec.gecamed.patient.ejb.session.interfaces.HistoryInterface#deleteAntecedents(lu.tudor.santec.gecamed.patient.ejb.entity.beans.v1.Antecedents)
	 */
	public void deleteAntecedents(Antecedents antecedents) throws Exception {
		/* ================================================== */
		if (antecedents.isPersistent()) {
			antecedents.setDeletedDate(new Date());
			antecedents.setDeletedBy(login.getCurrentUserID());
			em.merge(antecedents);
		}
		/* ================================================== */
	}
	//---------------------------------------------------------------------------

	
	
	/**
	 * Get all incidents of the patient. Includes the IncidentEntry objects
	 * for each Incident. Binary content is not loaded.
	 * 
	 * @param patientId
	 * @return
	 */
	public Collection<Incident> getPatientIncidents(Integer patientId) {
		/* ================================================== */
		List<Incident> historyelements = new ArrayList<Incident>();
		/* ------------------------------------------------------- */
		if (patientId == null)
			return historyelements;
		/* ------------------------------------------------------- */
		// check permissions
		/* ------------------------------------------------------- */
		try {
			if (this.login.userHasPermission(IPatientPermissions.VIEW_HISTORY) ||
					this.login.userHasPermission(IPatientPermissions.EDIT_HISTORY) ||
					this.login.userHasPermission(IPatientPermissions.CREATE_PRESCRIPTION)) {
				/* ------------------------------------------------------- */
				return fetchIncidents(patientId);
				/* ------------------------------------------------------- */
			}
		} catch (Exception e) {
			logger.log(Level.ERROR, e.getMessage(), e);
		}
		return historyelements;
		/* ================================================== */
	}
	
	//---------------------------------------------------------------------------

	@SuppressWarnings("unchecked")
	public List<Incident> fetchIncidents(Integer patientID){
		/* ================================================== */
		List<Incident> incidents = new ArrayList<Incident>();
		/* ------------------------------------------------------- */
		if (patientID == null)
			return incidents;
		/* ------------------------------------------------------- */
		try {
			/* --------------------------------------------- */
			List<Incident> l = em.createNamedQuery(Incident.GET_INCIDENTS_BY_PATIENT_ID)
					.setParameter("patientID", patientID)
					.getResultList();
			incidents.addAll(l);
			/* --------------------------------------------- */
		} catch (Exception e) {
			/* --------------------------------------------- */
			logger.log(Level.ERROR, e.getMessage(), e);
			/* --------------------------------------------- */
		}
		for (Incident i : incidents) { 
			try {
				/* --------------------------------------------- */
				for (IncidentEntry ie : i.getIncidentEntries()) {
					ie.getId();
					ie.getEntryType().getId();
					ie.getEntryType().getName();
				}
				/* --------------------------------------------- */
			} catch (Exception e) {
				/* --------------------------------------------- */
				logger.log(Level.ERROR, e.getMessage(), e);
				/* --------------------------------------------- */
			}
		}
		return incidents;
		/* ================================================== */
	}
	
	/* (non-Javadoc)
	 * @see lu.tudor.santec.gecamed.patient.ejb.session.interfaces.HistoryInterface#getPatientDatas(java.lang.Integer)
	 */
	@SuppressWarnings("unchecked")
	public PatientDatas getPatientDatas(Integer patientID) throws Exception
	{
		List<PatientDatas>	data;
		
		
		if (patientID == null)
			return null;
		
		if (this.login.userHasPermission(IPatientPermissions.VIEW_HISTORY) ||
				this.login.userHasPermission(IPatientPermissions.EDIT_HISTORY)) 
		{
			try 
			{
				data = em.createNamedQuery(PatientDatas.GET_DATAS_BY_PATIENTID)
						.setParameter("patientID", patientID)
						.getResultList();
				
				if (data == null || data.isEmpty())
				{
					// there is no patient data for this patient, yet
					return null;
				}
				
				if (data.size() > 1)
				{
					// warn, that there are is more than one patient data
					logger.log(Level.WARN, "There is more than one PatientDatas object for patient " + patientID + ".\n" +
							"Only the latest will be loaded.");
				}
				
				return data.get(0);
			}
			catch (Exception e) 
			{
				logger.log(Level.ERROR, "Error saving important patient data", e);
			}
		}
		return null;
	}


	/* (non-Javadoc)
	 * @see lu.tudor.santec.gecamed.patient.ejb.session.interfaces.HistoryInterface#savePatientDatas(lu.tudor.santec.gecamed.patient.ejb.entity.beans.v1.PatientDatas)
	 */
	public PatientDatas savePatientDatas(PatientDatas data, boolean chronicalTreatmentsChanged, boolean problemActiveChanged) throws Exception {

		PatientDatas loadedData;
		
		
		if (! this.login.userHasPermission(IPatientPermissions.EDIT_HISTORY))
			return null;
		
		if (data.isPersistent() && (chronicalTreatmentsChanged ^ problemActiveChanged))
		{
			// update only those information, that has been changed
			loadedData	= em.find(PatientDatas.class, data.getId());
			
			if (!chronicalTreatmentsChanged)
				data.setChronicalTreatments(loadedData.getChronicalTreatments());
			
			if (!problemActiveChanged)
				data.setActiveProblem(loadedData.getActiveProblem());
		}
		
		return em.merge(data);
	}


	@SuppressWarnings("unchecked")
	public Collection<Allergens> getAllergens() throws Exception {
		return  em.createNamedQuery("getAllergens").getResultList();
	}


	public Vector<Allergies> getAllergies(Integer patientID) throws Exception {
		Vector<Allergies> 	allergies = new Vector<Allergies>();
		if (this.login.userHasPermission(IPatientPermissions.VIEW_HISTORY) ||
				this.login.userHasPermission(IPatientPermissions.EDIT_HISTORY)) {
			// fetch all allergies
			@SuppressWarnings("unchecked")
			List<Allergies> allergyList = em.createNamedQuery ("getAllergiesByPatientID")
					.setParameter ("patientID", patientID)
					.getResultList();
			for (Iterator<Allergies> iter = allergyList.iterator(); iter.hasNext();) {
				Allergies element = (Allergies) iter.next();
				allergies.add(element);
			}
			return allergies;
		}
		// no permissions, no allergies
		return allergies;
	}


	/* (non-Javadoc)
	 * @see lu.tudor.santec.gecamed.patient.ejb.session.interfaces.HistoryManager#saveAllergie(lu.tudor.santec.gecamed.patient.ejb.entity.beans.Allergies)
	 */
	public Allergies saveAllergie(Allergies allergy) throws Exception {
		allergy = em.merge (allergy);
		sentAllergyUpdate(allergy.getPatientId());
		return allergy;
	}

	
	
	private void sentAllergyUpdate(Integer patientId) {
		
		try {
			Vector<Allergies> allergies = getAllergies(patientId);
			StringBuffer desc = new StringBuffer();
			
			for (Allergies allergy : allergies) {
				desc.append(allergy.getCode()).append("=").append(allergy.getAllergenName()).append("\n");
			}
			
			PatientUpdateObject pUpdate = new PatientUpdateObject(
					patientId, 
					"", 
					PatientUpdateObject.STATUS_UPDATED, 
					PatientUpdateObject.C_ALLERGIES, 
					desc.toString());
			
			patientAdmin.sendMessage(pUpdate);
			
		} catch (Exception e) {
			logger.warn("Error sending Allergy Update", e);
		}
		
	}

	/* (non-Javadoc)
	 * @see lu.tudor.santec.gecamed.patient.ejb.session.interfaces.HistoryManager#deleteAllergie(lu.tudor.santec.gecamed.patient.ejb.entity.beans.Allergies)
	 */
	public void deleteAllergie(Allergies allergy) throws Exception {
		if (allergy.isPersistent()) {
			allergy.setDeletionDate(new Date());
			allergy.setDeletedBy(login.getCurrentUserID());
			em.merge(allergy);
			sentAllergyUpdate(allergy.getPatientId());
		}
	}

	/**
	 * @param incident
	 */
	public Incident mergeIncident(Incident incident) {
		/* ================================================== */
		if (incident == null)
			return null;
		/* ------------------------------------------------------- */
		// save
		return em.merge(incident);
		/* ------------------------------------------------------- */

		/* ================================================== */
	}

	/**
	 *  
	 */
	@SuppressWarnings("unchecked")
	public Collection<Incident> getLatestIncident(Integer patientId, int number) {
		/* ====================================================== */
		try {
			/* --------------------------------------------- */
			Query q = em.createQuery("SELECT OBJECT(o) FROM Incident o " +
										"WHERE o.patientId = :patientId " +
										"ORDER BY o.incidentDate DESC");
			q.setParameter("patientId", patientId);
			q.setMaxResults(number);
			return (Collection<Incident>) q.getResultList();
			/* --------------------------------------------- */
		} catch (Exception e) {
			/* --------------------------------------------- */
			logger.log(Level.ERROR, e.getMessage(), e);
			/* --------------------------------------------- */
		}
		return null;
		/* ====================================================== */
	}
	
	
	@SuppressWarnings("unchecked")
	public Collection<Incident> getPatientIncidents(Integer patientId, Calendar startDate, Calendar endDate) {
		/* ====================================================== */
		try {
			// build the query string
			StringBuffer queryString = new StringBuffer(
									"SELECT OBJECT(o) FROM Incident o ")
					.append(		"WHERE o.patientId = :patientId ");
			if (startDate != null)
				queryString.append(	"AND o.incidentDate >= :startDate ");
			if (endDate != null)
				queryString.append(	"AND o.incidentDate <= :endDate ");
			queryString.append(		"ORDER BY o.patientId, o.incidentDate DESC");
			
			// create the query and the set the parameters
			Query query = em.createQuery(queryString.toString());
			if (startDate != null)
				query.setParameter("startDate", startDate.getTime());
			if (endDate != null)
				query.setParameter("endDate", 	endDate.getTime());
//			if (patientId != null)
			query.setParameter("patientId", patientId);
			
			return query.getResultList();
		} 
		catch (Exception e) 
		{
			logger.log(Level.ERROR, e.getMessage(), e);
			return null;
		}
		/* ====================================================== */
	}
	
	
	//***************************************************************************
	//* End of Class															*
	//***************************************************************************
		}
