/*******************************************************************************
 * 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.prescription.gui.widgets.editor;

import java.sql.Date;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import lu.tudor.santec.gecamed.address.ejb.session.beans.AddressManagerBean;
import lu.tudor.santec.gecamed.address.ejb.session.interfaces.AddressManagerInterface;
import lu.tudor.santec.gecamed.core.ejb.entity.beans.PhoneType;
import lu.tudor.santec.gecamed.core.gui.MainFrame;
import lu.tudor.santec.gecamed.core.gui.utils.IChangeListener;
import lu.tudor.santec.gecamed.core.utils.ManagerFactory;
import lu.tudor.santec.gecamed.core.utils.printing.ireport.UtilFormatter;
import lu.tudor.santec.gecamed.office.ejb.entity.beans.Physician;
import lu.tudor.santec.gecamed.patient.ejb.entity.beans.Incident;
import lu.tudor.santec.gecamed.patient.ejb.entity.beans.Patient;
import lu.tudor.santec.gecamed.prescription.ejb.entity.beans.Prescription;
import lu.tudor.santec.gecamed.prescription.ejb.entity.beans.PrescriptionDrug;
import lu.tudor.santec.gecamed.prescription.ejb.entity.beans.PrescriptionTemplate;
import lu.tudor.santec.gecamed.prescription.ejb.entity.beans.PrescriptionType;
import lu.tudor.santec.gecamed.prescription.ejb.session.beans.PrescriptionManagerBean;
import lu.tudor.santec.gecamed.prescription.ejb.session.interfaces.PrescriptionManager;

import org.apache.log4j.Logger;

/**
 *
 * Model for the prescription editor.
 * It holds one prescription object for each prescription type.
 * New prescriptions are filled with the needed adminstrative data of the patient and the physician.
 *
 * @author martin.heinemann@tudor.lu
 *
 *
 * @version
 * <br>$Log: EditorModel.java,v $
 * <br>Revision 1.17  2013-12-27 18:09:24  donak
 * <br>Cleanup of imports
 * <br>
 * <br>Revision 1.16  2013-07-15 06:18:35  ferring
 * <br>logging changed
 * <br>
 * <br>Revision 1.15  2011-10-05 08:28:59  ferring
 * <br>iReport printing changed. Beans added, only one formatter used for everything and reports changed, so that they only use the bean (util) Parameter
 * <br>
 * <br>Revision 1.14  2010-09-01 12:02:57  troth
 * <br>Incomplete - # 301: Prescription date appears in the accident filed in print out
 * <br>http://santec.tudor.lu/trac/gecamed/ticket/301
 * <br>
 * <br>Revision 1.13  2010-07-19 15:15:35  troth
 * <br>#557: add caisse de maladie to the prescription printout
 * <br>http://santec.tudor.lu/trac/gecamed/ticket/557
 * <br>
 * <br>Revision 1.12  2008-09-25 09:43:08  heinemann
 * <br>fixed copyrights
 * <br>
 * <br>Revision 1.11  2008-09-11 15:06:56  heinemann
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.10  2008-08-21 15:45:12  heinemann
 * <br>removed the bogus behaviour when there is no office entry in the database. The fields on the print outs are now left blank. The user gets an information that the office address is missing.
 * <br>
 * <br>Revision 1.9  2008-07-23 10:00:50  heinemann
 * <br>removed stand_alone column from prescription and prescription_revisions table
 * <br>
 * <br>Revision 1.8  2008-05-29 10:08:20  hermen
 * <br>now uses physician address for printing if set, else office address
 * <br>
 * <br>Revision 1.7  2008-02-11 16:51:50  heinemann
 * <br>moved IChangeListener to core
 * <br>
 * <br>Revision 1.6  2008-01-16 15:33:35  heinemann
 * <br>better documentation
 * <br>
 * <br>Revision 1.5  2007-11-20 08:58:53  hermen
 * <br>moved Managerfactory to core.utils and refactured code to use ManagerFactory instead of context.lookup
 * <br>
 * <br>Revision 1.4  2007/06/18 11:31:36  hermen
 * <br>cleanup of old stuff and moved some beans
 * <br>
 * <br>Revision 1.3  2007/03/12 14:32:10  heinemann
 * <br>Complete - # 46: make printed prescriptions editable
 * <br>http://santec.tudor.lu:8888/gecamed/ticket/46
 * <br>
 * <br>Revision 1.2  2007/03/02 08:28:42  hermen
 * <br>initial checkin after the merge of PatientModuleRebuild with the main HEAD
 * <br>
 * <br>Revision 1.1.2.18  2007/02/08 16:45:11  heinemann
 * <br>many changes
 * <br>
 * <br>Revision 1.1.2.17  2007/01/24 12:48:56  heinemann
 * <br>consultation and prescription update control.
 * <br>Modifications are displayed.
 * <br>And Incidents are not created if nothing has been entered in consultation, accident and prescription
 * <br>
 * <br>Revision 1.1.2.16  2007/01/22 12:21:15  heinemann
 * <br>Complete - # 41: Print empty prescription
 * <br>http://santec.tudor.lu:8888/gecamed/ticket/41
 * <br>Added button to the navi bar
 * <br>
 * <br>Revision 1.1.2.15  2007/01/22 10:24:07  heinemann
 * <br>Incomplete - # 13: print copies of prescriptions
 * <br>http://santec.tudor.lu:8888/gecamed/ticket/13
 * <br>
 * <br>Revision 1.1.2.14  2007/01/11 13:41:06  heinemann
 * <br>Complete - # 21: Context Menu -> create new prescription
 * <br>http://santec.tudor.lu:8888/gecamed/ticket/21
 * <br>
 * <br>Revision 1.1.2.13  2007/01/08 09:31:24  heinemann
 * <br>Add GSM support for prescription
 * <br>
 * <br>Revision 1.1.2.12  2007/01/04 13:51:36  heinemann
 * <br>The great space cleaning lady has done a big bunch of refactoring
 * <br>
 * <br>Revision 1.1.2.11  2007/01/04 12:13:53  heinemann
 * <br>Incomplete - # 22: Save consultation after a prescription was printed does not work
 * <br>http://santec.tudor.lu:8888/gecamed/ticket/22
 * <br>
 * <br>fixed and some other changes like the behaviour of the prescription editor in case of printing and afterwards saving the consultation etc
 * <br>
 * <br>Revision 1.1.2.10  2007/01/03 15:48:12  heinemann
 * <br>prescription was lost, when printing was aborted
 * <br>
 * <br>Revision 1.1.2.9  2006/12/28 10:32:26  heinemann
 * <br>bug fixing and template improvements
 * <br>
 * <br>Revision 1.1.2.8  2006/12/22 07:48:08  heinemann
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.1.2.7  2006/12/21 15:56:06  heinemann
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.1.2.6  2006/12/21 14:49:37  hermen
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.1.2.5  2006/12/21 14:26:43  heinemann
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.1.2.4  2006/12/20 10:07:26  heinemann
 * <br>fixed nullpointer in getModifiedPrescriptions
 * <br>
 * <br>Revision 1.1.2.3  2006/12/19 14:53:05  heinemann
 * <br>printing etc
 * <br>
 * <br>Revision 1.1.2.2  2006/12/15 15:59:11  heinemann
 * <br>presc
 * <br>
 * <br>Revision 1.1.2.1  2006/12/14 09:34:01  heinemann
 * <br>many changes
 * <br>
 */
public class EditorModel {

	/* ********************************************************
	 * Class members
	 */
	private HashMap<String, Prescription> prescriptions
		= new HashMap<String, Prescription>();

	private List<IChangeListener> changeListeners = new ArrayList<IChangeListener>();

	private String currentType;

	private EditorControler controler;
	
	private UtilFormatter formatter = new UtilFormatter((AddressManagerInterface) ManagerFactory.getRemote(AddressManagerBean.class));

	/**
	 *
	 */
	private int modifiedCounter = 0;
	
	/** the logger Object for this class */
	private static Logger logger = Logger.getLogger(EditorModel.class.getName());

	public static List<PrescriptionType> prescriptionTypes;

	/* --------------------------------------------------------
	 * End of Class Members
	 * ********************************************************/

	/**
	 * @param controler
	 */
	public EditorModel(EditorControler controler) {
		/* ====================================================== */
		this.controler = controler;
		try {
			formatter.setReferenceAddress(MainFrame.getCurrentOffice().getLatestOfficeAddress());
		} catch (Exception e) {
		}
		/* ====================================================== */
	}

	/* ********************************************************
	 * methods
	 */

	/**
	 * Switch the prescription type
	 *
	 * @param type
	 */
	public void switchType(String type) {
		/* ====================================================== */
		this.currentType = type;
		fireModelChanged();
		/* ====================================================== */
	}

	/**
	 * clear the data set of the model
	 */
	protected void reset() {
		/* ====================================================== */
		this.prescriptions.clear();
		fireModelChanged();
		modifiedCounter = 0;
		/* ====================================================== */
	}

	/**
	 * Returns the current prescription for the prescription type.
	 * If there is no prescription for the type
	 * a new one will be created
	 *
	 * @return
	 */
	protected Prescription getPrescription() {
		/* ====================================================== */
		if (prescriptions.get(currentType) == null) {
			// create a new prescription
			Prescription p = new Prescription();
			p.setPrescriptionDate(new java.util.Date());
			prescriptions.put(currentType, p);
//			prescriptions.put(currentType, new Prescription());
//			prescriptions.get(currentType).setPrescriptionDate(new java.util.Date());
		}
		return prescriptions.get(currentType);
		/* ====================================================== */
	}


	/**
	 * Set a list of prescriptions to be loaded in the model<br>
	 * The prescriptions must be persistant or must have a type id set!!!
	 * @param presc
	 */
	protected void setPrescriptions(List<Prescription> presc) {
		/* ====================================================== */
		if (presc == null)
			return;
		/* ------------------------------------------------------ */
		for (Prescription p : presc) {
			/* ------------------------------------------------------ */
			this.setPrescription(p);
			/* ------------------------------------------------------ */
		}

		fireModelChanged();
		/* ====================================================== */
	}


	/**
	 * Set one prescription.
	 * Can be used for the return of the save method from the session bean
	 *
	 * @param p
	 */
	protected void setPrescription(Prescription p) {
		/* ====================================================== */
		// try to get the type string for the type id
		if (p != null && p.getPrescriptionTypeId() != null) {
			// add to the hashmap
			this.prescriptions.put(getStringForTypeId(p.getPrescriptionTypeId()),
					p);
		}
		/* ====================================================== */
	}



	/**
	 * @return
	 */
	protected Prescription getCurrentPrescriptionForPrint(Patient patient) {
		/* ====================================================== */
		Prescription p = getFilledPrescription(currentType);
		if (p != null) {
			fillStaticData(p, patient);
		}
		return p;
		/* ====================================================== */
	}


	/**
	 * Get all prescriptions that needs to be saved.
	 *
	 * @return
	 */
	protected List<Prescription> getModifiedPrescriptions(
			Incident incident,
			Patient patient) {
		/* ====================================================== */

		List<Prescription> newPresc = new ArrayList<Prescription>();

		for (String key : prescriptions.keySet()) {
			/* ------------------------------------------------------ */
			Prescription tp = getFilledPrescription(key);
			// if we have a persisted prescription here, ignore it!!
			if (tp != null)
//			&& tp.getId() == null)
				newPresc.add(tp);
			/* ------------------------------------------------------ */
		}
		// add patient and physician data
		for (Prescription p : newPresc) {
			/* ------------------------------------------------------ */
			if (p != null) {
				p.setIncidentId(incident.getId());
				// accident
//				p.setAccidentDate(incident.getAccidentDate());
//				p.setAccidentNr(incident.getAccidentNr());
				fillStaticData(p, patient);
			}
			/* ------------------------------------------------------ */
		}
		return newPresc;
		/* ====================================================== */
	}


	/**
	 * Check the prescription and fill it with the patients and physicians
	 * information
	 *
	 * @param key
	 * @return
	 */
	private Prescription getFilledPrescription(String key) {
		/* ====================================================== */
		if (key.equals(PrescriptionType.MEDICINE)) {
			/* ------------------------------------------------------ */
			// check drugs
			List<PrescriptionDrug> drugs = controler.drugTableModel.getAllDrugs();
			if (drugs != null && drugs.size() > 0) {
				// set the prescription object for each drug
				for (PrescriptionDrug d : drugs) {
					d.setPrescription(prescriptions.get(key));
					// remove the id
					// obsolete, we can edit a prescription that is not printed!
//					d.setId(null);
					// assemble the name by name and form
					if (d.getForm() != null && !"".equals(d.getForm()))
						d.setName(d.getName() + " " + d.getForm());
				}
				/* ------------------------------------------------------ */
				// set the list to the prescription
				prescriptions.get(key).setPrescriptionDrugs(drugs);

				// set the type object
				if (this.getTypeForString(key) != null) {
					prescriptions.get(key).setPrescriptionTypeId(this.getTypeForString(key).getId());
					return prescriptions.get(key);
				}
				else {
					logger.error("Can not set PrescriptionType id for Prescription. type: " + key);
				}
				/* ------------------------------------------------------ */
			}
			/* ------------------------------------------------------ */
		} else {
			/* ------------------------------------------------------ */
			// check the prescriptions
			Prescription p = prescriptions.get(key);
			// if the prescription is empty, continue
			if (p != null)
			if (p.getTextContent() == null || "".equals(p.getTextContent().trim()))
				return null;
			else {
				/* ------------------------------------------------------ */
				// set the type object
				if (this.getTypeForString(key) != null) {
					p.setPrescriptionTypeId(this.getTypeForString(key).getId());
					return p;
				}
				else {
					logger.error("Can not set PrescriptionType id for Prescription. type: " + key);
				}
				/* ------------------------------------------------------ */
			}
			/* ------------------------------------------------------ */
		}
		return null;
		/* ====================================================== */
	}

	/**
	 * Fill the Prescription object with the patients data
	 *
	 * @param p
	 * @param patient
	 * @param standAlone
	 */
	private void fillStaticData(Prescription p, Patient patient) {
		/* ====================================================== */
//		p.setStandAlone(standAlone);

		// physician stuff
		Physician physician = MainFrame.getCurrentPhysician();
		p.setPhysicianId(physician.getId());
		p.setPhysicianFullName(formatter.formatPhysicianName(physician, true));
		p.setPhysicianUcmCode(physician.getUcmCode());
		p.setPhysicianSpeciality(physician.getSpeciality());

		/* ------------------------------------------------------ */
		// adddress
		p.setPhysicianAddress(formatter.formatPhysicianAddress(physician));
		/* ------------------------------------------------------ */
		// phone
		// if the physician has an own phone, take this,
		// if not, take the one from the office
		/* ------------------------------------------------------- */
		if (physician.getPhoneExtension() != null && !physician.getPhoneExtension().equals("")) {
			p.setPhysicianPhone(physician.getPhoneExtension());
		}
		else {
			/* ------------------------------------------------------- */
			try {
				p.setPhysicianPhone(MainFrame.getCurrentOffice()
					.getOfficePhoneByType(PhoneType.HOME).getNumber());
			} catch (Exception e) {
				p.setPhysicianPhone("");
			}
			/* ------------------------------------------------------- */
		}
		/* ------------------------------------------------------- */
		// fax
		/* ------------------------------------------------------- */
		if (physician.getFax() != null	&& !physician.getFax().equals("")) {
			/* ------------------------------------------------------- */
			p.setPhysicianFax(physician.getFax());
			/* ------------------------------------------------------- */
		}
		else {
			/* ------------------------------------------------------- */
			try {
				p.setPhysicianFax(MainFrame.getCurrentOffice()
						.getOfficePhoneByType(PhoneType.FAX).getNumber());
			} catch (Exception e) {
				p.setPhysicianFax("");
			}
			/* ------------------------------------------------------- */
		}
		/* ------------------------------------------------------- */
		//	gsm
		/* ------------------------------------------------------- */
		if (physician.getGsm() != null) {
			p.setPhysicianGsm(physician.getGsm());
		}
		else {
			p.setPhysicianGsm("");
		}

		/* ------------------------------------------------------ */
		// patient
		p.setPatientName(patient.getSurName());
		p.setPatientFirstName(patient.getFirstName());
		p.setPatientMaidenName(patient.getMaidenName());
		p.setPatientAddress(formatter.formatPatientHomeAddress(patient));
		p.setPatientSocialSecurityNumber(patient.getSocialSecurityNumber());
		/* ------------------------------------------------------ */
		/* ====================================================== */
	}

	/**
	 * Set the date of the prescription
	 * @param date
	 */
	protected void setDate(java.util.Date date) {
		/* ====================================================== */
		// try to create a sql date, if not, leave the field empty
		try {
			this.getPrescription().setPrescriptionDate(new Date(date.getTime()));
		} catch (Exception e) {
			// make it empty
			this.getPrescription().setPrescriptionDate(null);
		}
		/* ====================================================== */
	}

	/**
	 * Set the expirydate of the prescription
	 * @param date
	 */
	protected void setExpiryDate(java.util.Date date) {
		/* ====================================================== */
		try {
			this.getPrescription().setExpiryDate(new Date(date.getTime()));
		} catch (Exception e) {
			// make it empty
			this.getPrescription().setExpiryDate(null);
		}
		/* ====================================================== */
	}

	/**
	 * Set the textcontent of a prescription
	 *
	 * @param text
	 */
	protected void setTextContent(String text) {
		/* ====================================================== */
		this.getPrescription().setTextContent(text);
		if ("".equals(text))
			modifiedCounter--;
		else
			modifiedCounter++;
		/* ====================================================== */
	}

	/**
	 * Set the prescription drugs for a prescription.<br/>
	 * Should be used only by the medicine prescription type
	 *
	 * @param drugs
	 */
	protected void setDrugs(List<PrescriptionDrug> drugs) {
		/* ====================================================== */
		this.getPrescription().setPrescriptionDrugs(drugs);
		/* ====================================================== */
	}


	/**
	 * Add a change listener
	 *
	 * @param listener
	 */
	protected void addChangeListener(IChangeListener listener) {
		/* ====================================================== */
		this.changeListeners.add(listener);
		/* ====================================================== */
	}

	/**
	 * Remove a change listener
	 *
	 * @param listener
	 */
	protected void removeChangeListener(IChangeListener listener) {
		/* ====================================================== */
		this.changeListeners.remove(listener);
		/* ====================================================== */
	}

	/**
	 * Add a template to the prescription body
	 *
	 * @param template
	 */
	public void addTemplate(PrescriptionTemplate template) {
		/* ============================================= */
		if (template != null) {
			if (PrescriptionType.MEDICINE.equals(this.currentType)) {
				/* ------------------------------------------------------ */
				// temporal only!
//				this.getPrescription().setTextContent(
//						(this.getPrescription().getTextContent() != null ?
//								this.getPrescription().getTextContent()+"\n"
//								: "")
//						// a new line
//						+ "\n"
//						+ template.getTextContent());
				/* ------------------------------------------------------ */
			} else {
				/* ------------------------------------------------------ */
				
				this.setTextContent(
						(this.getPrescription().getTextContent() != null ?
								this.getPrescription().getTextContent() + "\n"
								: "")

						+ template.getTextContent());
				/* ------------------------------------------------------ */
			}
			fireModelChanged();
		}
		/* ============================================= */
	}

	/**
	 * Returns the isOld flag from the incidentControler.
	 * Is true if an old consultation is going to be opened
	 *
	 * @return
	 */
	public boolean isOld() {
		/* ====================================================== */
		return controler.incidentControler.isOld();
		/* ====================================================== */
	}


	/* --------------------------------------------------------
	 * End of methods
	 * ********************************************************/

	/* ********************************************************
	 * Helper
	 */

	/**
	 * Notify all registered listeners.
	 */
	public void fireModelChanged() {
		/* ====================================================== */
		if (changeListeners != null)
			for (IChangeListener l : changeListeners)
				l.fireEvent();
		/* ====================================================== */
	}


	/**
	 * Get all PrescriptionType objects
	 *
	 * @return
	 */
	public static List<PrescriptionType> getTypes() {
		/* ====================================================== */
			/* ------------------------------------------------------ */
		if (prescriptionTypes == null) {
			/* ------------------------------------------------------ */
			// get the types from the database
			prescriptionTypes = getManager().getPrescriptionTypes();
			/* ------------------------------------------------------ */
		}
			return prescriptionTypes;
			/* ------------------------------------------------------ */
		/* ====================================================== */
	}


	/**
	 * Obtain an instance of the PrescriptionManager SB
	 *
	 * @return
	 */
	public static PrescriptionManager getManager() {
		/* ====================================================== */
		return (PrescriptionManager)
			ManagerFactory.getRemote(PrescriptionManagerBean.class);
		/* ====================================================== */
	}


	/**
	 *
	 * Returns the PrescriptionType object for the given type string
	 *
	 * @param typeString
	 * @return
	 */
	public PrescriptionType getTypeForString(String typeString) {
		/* ====================================================== */
		if (getTypes() != null) {
			/* ------------------------------------------------------ */
			for (PrescriptionType t : getTypes()) {
				if (t.getName().equals(typeString))
					return t;
			}
			/* ------------------------------------------------------ */
		}
		return null;
		/* ====================================================== */
	}


	public static String getStringForTypeId(Integer id) {
		/* ====================================================== */
		if (id == null)
			return null;
		/* ------------------------------------------------------ */
		for (PrescriptionType t : getTypes()) {
			if (t.getId().equals(id))
				return getStaticStringForTypeString(t.getName());
		}
		return null;
		/* ====================================================== */
	}


	/**
	 * get the static type string for a string
	 *
	 * @param str
	 * @return
	 */
	public static String getStaticStringForTypeString(String str) {
		/* ====================================================== */
		if (PrescriptionType.MEDICINE.equals(str))
				return PrescriptionType.MEDICINE;
		else if (PrescriptionType.CERIFICATS.equals(str))
				return PrescriptionType.CERIFICATS;
		else if (PrescriptionType.NURSING.equals(str))
			return PrescriptionType.NURSING;
		else if (PrescriptionType.PHYSIOTHERAPY.equals(str))
			return PrescriptionType.PHYSIOTHERAPY;
		else if (PrescriptionType.RADIOGRAPHY.equals(str))
			return PrescriptionType.RADIOGRAPHY;
		else if (PrescriptionType.TRANSFERALS.equals(str))
			return PrescriptionType.TRANSFERALS;
		else
			return null;
		/* ====================================================== */
	}

	public boolean isModified() {
		/* ====================================================== */
		return (modifiedCounter != 0);
		/* ====================================================== */
	}



	/* --------------------------------------------------------
	 * End of Helper
	 * ********************************************************/
}
