/*******************************************************************************
 * 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.entity.beans;

import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.OrderBy;
import javax.persistence.Table;
import javax.persistence.Transient;

import lu.tudor.santec.gecamed.address.ejb.entity.beans.AddressType;
import lu.tudor.santec.gecamed.core.ejb.entity.beans.GECAMedEntityBean;
import lu.tudor.santec.gecamed.core.ejb.entity.beans.Gender;
import lu.tudor.santec.gecamed.core.ejb.entity.beans.PhoneType;
import lu.tudor.santec.gecamed.core.utils.SSNChecker;
import lu.tudor.santec.i18n.Translatrix;

/**
 * Entity Bean that maps the <b>patient.patient</b> table.
 * represents one single patient with all his administrative data.
 *
 * @version
 * <br>$Log: Patient.java,v $
 * <br>Revision 1.62  2013-10-29 10:04:08  donak
 * <br>Fixed: Unlinked patient records possessed the possibility to upload documents to the DSP, which is impossible
 * <br>Fixed: User will now be informed if client time is out of sync with the server and thus the saml assertion is denied
 * <br>
 * <br>Revision 1.61  2013-07-15 06:18:37  ferring
 * <br>logging changed
 * <br>
 * <br>Revision 1.60  2013-06-10 08:22:09  ferring
 * <br>eSante POC
 * <br>
 * <br>Revision 1.59  2013-05-15 12:56:26  ferring
 * <br>old search string won't be stored in DB any longer. This caused wrong results in the patient search.
 * <br>
 * <br>Revision 1.58  2013-04-09 07:37:29  ferring
 * <br>Patient search unaccented
 * <br>
 * <br>Revision 1.57  2013-03-12 08:37:34  kutscheid
 * <br>export and import a patient's photo and status
 * <br>
 * <br>Revision 1.56  2013-02-12 17:22:14  troth
 * <br>add new function for the MM Export tab to search for patient.
 * <br>
 * <br>Revision 1.55  2012-11-30 15:35:05  ferring
 * <br>mrDeclarationNo added for patient
 * <br>
 * <br>Revision 1.54  2012-11-28 16:30:11  troth
 * <br>New PatientAdminBean function to get patient by over his RIS-Id.
 * <br>
 * <br>Revision 1.53  2012-07-18 07:49:22  ferring
 * <br>SSN constants and formating removed from class SSNField and added to class Patient to give the server access to it
 * <br>
 * <br>Revision 1.52  2012-03-28 12:48:19  ferring
 * <br>Prescription printing now always takes the correct patient, independent of the SSN.
 * <br>
 * <br>Revision 1.51  2012-01-24 14:38:52  ferring
 * <br>Errors and warnings of Jenkins build corrected
 * <br>
 * <br>Revision 1.50  2012-01-24 10:21:44  ferring
 * <br>Native Queries to Named Queries
 * <br>
 * <br>Revision 1.49  2011-09-02 14:11:55  troth
 * <br>Add the new agenda appointment printing for patient function.
 * <br>
 * <br>Revision 1.48  2010-05-18 13:37:01  gbosch
 * <br>changed address handling
 * <br>
 * <br>Revision 1.47  2010-04-27 15:09:43  mack
 * <br>Added patient contact getter and setter
 * <br>
 * <br>Revision 1.46  2010-04-06 15:36:50  hermen
 * <br>added toLogString
 * <br>
 * <br>Revision 1.45  2009-10-01 13:49:13  hermen
 * <br>added physician panel to patient
 * <br>select CNS as default for new patient
 * <br>
 * <br>Revision 1.44  2008-12-22 09:40:12  hermen
 * <br>set default status
 * <br>
 * <br>Revision 1.43  2008-10-21 12:19:59  hermen
 * <br>improved toString/toShortString
 * <br>
 * <br>Revision 1.42  2008-09-25 09:43:06  heinemann
 * <br>fixed copyrights
 * <br>
 * <br>Revision 1.41  2008-08-29 12:57:14  heinemann
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.40  2008-07-18 13:19:51  hermen
 * <br>updated mapping
 * <br>
 * <br>Revision 1.39  2008-07-16 09:08:49  hermen
 * <br>modified toString methods
 * <br>
 * <br>Revision 1.38  2008-01-17 09:19:59  hermen
 * <br>updated Javadoc and refactured code
 * <br>
 *
 */
@javax.persistence.NamedQueries( {
		// findAll NamedQuery
		@NamedQuery(name = "findAllPatient", query = "SELECT OBJECT(o) FROM Patient o"),
		// NamedQueries using Fields.
		//@NamedQuery(name = "findAllPatientByBirthDate", query = "SELECT OBJECT(o) FROM Patient o WHERE o.birthDate = :birthDate"),
		//@NamedQuery(name = "findAllPatientByChildrenNumber", query = "SELECT OBJECT(o) FROM Patient o WHERE o.childrenNumber = :childrenNumber"),
		//@NamedQuery(name = "findAllPatientByCreationDate", query = "SELECT OBJECT(o) FROM Patient o WHERE o.creationDate = :creationDate"),
		//@NamedQuery(name = "findAllPatientByEmail", query = "SELECT OBJECT(o) FROM Patient o WHERE o.email = :email"),
		//@NamedQuery(name = "findAllPatientByFirstName", query = "SELECT OBJECT(o) FROM Patient o WHERE o.firstName = :firstName"),
		//@NamedQuery(name = "findAllPatientByLastModification", query = "SELECT OBJECT(o) FROM Patient o WHERE o.lastModification = :lastModification"),
		//@NamedQuery(name = "findAllPatientByLock", query = "SELECT OBJECT(o) FROM Patient o WHERE o.lock = :lock"),
		//@NamedQuery(name = "findAllPatientByMaidenName", query = "SELECT OBJECT(o) FROM Patient o WHERE o.maidenName = :maidenName"),
		//@NamedQuery(name = "findAllPatientByModifiedBy", query = "SELECT OBJECT(o) FROM Patient o WHERE o.modifiedBy = :modifiedBy"),
		//@NamedQuery(name = "findAllPatientBySocialSecurityNumber", query = "SELECT OBJECT(o) FROM Patient o WHERE o.socialSecurityNumber = :socialSecurityNumber"),
		// @NamedQuery(name = "findAllPatientBySurName", query = "SELECT OBJECT(o) FROM Patient o WHERE o.surName = :surName"),

		// paterns
		@NamedQuery(name = "findPatientBySocialSecurityNumber", query = "SELECT OBJECT(o) FROM Patient o WHERE o.socialSecurityNumber = :socialSecurityNumber"),
		@NamedQuery(name = "findAllPatientBySocialSecurityNumberPattern", query = "SELECT OBJECT(o) FROM Patient o WHERE upper(o.socialSecurityNumber) LIKE upper(:socialSecurityNumber)"),
		@NamedQuery(name = "findAllPatientByPattern", query = "SELECT OBJECT(o) FROM Patient o WHERE (upper(o.maidenName) LIKE upper(:pattern) "
								+ "OR upper(o.surName) LIKE upper(:pattern) OR upper(o.firstName) LIKE upper(:pattern))"),
		@NamedQuery(name = Patient.GET_PATIENT_IDS_WITH_NULL_INCIDENTS, query = "SELECT DISTINCT incident.patientId " 
								+ "FROM Incident incident " 
								+ "LEFT JOIN incident.incidentEntries as entries " 
								+ "WHERE entries.incidentId is null " 
								+ "AND incident.isAccident = false "),
								// + "AND incident.id NOT IN (select incidentId from Prescription)"),
//		@NamedQuery(name = Patient.GET_PATIENTS_WITH_CONSULTATIONS, query = "SELECT DISTINCT OBJECT(o) FROM Patient o, Incident i "
//								+ "WHERE i.patientId = o.id "
//								+ "AND i.consultations.size > 0")
		@NamedQuery(name = Patient.GET_PATIENT_OF_INCIDENT, 
				query = "SELECT OBJECT(p) FROM Patient p, Incident i " +
						"WHERE i.id = :incidentId AND i.patientId = p.id"),
		@NamedQuery(name = Patient.FIND_PATIENT_BY_RISID,
				query = "SELECT OBJECT(o) FROM Patient o WHERE o.idRIS = :risID")
		/* TODO
				@NamedQuery(name = Patient.FIND_PATIENT_TO_EXPORT,
				query = "SELECT OBJECT(o) FROM Patient o WHERE o.id IN (:addPatientsList) OR  ")
		*/
})

@Entity
@Table(name = "patient", schema = "patient")
public class Patient extends GECAMedEntityBean implements Serializable {
	
	private static final long serialVersionUID = 1L;
	
//	public static final String GET_PATIENTS_WITH_CONSULTATIONS_ON_INCIDENTS = "getPatientsWithConsultationsOnIncidents";
	public static final String GET_PATIENT_IDS_WITH_NULL_INCIDENTS 			= "getPatientIDsWithNullIncidents";
//	public static final String GET_PATIENTS_WITH_CONSULTATIONS 				= "getPatientsWithConsultations";
	public static final String GET_PATIENT_OF_INCIDENT 						= "getPatientOfIncident";
	public static final String FIND_PATIENT_BY_RISID		 				= "findPatientByRisID";
	
//	public static final String EMPTY_SOCIAL_SECURITY		= "0000000000000";
	
	public static final int STATUS_NEW 			= 0;
	public static final int STATUS_ACTIVE 		= 1;
	public static final int STATUS_INACTIVE		= 2;
	public static final int STATUS_DEPARTED		= 3;
	public static final String[] STATES = {"NEW", "ACTIVE", "INACTIVE", "DEPARTED"};
	
	public static final String	c_Space					= " ";

	public static final String FIELD_MATRICULE 	= "MATRICULE";
	public static final String FIELD_LASTNAME 	= "LASTNAME";
	public static final String FIELD_FIRSTNAME 	= "FIRSTNAME";
	public static final String FIELD_BIRTHDATE 	= "BIRTHDATE";
	public static final String FIELD_EMAIL 		= "EMAIL";
	public static final String FIELD_MOBILE 	= "MOBILE";
	public static final String FIELD_REASON 	= "REASON";
	
//	private static Pattern c_SSNPattern = Pattern.compile ("^(\\d{4})(\\d{2})(\\d{2})(\\d{3})$",Pattern.CASE_INSENSITIVE);
	
	private String socialSecurityNumber;
	private String firstName;
	
	/**
	 * a.k.a maiden name
	 * TODO refactor to maiden name, after CARA demo!!!
	 */
	private String surName;

	/**
	 * a.k.a. marriage name
	 * TODO refactor to marriage name, after CARA demo!!!
	 */
	private String maidenName;

	private String title;
	private String gender;
	private String nationality;
	private String language;
	private Date birthDate;
	private String birthLocality;
	private String maritalStatus;
	private String email;
	private Integer childrenNumber;
	private String job;
	private String idLuxembourg;
	private String idEuropean;
	private String idFutureNational;
	private String complementaryNo;
	private String idRIS;
	private Date creationDate;
	private Integer doctorID;
	private Integer modifiedBy;
	private Date lastModification;
	private Integer lock;
	private Insurance insurance;
	private Integer insuranceID;
	private InsurancePlan complementary;
	private Integer complementaryID;
	private String	policyNumber;
	private String	otherPhysicians;
	private String	mrDeclarationNo;
//	private String	searchHelper;
	
	private String	storage;
	private String	remarks;
	
	/* ------------------------------------------------------- */
	private Integer spouseId;
	private String spouseName;
	
	private String childrenName;
	private Set<Patient> children;
	
	private String parentName;
	private Set<Patient> parents;
	/* ------------------------------------------------------- */

	private Integer status = STATUS_NEW;

	private Set<PatientFoto> fotos;

	private Set<PatientAddress> address;

	private Set<PatientPhone> phones;

	private Set<PatientContact> contacts;
	
	public Patient() {
		this.gender = Gender.UNKNOWN;
		this.socialSecurityNumber = SSNChecker.EMPTY_SSN_COMPACT;
		this.status = Patient.STATUS_ACTIVE;
	}
	
	public Patient(HashMap<String, String> init) {
		this();
		if (init != null) {
			if (init.containsKey(FIELD_MATRICULE)) {
				setSocialSecurityNumber(init.get(FIELD_MATRICULE));
			}
			if (init.containsKey(FIELD_FIRSTNAME)) {
				setFirstName(init.get(FIELD_FIRSTNAME));
			}
			if (init.containsKey(FIELD_LASTNAME)) {
				setSurName(init.get(FIELD_LASTNAME));
			}
			if (init.containsKey(FIELD_BIRTHDATE)) {
				try {
					Date birthDate = new SimpleDateFormat("yyyyMMdd").parse(init.get(FIELD_BIRTHDATE));
					setBirthDate(birthDate);
					if (!init.containsKey(FIELD_MATRICULE)) {
						setSocialSecurityNumber(init.get(FIELD_BIRTHDATE)+"000000");
					}
				} catch (Exception e) {}
			}
			if (init.containsKey(FIELD_EMAIL)) {
				setEmail(init.get(FIELD_EMAIL));
			}
			if (init.containsKey(FIELD_MOBILE)) {
				try {
					Set<PatientPhone> phones = getPhones();
					if (phones == null) {
						phones = new HashSet<PatientPhone>();
					}
					PatientPhone phone = new PatientPhone();
					phone.setType(PhoneType.MOBILE);
					phone.setNumber(init.get(FIELD_MOBILE));
					phones.add(phone);
					setPhones(phones);
				} catch (Exception e) {
				}
			}
		}
	}

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

//public static String getPrettyFormattedSSN (String p_SSN)
//	{
//	try 
//		{
//		Long.parseLong(p_SSN);
//		if (p_SSN.length() >= 8 && p_SSN.length() <= 11)
//			{
//			return new StringBuilder(14)
//					.append(p_SSN.substring(0, 4))
//					.append(" ")
//					.append(p_SSN.substring(4, 6))
//					.append(" ")
//					.append(p_SSN.substring(6, 8))
//					.append(" ")
//					.append(p_SSN.substring(8))
//					.toString().trim();
//			}
//		}
//	catch (NumberFormatException e) {}
////	catch (Exception e)
////		{
////		logger.log(Level.ERROR, e.getMessage(), e);
////		}
//	
//	return p_SSN;
//	}
	
//---------------------------------------------------------------------------

@Transient
public String formatSocialSecurityNumber ()
	{
	socialSecurityNumber = SSNChecker.getFormattedSSN(socialSecurityNumber, false);
	return socialSecurityNumber;
	}

@Transient
public String formatInsurance ()
{
	if (this.insurance != null)
		return this.insurance.toString();
	else
		return "";
}

//---------------------------------------------------------------------------
/**
 * returns the patient contact,i.e. the person who guarantees to pay for
 * costs incurred by the patient.
 * @return the guarantor for this patient if such a person exists or
 * <code>null</code> if patient covers is or her own costs.
 */
//---------------------------------------------------------------------------

@Transient
public PatientContact getPatientContact ()
	{
	Set<PatientContact> l_Contacts = null;
	Iterator<PatientContact> l_ContactIterator = null;
	PatientContact l_Contact = null;

	l_Contacts = this.getContacts();
    
	if (l_Contacts != null) 
		{
		l_ContactIterator = l_Contacts.iterator();
		if (l_ContactIterator.hasNext()) l_Contact = l_ContactIterator.next();
		}

	return l_Contact;	
	}

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

@Transient
public void setPatientContact (PatientContact p_Contact)
	{
	Set <PatientContact> l_Contacts = null;
	
	if (p_Contact != null)
		{
		l_Contacts = new HashSet <PatientContact> ();
		p_Contact.setPatientId (this.getId());
		l_Contacts.add (p_Contact);
		}
	this.setContacts (l_Contacts);
	}

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

	/**
	 * @return Returns the birthDate.
	 */
	@Column(name = "birth_date")
	public Date getBirthDate() {
		return birthDate;
	}
	/**
	 * @param birthDate The birthDate to set.
	 */
	public void setBirthDate(Date birthDate) {
		this.birthDate = birthDate;
	}
	/**
	 * @return Returns the childrenNumber.
	 */
	@Column(name = "children_number")
	public Integer getChildrenNumber() {
		return childrenNumber;
	}
	/**
	 * @param childrenNumber The childrenNumber to set.
	 */
	public void setChildrenNumber(Integer childrenNumber) {
		this.childrenNumber = childrenNumber;
	}
	/**
	 * @return Returns the creationDate.
	 */
	@Column(name = "creation_date")
	public Date getCreationDate() {
		return creationDate;
	}
	/**
	 * @param creationDate The creationDate to set.
	 */
	public void setCreationDate(Date creationDate) {
		this.creationDate = creationDate;
	}
	/**
	 * @return Returns the doctorID.
	 */
	@Column(name = "doctor_id")
	public Integer getDoctorID() {
		return doctorID;
	}
	/**
	 * @param doctorID The doctorID to set.
	 */
	public void setDoctorID(Integer doctorID) {
		this.doctorID = doctorID;
	}
	/**
	 * @return Returns the email.
	 */
	@Column(name = "email")
	public String getEmail() {
		return email;
	}
	/**
	 * @param email The email to set.
	 */
	public void setEmail(String email) {
		this.email = email;
	}
	/**
	 * @return Returns the firstName.
	 */
	@Column(name = "first_name")
	public String getFirstName() {
		return firstName;
	}
	/**
	 * @param firstName The firstName to set.
	 */
	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}
	/**
	 * @return Returns the gender.
	 */
	@Column(name = "gender")
	public String getGender() {
		return gender;
	}
	/**
	 * @param gender The gender to set.
	 */
	public void setGender(String gender) {
		this.gender = gender;
	}
	/**
	 * @return Returns the idEuropean.
	 */
	@Column(name = "id_european")
	public String getIdEuropean() {
		return idEuropean;
	}
	/**
	 * @param idEuropean The idEuropean to set.
	 */
	public void setIdEuropean(String idEuropean) {
		this.idEuropean = idEuropean;
	}
	/**
	 * @return Returns the idFutureNational.
	 */
	@Column(name = "id_future_national")
	public String getIdFutureNational() {
		return idFutureNational;
	}
	/**
	 * @param idFutureNational The idFutureNational to set.
	 */
	public void setIdFutureNational(String idFutureNational) {
		this.idFutureNational = idFutureNational;
	}
	/**
	 * Provides the eSanté DSP id of the patient if his GECAMed record is linked to a DSP.
	 * @return Returns the eSanté DSP id if the patient is linked to a DSP or null otherwise
	 */
	@Column(name = "id_luxembourg")
	public String getIdLuxembourg() {
		return idLuxembourg;
	}
	/**
	 * @param idLuxembourg The idLuxembourg to set.
	 */
	public void setIdLuxembourg(String idLuxembourg) {
		this.idLuxembourg = idLuxembourg;
	}

	/**
	 * @return Returns the idRIS.
	 */
	@Column(name = "id_ris")
	public String getIdRIS() {
		return idRIS;
	}
	/**
	 * @param idRIS The idRIS to set.
	 */
	public void setIdRIS(String idRIS) {
		this.idRIS = idRIS;
	}

	/**
	 * @return Returns the language.
	 */
	@Column(name = "language")
	public String getLanguage() {
		return language;
	}
	/**
	 * @param language The language to set.
	 */
	public void setLanguage(String language) {
		this.language = language;
	}
	/**
	 * @return Returns the lastModification.
	 */
	@Column(name = "last_modification")
	public Date getLastModification() {
		return lastModification;
	}
	/**
	 * @param lastModification The lastModification to set.
	 */
	public void setLastModification(Date lastModification) {
		this.lastModification = lastModification;
	}
	/**
	 * @return Returns the lock.
	 */
	@Column(name = "lock")
	public Integer getLock() {
		return lock;
	}
	/**
	 * @param lock The lock to set.
	 */
	public void setLock(Integer lock) {
		this.lock = lock;
	}
	/**
	 * @return Returns the maidenName.
	 * a.k.a. marriage name
	 * TODO refactor to marriage name, after CARA demo!!
	 */
	@Column(name = "maiden_name")
	public String getMaidenName() {
		return maidenName;
	}
	/**
	 * @param maidenName The maidenName to set.
	 */
	public void setMaidenName(String maidenName) {
		this.maidenName = maidenName;
	}
	/**
	 * @return Returns the maritalStatus.
	 */
	@Column(name = "marital_status")
	public String getMaritalStatus() {
		return maritalStatus;
	}
	/**
	 * @param maritalStatus The maritalStatus to set.
	 */
	public void setMaritalStatus(String maritalStatus) {
		this.maritalStatus = maritalStatus;
	}
	/**
	 * @return Returns the modifiedBy.
	 */
	@Column(name = "modified_by")
	public Integer getModifiedBy() {
		return modifiedBy;
	}
	/**
	 * @param modifiedBy The modifiedBy to set.
	 */
	public void setModifiedBy(Integer modifiedBy) {
		this.modifiedBy = modifiedBy;
	}
	/**
	 * @return Returns the nationality.
	 */
	@Column(name = "nationality")
	public String getNationality() {
		return nationality;
	}
	/**
	 * @param nationality The nationality to set.
	 */
	public void setNationality(String nationality) {
		this.nationality = nationality;
	}
	/**
	 * @return Returns the socialSecurityNumber.
	 */
	@Column(name = "social_security_number")
	public String getSocialSecurityNumber() {
		return socialSecurityNumber;
	}
	
	/**
	 * Provides the social security number of the patient in the new, 13 digit format
	 * 
	 * @param formatSSN
	 *            Flag that indicates if the the SSN should be formated by separating date, ids, and checksum with spaces
	 * @return The 13 digit social security number (w/ or w/o formatting)
	 */
	@Transient
	public String getSocialSecurityNumber13Digits(boolean formatSSN) {
		return SSNChecker.get13DigitsSSN(getSocialSecurityNumber(), formatSSN);
	}

	/**
	 * @param socialSecurityNumber The socialSecurityNumber to set.
	 */
	public void setSocialSecurityNumber(String socialSecurityNumber) {
		this.socialSecurityNumber = socialSecurityNumber;
	}
	/**
	 * @return Returns the surName.
	 */
	@Column(name = "sur_name")
	public String getSurName() {
		return surName;
	}
	/**
	 * @param surName The surName to set.
	 */
	public void setSurName(String surName) {
		this.surName = surName;
	}
	/**
	 * @return Returns the title.
	 */
	@Column(name = "title")
	public String getTitle() {
		return title;
	}
	/**
	 * @param title The title to set.
	 */
	public void setTitle(String title) {
		this.title = title;
	}

	/**
	 * @return Returns the PatientAddress.
	 */
	@OneToMany(cascade = javax.persistence.CascadeType.ALL, fetch = javax.persistence.FetchType.EAGER)
	@JoinColumn(name = "patient_id")
	@OrderBy("date DESC")
	public Set<PatientAddress> getAddress() {
		return address;
	}

	/**
	 * @param PatientAddress
	 *            The PatientAddress to set.
	 */
	public void setAddress(
			Set<PatientAddress> address) {
		this.address = address;
	}

	/**
	 * @return Returns the Phones.
	 */
	@OneToMany(cascade = javax.persistence.CascadeType.ALL, fetch = javax.persistence.FetchType.EAGER)
	@JoinColumn(name = "patient_id")
	public Set<PatientPhone> getPhones() {
		return phones;
	}

	/**
	 * @param Phones
	 *            The Phones to set.
	 */
	public void setPhones(
			Set<PatientPhone> phones) {
		this.phones = phones;
	}

	/**
	 * @return Returns the contacts.
	 */
	@OneToMany(cascade = javax.persistence.CascadeType.ALL, fetch = javax.persistence.FetchType.EAGER)
	@JoinColumn(name = "patient_id")
	public Set<PatientContact> getContacts() {
		return contacts;
	}
	/**
	 * @param contacts The contacts to set.
	 */
	public void setContacts(Set<PatientContact> contacts) {
		this.contacts = contacts;
	}

	/**
	 * @return Returns the insurance.
	 */
	@ManyToOne
	@JoinColumn(name="insurance_id")
	public Insurance getInsurance() {
		return insurance;
	}
	/**
	 * @param insurance The insurance to set.
	 */
	public void setInsurance(Insurance insurance) {
		this.insurance = insurance;
	}

	/**
	 * @return Returns the insuranceID.
	 */
	@Column(name="insurance_id", updatable=false, insertable=false)
	public Integer getInsuranceID() {
		return insuranceID;
	}

	/**
	 * @param insuranceID The insuranceID to set.
	 */
	public void setInsuranceID(Integer insuranceID) {
		this.insuranceID = insuranceID;
	}


	/**
	 * @return Returns the thirdparty.
	 */
	@ManyToOne
	@JoinColumn(name="complementary_id")
	public InsurancePlan getComplementary() {
		return complementary;
	}
	/**
	 * @param thirdparty The thirdparty to set.
	 */
	public void setComplementary(InsurancePlan thirdparty) {
		this.complementary = thirdparty;
	}

	/**
	 * @return Returns the complementaryID.
	 */
	@Column(name="complementary_id", updatable=false, insertable=false)
	public Integer getComplementaryID() {
		return complementaryID;
	}

	/**
	 * @param complementaryID The complementaryID to set.
	 */
	public void setComplementaryID(Integer complementaryID) {
		this.complementaryID = complementaryID;
	}

	/**
	 * @return The policy number of the complementary insurance plan.
	 */
	@Column(name = "policy_number")
	public String getPolicyNumber() {
		return policyNumber;
	}
	/**
	 * @param policyNumber specifies the policy number to be set
	 */
	public void setPolicyNumber(String policyNumber) {
		this.policyNumber = policyNumber;
	}

	// ---------------------------------------------------
//	/**
//	 * @return Returns the spouse.
//	 */
//	@Column(name="spouse_id", insertable=false, updatable=false, fe)
//	public Patient getSpouse() {
//		return spouse;
//	}
//	/**
//	 * @param spouse The spouse to set.
//	 */
//	public void setSpouse(Patient spouse) {
//		this.spouse = spouse;
//	}

	// ---------------------------------------------------
	/**
	 * @return Returns the spouseId.
	 */
	@Column(name="spouse_id")
	public Integer getSpouseId() {
		return spouseId;
	}
	/**
	 * @param spouseId The spouseId to set.
	 */
	public void setSpouseId(Integer spouseId) {
		this.spouseId = spouseId;
	}

	/**
	 * @return Returns the storage.
	 */
	@Column(name = "storage")
	public String getStorage() {
		return storage;
	}
	/**
	 * @param Storage The storage to set.
	 */
	public void setStorage(String storage) {
		this.storage=storage;
	}
	
	/**
	 * @return Returns the storage.
	 */
	@Column(name = "remarks")
	public String getRemarks() {
		return remarks;
	}
	/**
	 * @param Remarks The remarks to set.
	 */
	public void setRemarks(String remarks) {
		this.remarks=remarks;
	}
	/* *********************************************************
	 * Children
	 */

	@OneToMany(fetch=FetchType.EAGER)
	@JoinTable(name = "patient_relation", schema="patient",
			joinColumns = {@JoinColumn(name="child_id")},
			inverseJoinColumns = {@JoinColumn(name="parent_id")})
	public Set<Patient> getChildren() {
		return children;
	}

	public void setChildren(Set<Patient> children) {
		this.children = children;
	}


	/* *********************************************************
	 * Parents
	 */



	@OneToMany(fetch=FetchType.EAGER)
	@JoinTable(name = "patient_relation", schema="patient",
			joinColumns = {@JoinColumn(name="parent_id")},
			inverseJoinColumns = {@JoinColumn(name="child_id")})
	public Set<Patient> getParents() {
		return parents;
	}

	public void setParents(Set<Patient> parent) {
		this.parents = parent;
	}

	/* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	public String toString() {
		if (this.getSurName() == null && this.getFirstName() == null) {
			return Translatrix.getTranslationString("pm.newPatient");
		}
		try {
			String ssn = getSocialSecurityNumber();
			try {
				ssn = ssn.substring(0, 8) + " " + ssn.substring(8);
			} catch (Exception e) {
			}
			return toShortString() + " (" +ssn + ")";
		} catch (Exception e) {
			return "Patient has no name yet!";
		}
	}

	/**
	 * Returns the patients Name in the form: 
	 * <b>SurName, Firstname
	 * If Surname is Empty the Maindenname is used instead</b>
	 * @return
	 */
	public String toShortString() {
		if (this.getSurName() == null && this.getFirstName() == null) {
			return Translatrix.getTranslationString("pm.newPatient");
		}
		
		StringBuffer sb = new StringBuffer();
		if (this.getSurName() != null && ! this.getSurName().equals(""))
		    sb.append(this.getSurName()+ ", ");
		else if (this.getMaidenName() != null && ! this.getMaidenName().equals(""))
			sb.append(this.getMaidenName() + ", ");
		
		sb.append((this.getFirstName() != null ? this.getFirstName() : ""));
		
		return sb.toString();
	}


	/**
	 * Returns the patient's home address
	 *
	 * @return
	 */
	@Transient
	public PatientAddress getHomeAddress() {
		/* ==================================== */
		if (this.getAddress() == null)
			return null;
		
		List<PatientAddress> homeAddresses = new ArrayList<PatientAddress>();
		// --------------------------------------
		for (PatientAddress adr : this.getAddress()) {
			/* --------------------------------------------- */
			if(adr.getType().equals(AddressType.PRIVATE))
				homeAddresses.add(adr);
			/* --------------------------------------------- */
		}
		if (homeAddresses.size() == 0) {
			for (PatientAddress adr : this.getAddress()) {
				/* --------------------------------------------- */
				if(adr.getType().equals(AddressType.BILLING))
					homeAddresses.add(adr);
				/* --------------------------------------------- */
			}
		}
		if (homeAddresses.size() == 0) {
			for (PatientAddress adr : this.getAddress()) {
				/* --------------------------------------------- */
				if(adr.getType().equals(AddressType.WORK))
					homeAddresses.add(adr);
				/* --------------------------------------------- */
			}
		}
		Collections.sort(homeAddresses);
		// very bad. But there must be an  address.
		// The NullPointer can be catched somewhere else
		try {
			return homeAddresses.get(0);
		} catch (Exception e) {
			return null;
		}
		/* ==================================== */
	}

	/**
	 * Returns the patient's billing address
	 *
	 * @return
	 */
	@Transient
	public PatientAddress getBillingAddress() {
		/* ==================================== */
		if (this.getAddress() == null)
			return null;

		List<PatientAddress> billingAddresses = new ArrayList<PatientAddress>();		
		
		// --------------------------------------
		for (PatientAddress adr : this.getAddress()) {
			/* --------------------------------------------- */
			if(adr.getType().equals(AddressType.BILLING))
				billingAddresses.add(adr);
			/* --------------------------------------------- */
		}
		if (billingAddresses.size() == 0) {
			for (PatientAddress adr : this.getAddress()) {
				/* --------------------------------------------- */
				if(adr.getType().equals(AddressType.PRIVATE))
					billingAddresses.add(adr);
				/* --------------------------------------------- */
			}
		}
		if (billingAddresses.size() == 0) {
			for (PatientAddress adr : this.getAddress()) {
				/* --------------------------------------------- */
				if(adr.getType().equals(AddressType.WORK))
					billingAddresses.add(adr);
				/* --------------------------------------------- */
			}
		}
		Collections.sort(billingAddresses);
		// very bad. But there must be an  address.
		// The NullPointer can be catched somewhere else
		try {
			return billingAddresses.get(0);
		} catch (Exception e) {
			return null;
		}
		/* ==================================== */
	}
	/**
	 * @return Returns the foto.
	 */
	@OneToMany(cascade = javax.persistence.CascadeType.ALL, fetch = javax.persistence.FetchType.EAGER)
	@JoinColumn(name = "patient_id")
	public Set<PatientFoto> getFotos() {
		return fotos;
	}
	/**
	 * @param foto The foto to set.
	 */
	public void setFotos(Set<PatientFoto> fotos) {
		this.fotos = fotos;
	}
	/**
	 * @return Returns the birthLocality.
	 */
	@Column(name = "birth_locality")
	public String getBirthLocality() {
		return birthLocality;
	}
	/**
	 * @param birthLocality The birthLocality to set.
	 */
	public void setBirthLocality(String birthLocality) {
		this.birthLocality = birthLocality;
	}

	/**
	 * @return Returns the status.
	 */
	@Column(name = "status")
	public Integer getStatus() {
		return status;
	}

	/**
	 * @param status The status to set.
	 */
	public void setStatus(Integer status) {
		this.status = status;
	}

	@Transient
	public String getStatusName() {
		try {
			return STATES[getStatus()];
		} catch (Exception e) {
		}
		return "";
	}

	/**
	 * @return Returns the job.
	 */
	@Column(name = "job")
	public String getJob() {
		return this.job;
	}

	/**
	 * @param job The job to set.
	 */
	public void setJob(String job) {
		this.job = job;
	}

	// =======================================================
	// Children name
	// =======================================================
	/**
	 * @return the childrenName
	 */
	@Column(name="children_name")
	public String getChildrenName() {
		return childrenName;
	}

	/**
	 * @param childrenName the childrenName to set
	 */
	public void setChildrenName(String childrenName) {
		this.childrenName = childrenName;
	}
	// =======================================================
	// Parent name
	// =======================================================
	/**
	 * @return the parentName
	 */
	@Column(name="parent_name")
	public String getParentName() {
		return parentName;
	}

	/**
	 * @param parentName the parentName to set
	 */
	public void setParentName(String parentName) {
		this.parentName = parentName;
	}
	// =======================================================
	// Spouse name
	// =======================================================
	/**
	 * @return the spouseName
	 */
	@Column(name="spouse_name")
	public String getSpouseName() {
		return spouseName;
	}

	/**
	 * @param spouseName the spouseName to set
	 */
	public void setSpouseName(String spouseName) {
		this.spouseName = spouseName;
	}
	
	// =======================================================
	// OtherDoctors
	// =======================================================
	/**
	 * @return the patients other physicians
	 */
	@Column(name="other_physicians")
	public String getOtherPhysicians() {
	    return otherPhysicians;
	}
	
	/**
	 * @param otherPhysicians the otherPhysicians to set
	 */
	public void setOtherPhysicians(String otherPhysicians) {
	    this.otherPhysicians = otherPhysicians;
	}
	
	
	/**
	 * @param type use type from PhoneType
	 * @return the phone objectz, null if no number is available
	 */
	public PatientPhone getPhone(String type) {
		/* ================================================== */
    	
    	if (phones != null) {
    		for (PatientPhone p : phones)
    			if (type.equals(p.getType()))
    				return p;
    	}
    	
    	return null;
		/* ================================================== */
	}
	
	
	/**
	 * @return The number for the <i>médecin référent</i> form
	 */
	@Column (name = "mr_declaration_no")
	public String getMrDeclarationNo()
	{
		return mrDeclarationNo;
	}
	
	
	public void setMrDeclarationNo(String mrDeclarationNo)
	{
		this.mrDeclarationNo = mrDeclarationNo;
	}
	
	
	@Column(name = "complementary_insurance_number")
	/**
	 * @return the complementaryInsuranceNumber
	 */
	public String getComplementaryNo ()
	{
		return complementaryNo;
	}
	
	
	/**
	 * @param complementaryInsuranceNumber the complementaryInsuranceNumber to set
	 */
	public void setComplementaryNo (String complementaryInsuranceNumber)
	{
		this.complementaryNo = complementaryInsuranceNumber;
	}
	

//	@Column (insertable = false, updatable = false, name = "search")
//	public String getSearchHelper ()
//	{
//		return searchHelper;
//	}
//	
//	
//	public void setSearchHelper (String searchText) 
//	{
//		this.searchHelper = searchText;
//	}
	
	
	public String toLogString() {
	    return getId() + "; " + getSurName() + ", " + getFirstName() + "; " + getSocialSecurityNumber();
	}
}
