/*******************************************************************************
 * 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.text.DateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Set;

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

import lu.tudor.santec.gecamed.office.ejb.entity.beans.Physician;
import lu.tudor.santec.gecamed.patient.ejb.entity.beans.HospitalPrescription;
import lu.tudor.santec.gecamed.patient.ejb.entity.beans.HospitalPrescriptionPage;
import lu.tudor.santec.gecamed.patient.ejb.entity.beans.HospitalReport;
import lu.tudor.santec.gecamed.patient.ejb.entity.beans.Hospitalisation;
import lu.tudor.santec.gecamed.patient.ejb.entity.beans.HospitalisationPeriod;
import lu.tudor.santec.gecamed.patient.ejb.entity.beans.Passage;
import lu.tudor.santec.gecamed.patient.ejb.entity.interfaces.HospitalisationElement;
import lu.tudor.santec.gecamed.patient.ejb.session.interfaces.HospitalisationBeanInterface;




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

@Stateless
@Remote (HospitalisationBeanInterface.class)
public class HospitalisationBean implements HospitalisationBeanInterface 
	{
	private static final long serialVersionUID = 1L;

	private static final boolean MERGE_ELEMENTS = true;
	
	@PersistenceContext (unitName="gecam")
	EntityManager em;
	
	private HashMap<Integer, Physician> physicians;

//	private static Logger logger = Logger.getLogger(HospitalisationBean.class.getName()); 
	
//***************************************************************************
//* methods for Hospitalisation                                                              *
//***************************************************************************

//	 HospitalisationHistory *****************************************************
	@SuppressWarnings("unchecked")
	public List<HospitalisationElement> getHospitalisationHistory(Integer patientId, Locale locale)
			throws Exception {
		
		
		
		// fetch all physicians
		fetchPhysicians();
		
		List<HospitalisationElement> hospitalisationEntries = new ArrayList<HospitalisationElement>();

		DateFormat dateFormat = DateFormat.getDateTimeInstance(
							DateFormat.SHORT,
							DateFormat.SHORT,
							locale);

		Query q = em.createQuery("SELECT Object(o) FROM Hospitalisation o WHERE o.patientId = :patientId");
		q.setParameter("patientId", patientId);
		
		long start = System.currentTimeMillis();
		
		List<Hospitalisation> result = q.getResultList();
		
//	    logger.info("fetching Hospitalisations for patient from database took "+ (System.currentTimeMillis()-start) + "ms");
	    
		Collections.sort(result, new Comparator() {
			public int compare(Object o1, Object o2) {
				Hospitalisation h1 = (Hospitalisation) o1;
				Hospitalisation h2 = (Hospitalisation) o2;
				try {
					if ((h1.getStartDate() != null) && (h2.getStartDate() == null)) return 1;
					
					if ((h1.getStartDate() == null) && (h2.getStartDate() != null)) return -1;
					
					if ((h1.getStartDate() == null) && (h2.getStartDate() == null)) return 0;
					
					if (h1.getStartDate().before(h2.getStartDate()))
							return 1;
					else if (h2.getStartDate().before(h1.getStartDate()))
							return -1;
					else 
						return 0;
				} catch (Exception e) {
					e.printStackTrace();
				}
				return 0;
			}
		});
		
		if (result != null && result.size() > 0) { // IF Hospitalisations
			/* ------------------------------------------------- */
			for (Hospitalisation hosp : result) { // FOR Hospitalisation
				
				// create a HospitalisationElement for the HOSPITALISATION
				if (hosp.getHospitalisationPeriods() != null) {
					
					//	ADD HOSPITALISATION
					hospitalisationEntries.add(createHospitalisation(hosp, dateFormat));
//				    logger.info("after creation of Hospitalisations entries, "+ (System.currentTimeMillis()-start) + " ms expired since invocation");
					
					//	ADD ACCIDENT
					if (hosp.getIsWorkAccident())
						{
						hospitalisationEntries.add(createAccident(hosp, dateFormat));						
//					    logger.info("after creation of Accident entries, "+ (System.currentTimeMillis()-start) + " ms expired since invocation");
						}
						
						
					//	ADD HOSPITALISATION_PERIODS
					hospitalisationEntries.addAll(createHospitalisationPeriods(hosp, dateFormat));
//				    logger.info("after creation of Hospitalisation Period entries, "+ (System.currentTimeMillis()-start) + " ms expired since invocation");
					
				} // END create a HospitalisationElement for the HOSPITALISATION
			
			} // END FOR Hospitalisation
			
		} // END IF Hospitalisations
				
		return hospitalisationEntries;
	}
	
	
	/* (non-Javadoc)
	 * @see lu.tudor.santec.gecamed.patient.ejb.session.interfaces.HospitalisationBeanInterface#getHospitalPrescription(java.lang.Integer)
	 */
	@SuppressWarnings("unchecked")
	public Collection<HospitalPrescriptionPage> getHospitalPrescriptionPages(Integer id) {
		/* ==================================================== */
		if (id != null) {
			/* ---------------------------------------------- */
			// get the prescription
			Query q = em.createQuery("SELECT Object(o) FROM HospitalPrescriptionPage o " +
					"WHERE o.hospitalPrescriptionId = :id");
			q.setParameter("id", id);
			return q.getResultList ();
			/* ---------------------------------------------- */
		} else
			return null;
		/* ==================================================== */
	}

	
/* (non-Javadoc)
 * @see lu.tudor.santec.gecamed.patient.ejb.session.interfaces.HospitalisationBeanInterface#getPassageById(java.lang.Integer)
 */
public Passage getPassageById (Integer passageId) throws Exception
	{
	Passage l_Passage = null;
	
	try	{
		l_Passage = (Passage) em.createNamedQuery(Passage.FIND_PASSAGE_BY_ID)
					  			.setParameter("id", passageId)
					  			.getSingleResult();
		
//		l_Passage= em.find(Passage.class, passageId);
		}
	catch (NoResultException p_Exception)
		{
		l_Passage = null;
		}
	
	return l_Passage;
	}
	

/* (non-Javadoc)
 * @see lu.tudor.santec.gecamed.patient.ejb.session.interfaces.HospitalisationBeanInterface#getHospitalReport(java.lang.Integer)
 */
public byte[] getHospitalReport(Integer id) {
/* ==================================================== */
if (id != null) {
	/* ---------------------------------------------- */
	// get the report
	Query q = em.createQuery("SELECT Object(o) FROM HospitalReport o " +
			"WHERE o.id = :id");
	q.setParameter("id", id);
	HospitalReport r = (HospitalReport) q.getSingleResult();
	if (r != null) {
		/* ------------------------------------------ */
		return r.getData();
		/* ------------------------------------------ */
	} else 
		return null;
	/* ---------------------------------------------- */
} else
	return null;
/* ==================================================== */
}

//***************************************************************************
//* private Helper methods.....									     											*
//***************************************************************************


	/**
	 * prefetches the doctors to an hashmap
	 */
	private void fetchPhysicians() {
		// fetch doctors
		if (physicians != null)
			return;
		physicians = new HashMap<Integer, Physician>();
		Query q = em.createNamedQuery("findAllPhysician");
		Collection phys = q.getResultList();
		for (Iterator iter = phys.iterator(); iter.hasNext();) {
			Physician p = (Physician) iter.next();
			physicians.put(p.getId(), p);
		}
	}


	
	/**
	 * creates a HospitalisationElement for the given Hospitalisation
	 * @param hosp
	 * @param dateFormat
	 * @return
	 */
	private HospitalisationElement createHospitalisation(Hospitalisation hosp, DateFormat dateFormat) {
		HospitalisationElement entry = new HospitalisationElement(
				hosp.getId(),
				hosp.getStartDate(),
				null,
				"<html><b>No. Admission: " + hosp.getPasID() + "</b>",
				HospitalisationElement.HOSPITALISATION);
		return entry;
	}


	/**
	 * creates a HospitalisationElement of the accident of the given
	 * Hospitalisation
	 * 
	 * @param hosp
	 * @param dateFormat
	 * @return
	 */
	private HospitalisationElement createAccident(Hospitalisation hosp,
			DateFormat dateFormat) {
		StringBuffer accDesc = new StringBuffer();
		if (hosp.getWorkAccidentDate() != null)
			accDesc.append("Date: ").append(dateFormat.format(hosp.getWorkAccidentDate())).append(" ");
		if (hosp.getWorkAccidentNumber() != null)
			accDesc.append("Nr: ").append(hosp.getWorkAccidentNumber());

		HospitalisationElement acc = new HospitalisationElement(hosp.getId(),
				hosp.getStartDate(), null, accDesc.toString(),
				HospitalisationElement.ACCIDENT);
		return acc;
	}


	/**
	 * creates a HospitalisationElements for the HospitalisationPeriods of the
	 * given Hospitalisation
	 * 
	 * @param hosp
	 * @param dateFormat
	 * @return
	 */
	private Collection<HospitalisationElement> createHospitalisationPeriods(
			Hospitalisation hosp, DateFormat dateFormat) {
		
		Set <HospitalisationPeriod>	periods = hosp.getHospitalisationPeriods();
		Collection<HospitalisationElement> elements = new ArrayList<HospitalisationElement>();

		HospitalisationElement previousPeriodElement = null;
		Date previousEndDate = null;
		String previousDepartment = "";
		
		if (periods != null) {
			for (HospitalisationPeriod peri : periods) { 
							
				StringBuffer periodDesc = new StringBuffer();

				periodDesc.append("<html><table border=\"0\" cellpadding=\"2\">"
								+ "<tr vAlign=\"top\">" + "<td>"
								+ "<img src=\":image\">" + "</td>" + "<td>");

				// Start
				if (peri.getStartDate() != null)
					periodDesc.append ("<b>D&eacute;but: </b>").append(dateFormat.format(peri.getStartDate()));

				if (peri.getEndDate() != null)
					periodDesc.append("<b> Fin: </b>").append(dateFormat.format(peri.getEndDate()));
				
				if (peri.getHospitalisationClass() != null)
					periodDesc.append("<br> <b>Classe: </b>").append(peri.getHospitalisationClass().getAcronym());
					
				if (peri.getHospitalDepartment() != null)
					periodDesc.append("<b> Dep: </b>").append(peri.getHospitalDepartment().toString());
					
				if ((peri.getDescription() != null) && (!peri.getDescription().equals("")))
					periodDesc.append("<br><b>Description: </b>").append(peri.getDescription());
				
				periodDesc.append("</td></tr><tr vAlign=\top\"><td colspan=\"2\">");				
				periodDesc.append( "</td></tr></table></html>");

				Integer type = 0;
				if (peri.getHospitalisationClass() == null || peri.getHospitalisationClass().getAcronym() == null) {
					type = HospitalisationElement.HOSPITALISATION_PERIOD_A;
				} else if (peri.getHospitalisationClass().getAcronym().equals("A")) {
					type = HospitalisationElement.HOSPITALISATION_PERIOD_A;
				} else if (peri.getHospitalisationClass().getAcronym().equals(
						"1")) {
					type = HospitalisationElement.HOSPITALISATION_PERIOD_1;
				} else if (peri.getHospitalisationClass().getAcronym().equals(
						"2")) {
					type = HospitalisationElement.HOSPITALISATION_PERIOD_2;
				}

				HospitalisationElement hospPeriod = new HospitalisationElement(
						peri.getId(), peri.getStartDate(), null, periodDesc.toString(), type);
				
				// merge hospitalisation periods
				if (MERGE_ELEMENTS &&
						previousPeriodElement != null && 
						previousPeriodElement.getType() != null &&
						previousPeriodElement.getType().equals(hospPeriod.getType())) {
					
//					System.out.println("\r\n#####################################\r\n" + 
//							"merge: \r\n" + previousPeriodElement + hospPeriod + 
//							"#####################################\r\n");
					
					// set new startdate
					previousPeriodElement.setDate(hospPeriod.getDate());
					StringBuffer newDesc = new StringBuffer();

					newDesc.append("<html><table border=\"0\" cellpadding=\"2\">"
									+ "<tr vAlign=\"top\">" + "<td>"
									+ "<img src=\":image\">" + "</td>" + "<td>");

					// Start
					if(peri.getStartDate() != null)
						newDesc.append("<b>D&eacute;but: </b>").append(dateFormat.format(peri.getStartDate()));
					
					// End
					if(previousEndDate != null)
						newDesc.append("<b> Fin: </b>").append(dateFormat.format(previousEndDate));
						
					// Classe
					if (peri.getHospitalisationClass() != null)
						newDesc.append("<br> <b>Classe: </b>").append(peri.getHospitalisationClass().getAcronym());
		
					if ((peri.getHospitalDepartment() != null) && ! previousDepartment.endsWith(peri.getHospitalDepartment().toString()))
						previousDepartment = peri.getHospitalDepartment().toString() + ", " + previousDepartment;						

					newDesc.append("<b> Dep: </b>").append(previousDepartment);
					
					// Desc.
					if ((peri.getDescription() != null) && (!peri.getDescription().equals("")))
						newDesc.append("<br><b>Description: </b>").append (peri.getDescription());
					
					newDesc.append("</td></tr><tr vAlign=\top\"><td colspan=\"2\">");
					newDesc.append( "</td></tr></table></html>");
					
					previousPeriodElement.setDescription(newDesc.toString());
					
				// last hospclass != curr hospclass
				} else {
					elements.add(hospPeriod);					
					previousPeriodElement = hospPeriod;
				}
				
				previousEndDate = peri.getEndDate();
				try {
					previousDepartment = peri.getHospitalDepartment().toString();					
				} catch (Exception e) {
					previousDepartment = "";
				}

				// ------------------------------------------

				// ADD DIRECT PASSAGES
				elements.addAll(createDirectPassages(peri, dateFormat));

				// ADD ORDERS
				elements.addAll(createOrders(peri, dateFormat));

			} // END FOR HospitalisationPeriod
		} // END create HospitalisationElements for the HOSPITALISATION_PERIOD

		return elements;
	}


	/**
	 * creates a HospitalisationElements for the HospitalisationPrescription of the given HospitalisationPeriod
	 * @param peri
	 * @param dateFormat
	 * @return
	 */
	private Collection<HospitalisationElement> createOrders(
			HospitalisationPeriod peri, DateFormat dateFormat) {
		Collection<HospitalisationElement> elements = new ArrayList<HospitalisationElement>();
		// create HospitalisationElements for the ORDER
		if (peri.getPrescriptions() != null
				&& peri.getPrescriptions().size() > 0) {
			for (HospitalPrescription pres : peri.getPrescriptions()) { // FOR
																		// ORDER
				StringBuffer prescDesc = new StringBuffer();
				prescDesc.append("<html><table border=\"0\" cellpadding=\"2\">"
						+ "<tr vAlign=\"top\">" + "<td>"
						+ "<img src=\":blank\" height=\"16\">" + "</td>"
						+ "<td>" + "<img src=\":image\" >" + "</td>" + "<td>");

				prescDesc.append("<b>");
				if (pres.getDate() != null)
					prescDesc.append(dateFormat.format(pres.getDate()));
				prescDesc.append("</b> No. Ordonnance: ").append(pres.getOrderNumber());

				prescDesc.append("</td></tr></table></html>");
				HospitalisationElement prescription = new HospitalisationElement(
						pres.getId(), pres.getDate(), null, prescDesc.toString(),
						HospitalisationElement.PRESCRIPTION);
				if ((pres.getPages() == null) || (pres.getPages().size() == 0)) {
					prescription.setVerified(false);
				} else {
					prescription.setVerified(true);
				}
				elements.add(prescription);

				/* --------------------------------------------- */

				// ADD PASSAGES
				elements.addAll(createPassages(pres, dateFormat));

				// ADD REPORTS
				elements.addAll(createReports(pres, dateFormat));

			} // END FOR ORDER
		} // END create HospitalisationElements for the ORDER
		return elements;
	}


	/**
	 * creates a HospitalisationElements for the Reports of the given HospitalisationPrescription
	 * @param pres
	 * @param dateFormat
	 * @return
	 */
	private Collection<HospitalisationElement> createReports(HospitalPrescription pres, DateFormat dateFormat) {
		Collection<HospitalisationElement> elements = new ArrayList<HospitalisationElement>();
		for (Iterator iter = pres.getReports().iterator(); iter.hasNext();) {
			HospitalReport rep = (HospitalReport) iter.next();

			StringBuffer repDesc = new StringBuffer();
			repDesc.append("<html><table border=\"0\" cellpadding=\"2\">"
					+ "<tr vAlign=\"top\">" + "<td>"
					+ "<img src=\":blank\" height=\"16\">" + "</td>" + "<td>"
					+ "<img src=\":image\" >" + "</td>" + "<td>");

			if (rep.getDate() != null)
				repDesc.append("<b>").append(dateFormat.format(rep.getDate())).append("</b> ");
			repDesc.append(physicians.get(rep.getInterpreterID()).toString());

			repDesc.append("</td></tr></table></html>");
			HospitalisationElement report = new HospitalisationElement(rep
					.getId(), rep.getDate(), rep.getId(), repDesc.toString(),
					HospitalisationElement.REPORT);
			elements.add(report);

		}
		return elements;
	}


	/**
	 * creates a HospitalisationElements for the Passages of the given HospitalisationPrescription
	 * @param pres
	 * @param dateFormat
	 * @return
	 */
	@SuppressWarnings("unchecked")
	private Collection<HospitalisationElement> createPassages(HospitalPrescription pres, DateFormat dateFormat) {
		Collection<HospitalisationElement> elements = new ArrayList<HospitalisationElement>();
	    Collection<Passage> passages = em.createNamedQuery(Passage.FIND_PASSAGE_BY_HOSPITAL_PPRESCRIPTION_ID)
				.setParameter("hospitalPrescriptionId", pres.getId())
				.getResultList();
		for (Iterator iter = passages.iterator(); iter
				.hasNext();) {
			Passage pas = (Passage) iter.next();
			
			StringBuffer passageDesc = new StringBuffer();
			passageDesc.append("<html><table border=\"0\" cellpadding=\"2\">" +
					"<tr vAlign=\"top\">" +
						"<td>" +
						"<img src=\":blank\" height=\"16\">" +
						"</td>" +
						"<td>" +
						"<img src=\":blank\" height=\"16\">" +
						"</td>" +
						"<td>" +
						"<img src=\":image\" >" +
						"</td>" +
						"<td>"
						);
			passageDesc.append("<b>").append(dateFormat.format(pas.getDate())).append("</b> ")
									 .append(pas.getTreatmentName()).append(" (").append(pas.getTreatUCMCode()).append(")");

			passageDesc.append("</td></tr></table></html>");
				HospitalisationElement passage = new HospitalisationElement(
						pas.getId(),
						pas.getDate(),
						pas.getPhysicianId(),
						passageDesc.toString(),
						HospitalisationElement.PASSAGE);
				passage.setToolTip("Acc. No.: " + pas.getAccessionNumber());
				passage.setVerified(pas.getVerified() != null ? pas.getVerified() : false);
				passage.setRx(pas.getRX() != null ? pas.getRX() : true);
				elements.add(passage);
			
		}
		return elements;
	}


	/**
	 * creates a HospitalisationElements for the PAssages of the given HospitalisationPeriod
	 * @param peri
	 * @param dateFormat
	 * @return
	 */
	private Collection<HospitalisationElement> createDirectPassages(HospitalisationPeriod peri, DateFormat dateFormat) {
		Collection<HospitalisationElement> elements = new ArrayList<HospitalisationElement>();
		if (peri.getPassages() != null && peri.getPassages().size() > 0) {
			for (Passage pas : peri.getPassages()) { // FOR DIRECT PASSAGE
				if (pas.getHospitalPrescriptionId() != null) continue;
				
				StringBuffer passageDesc = new StringBuffer();
				passageDesc.append("<html><table border=\"0\" cellpadding=\"2\">" +
						"<tr vAlign=\"top\">" +
							"<td>" +
								"<img src=\":blank\" height=\"16\">" +
							"</td>" +
							"<td>" +
							"<img src=\":image\" >" +
							"</td>" +
							"<td>"
							);
				
				passageDesc.append("<b>").append(dateFormat.format(pas.getDate())).append("</b> ")
				 .append(pas.getTreatmentName()).append(" (").append(pas.getTreatUCMCode()).append(")");

//				passageDesc.append("<b>" +  dateFormat.format(pas.getDate())+ "</b> " +
//						pas.getTreatmentName()+" ("
//						+pas.getTreatUCMCode()+")" );

				passageDesc.append("</td></tr></table></html>");
					HospitalisationElement passage = new HospitalisationElement(
							pas.getId(),
							pas.getDate(),
							pas.getPhysicianId(),
							passageDesc.toString(),
							HospitalisationElement.PASSAGE);
					passage.setToolTip("Acc. No.: " + pas.getAccessionNumber());
					passage.setVerified(pas.getVerified() != null ? pas.getVerified() : false);
					passage.setRx(pas.getRX() != null ? pas.getRX() : true);
					elements.add(passage);
					
				/* --------------------------------------------- */
			} // END FOR DIRECT PASSAGE
		}
		return elements;
	}


	public void setPassageRx(Integer passageID, Boolean rx) throws Exception {
		em.find(Passage.class, passageID).setRX(rx);
	}

	/* (non-Javadoc)
	 * @see lu.tudor.santec.gecamed.patient.ejb.session.interfaces.HospitalisationBeanInterface#setPassageStatus(java.lang.Integer, java.lang.Boolean)
	 */
	public void setPassageVerified(Integer passageID, Boolean verified) throws Exception {
		em.find(Passage.class, passageID).setVerified(verified);
	}
	

//***************************************************************************
//* End of Class															*
//***************************************************************************
	}
