package lu.tudor.santec.gecamed.importexport.gui.export;

import java.awt.Color;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import javax.ejb.FinderException;
import javax.naming.NamingException;
import javax.xml.namespace.QName;

import lu.gecamed.schemas.ximport.AddressDocument.Address;
import lu.gecamed.schemas.ximport.AddressType;
import lu.gecamed.schemas.ximport.AllergyDocument.Allergy;
import lu.gecamed.schemas.ximport.AntecedentDocument.Antecedent;
import lu.gecamed.schemas.ximport.ChildrenDocument.Children;
import lu.gecamed.schemas.ximport.EntryType;
import lu.gecamed.schemas.ximport.FileEntryDocument;
import lu.gecamed.schemas.ximport.FileEntryDocument.FileEntry;
import lu.gecamed.schemas.ximport.GecamedDataDocument;
import lu.gecamed.schemas.ximport.GecamedDataType;
import lu.gecamed.schemas.ximport.GenderDocument.Gender;
import lu.gecamed.schemas.ximport.GuarantorDocument.Guarantor;
import lu.gecamed.schemas.ximport.IdDocument;
import lu.gecamed.schemas.ximport.IdDocument.Id;
import lu.gecamed.schemas.ximport.MaritalStatusDocument.MaritalStatus;
import lu.gecamed.schemas.ximport.MeasurementDocument.Measurement;
import lu.gecamed.schemas.ximport.MeasurementDocument.Measurement.MeasurementType;
import lu.gecamed.schemas.ximport.MemoDocument.Memo;
import lu.gecamed.schemas.ximport.ParentsDocument.Parents;
import lu.gecamed.schemas.ximport.PatientDocument.Patient;
import lu.gecamed.schemas.ximport.PersonType;
import lu.gecamed.schemas.ximport.PhoneWithTypeType;
import lu.gecamed.schemas.ximport.SettlementDocument.Settlement;
import lu.gecamed.schemas.ximport.StateDocument.State;
import lu.gecamed.schemas.ximport.StatusDocument;
import lu.gecamed.schemas.ximport.StreetDocument.Street;
import lu.gecamed.schemas.ximport.TitleTranslation;
import lu.tudor.santec.gecamed.address.ejb.entity.beans.GECAMedAddressBean;
import lu.tudor.santec.gecamed.billing.ejb.entity.beans.Act;
import lu.tudor.santec.gecamed.billing.ejb.entity.beans.Invoice;
import lu.tudor.santec.gecamed.billing.ejb.session.beans.InvoiceBean;
import lu.tudor.santec.gecamed.billing.ejb.session.interfaces.InvoiceInterface;
import lu.tudor.santec.gecamed.core.gui.plugin.filehandler.FileOpener;
import lu.tudor.santec.gecamed.core.utils.ManagerFactory;
import lu.tudor.santec.gecamed.formeditor.gui.view.FormTab;
import lu.tudor.santec.gecamed.importexport.gui.export.PatientFileNotFoundException.ErrorStates;
import lu.tudor.santec.gecamed.office.ejb.entity.beans.Physician;
import lu.tudor.santec.gecamed.office.ejb.session.beans.OfficeManagerBean;
import lu.tudor.santec.gecamed.office.ejb.session.interfaces.OfficeManagerInterface;
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.IncidentEntryType;
import lu.tudor.santec.gecamed.patient.ejb.entity.beans.MeasurementValue;
import lu.tudor.santec.gecamed.patient.ejb.entity.beans.PatientAddress;
import lu.tudor.santec.gecamed.patient.ejb.entity.beans.PatientContact;
import lu.tudor.santec.gecamed.patient.ejb.entity.beans.PatientDatas;
import lu.tudor.santec.gecamed.patient.ejb.entity.beans.PatientMemo;
import lu.tudor.santec.gecamed.patient.ejb.entity.beans.PatientPhone;
import lu.tudor.santec.gecamed.patient.ejb.session.beans.HistoryManagerBean;
import lu.tudor.santec.gecamed.patient.ejb.session.beans.PatientAdminBean;
import lu.tudor.santec.gecamed.patient.ejb.session.beans.PatientMemoManagerBean;
import lu.tudor.santec.gecamed.patient.ejb.session.interfaces.HistoryManager;
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.ejb.session.interfaces.PatientMemoInterface;
import lu.tudor.santec.gecamed.prescription.ejb.entity.beans.Prescription;
import lu.tudor.santec.gecamed.prescription.ejb.session.beans.PrescriptionManagerBean;
import lu.tudor.santec.gecamed.prescription.ejb.session.interfaces.PrescriptionManager;
import lu.tudor.santec.gecamed.usermanagement.ejb.entity.beans.GecamedUser;
import lu.tudor.santec.gecamed.usermanagement.ejb.session.beans.UserAdminBean;
import lu.tudor.santec.gecamed.usermanagement.ejb.session.interfaces.UserAdminInterface;
import lu.tudor.santec.i18n.Translatrix;

import org.apache.commons.io.FileUtils;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.xmlbeans.XmlCalendar;
import org.apache.xmlbeans.XmlCursor;
import org.apache.xmlbeans.XmlOptions;

public class XMLExporter {
	
	/** the logger Object for this class */
	private static Logger logger = Logger.getLogger(XMLExporter.class.getName());
	
	private static final XmlOptions OPTS = new XmlOptions();
	static {
		// initialize the static XmlOptions
		OPTS.setSavePrettyPrint();
		OPTS.setSaveSuggestedPrefixes(getPrefixes());
		OPTS.setSaveAggressiveNamespaces();
		OPTS.setUseDefaultNamespace();
		OPTS.setCharacterEncoding("UTF-8");
	}

	/**
	 * The predefined namespaces for the xml file. define prefixes in this map
	 * to allow readable or custom ones instead of ns1, ns2 etc
	 */
	private static Map<String, String> prefixes = null;
	/**
	 * The one static instance of OfficeManagerInterface. It will be initialized
	 * when needed. Never use this variable directly, instead use the getter!
	 */
	private static OfficeManagerInterface officeManager = null;
	/**
	 * The one static instance of PatientMemoInterface. It will be initialized
	 * when needed. Never use this variable directly, instead use the getter!
	 */
	private static PatientMemoInterface memoManager = null;
	/**
	 * The one static instance of PrescriptionManager. It will be initialized
	 * when needed. Never use this variable directly, instead use the getter!
	 */
	private static PrescriptionManager prescriptionManager = null;
	/**
	 * The one static instance of HistoryManager. It will be initialized when
	 * needed. Never use this variable directly, instead use the getter!
	 */
	private static HistoryManager historyManager = null;
	/**
	 * The one static instance of InvoiceInterface. It will be initialized when
	 * needed. Never use this variable directly, instead use the getter!
	 */
	private static InvoiceInterface invoiceManager = null;
	/**
	 * The one static instance of PatientAdminInterface. It will be initialized
	 * when needed. Never use this variable directly, instead use the getter!
	 */
	private static PatientAdminInterface patientManager = null;
	/**
	 * The one static instance of UserAdminInterface. It will be initialized
	 * when needed. Never use this variable directly, instead use the getter!
	 */
	private static UserAdminInterface userManager = null;

	// define the bitmask values
	/**
	 * Include simple master data. If {@link #INCLUDE_EXTENDED_MASTER_DATA} is
	 * set this setting has no effect.
	 */
	public static final int INCLUDE_MASTER_DATA = 1;
	/**
	 * Include extended master data. This overrides {@link #INCLUDE_MASTER_DATA}
	 * .
	 */
	public static final int INCLUDE_EXTENDED_MASTER_DATA = 1 << 1;
	/** Include consultations in the export */
	public static final int INCLUDE_CONSULTATIONS = 1 << 2;
	/** Include invoices in the export */
	public static final int INCLUDE_INVOICES = 1 << 3;
	/** Include prescriptions in the export */
	public static final int INCLUDE_PRESCRIPTIONS = 1 << 4;
	/** Include form entries in the export */
	public static final int INCLUDE_FORMS = 1 << 5;
	/** Include the active problems of a patient in the export */
	public static final int INCLUDE_ACTIVE_PROBLEMS = 1 << 6;
	/** Include allergies in the export */
	public static final int INCLUDE_ALLERGIES = 1 << 7;
	/** Include antecedents in the export */
	public static final int INCLUDE_ANTECEDENTS = 1 << 8;
	/** Include chronical treatments in the export */
	public static final int INCLUDE_CHRONICAL_TREATMENTS = 1 << 9;
	/** Include files in the export */
	public static final int INCLUDE_FILE = 1 << 10;
	/** Include letters in the export */
	public static final int INCLUDE_LETTERS = 1 << 11;

	private static final String SUFFIX = ".xml";
	private static final String FILE_FOLDER_NAME = "files";

	/**
	 * Get the prefixes for the XmlOptions
	 * 
	 * @return A map of prefixes for namespaces in the document. Unbound
	 *         namespaces will get ns1, ns2 etc as prefix.
	 */
	private static Map<String, String> getPrefixes() {
		if (prefixes == null) {
			prefixes = new HashMap<String, String>();
			// do not define the import namespace as it should become the
			// default namespace. However it can stay here in a comment as an
			// example
			// prefixes.put("http://gecamed.lu/schemas/import", "import");
		}
		return prefixes;
	} 

	/**
	 * Generate the xml export for a patient
	 * 
	 * @param gecamedPatient
	 *            The patient bean, taken fromthe gecamed database
	 * @param options
	 *            A bitmask made out of the INCLUDE_* constants of this class
	 * @param outputFolder
	 *            The folder to store the generated file into. files that were
	 *            referenced in the given patient will be stored to a subfolder
	 *            called "files"
	 * @return The file containing the generated xml or Null if the file could not be written.
	 * @throws PatientFileNotFoundException If one or more files of this patient could not be found. One exception bundles all missing files.
	 * @throws IllegalArgumentException If the physician for an incident could not be found and the patient did not have a main physician
	 */
	public static File generateXMLForPatient(lu.tudor.santec.gecamed.patient.ejb.entity.beans.Patient gecamedPatient, int options,
			File outputFolder) throws PatientFileNotFoundException, IllegalArgumentException {
		return generateXMLForPatient(gecamedPatient, options, outputFolder, false);
	}
		
		/**
		 * Generate the xml export for a patient
		 * 
		 * @param gecamedPatient
		 *            The patient bean, taken fromthe gecamed database
		 * @param options
		 *            A bitmask made out of the INCLUDE_* constants of this class
		 * @param outputFolder
		 *            The folder to store the generated file into. files that were
		 *            referenced in the given patient will be stored to a subfolder
		 *            called "files"
		 * @param force True if the export should be forced, ignoring errors
		 * @return The file containing the generated xml or Null if the file could not be written.
		 * @throws PatientFileNotFoundException If one or more files of this patient could not be found. One exception bundles all missing files.
		 * @throws IllegalArgumentException If the physician for an incident could not be found and the patient did not have a main physician
		 */
		public static File generateXMLForPatient(lu.tudor.santec.gecamed.patient.ejb.entity.beans.Patient gecamedPatient, int options,
				File outputFolder, boolean force) throws PatientFileNotFoundException, IllegalArgumentException {
		// create a new gecamed document
		if (!outputFolder.exists() || !outputFolder.isDirectory()) {
			throw new IllegalArgumentException("The given file object must be a folder");
		}
		GecamedDataDocument document = GecamedDataDocument.Factory.newInstance();
		GecamedDataType gecamedData = document.addNewGecamedData();
		storePatient(gecamedPatient, gecamedData, options, outputFolder, force);
		// add a schemalocation
		XmlCursor newCursor = document.newCursor();
		if (newCursor.toFirstChild()) {
			newCursor.setAttributeText(new QName("http://www.w3.org/2001/XMLSchema-instance", "schemaLocation"),
					"http://gecamed.lu/_media/download/xml_schema/gecameddata.xsd");
		}
		// physicians will be added as needed during the parsing of the patient
		try {
			File outputFile = new File(outputFolder.getAbsolutePath() + File.separatorChar + getPatientIdentifier(gecamedPatient) + SUFFIX);
			document.save(outputFile,
					OPTS);
			return outputFile;
		} catch (IOException e) {
			logger.error("Error while trying to create export file of patient " + gecamedPatient.toLogString(), e);
		}
		return null;
	}

	/**
	 * Add a patient to the given gecamedData element
	 * 
	 * @param gecamedPatient
	 *            The patient to be added
	 * @param options
	 *            A bitmask made out of the INCLUDE_* constants of this class
	 * @param gecamedData
	 *            The gecamedData to contain the patient
	 * @param outputFolder
	 *            The folder to store the generated file into. files that were
	 *            referenced in the given patient will be stored to a subfolder
	 *            called "files"
	 * @param force True if the export should be forced, ignoring errors
	 * @throws PatientFileNotFoundException If one or more files of this patient could not be found. One exception bundles all missing files.
	 * @throws IllegalArgumentException If the physician for an Incident could not be found ant the patient does not have a physician for himself.
	 */
	private static void storePatient(lu.tudor.santec.gecamed.patient.ejb.entity.beans.Patient gecamedPatient, GecamedDataType gecamedData,
			int options, File outputFolder, boolean force) throws PatientFileNotFoundException, IllegalArgumentException {
		Patient patient = gecamedData.addNewPatient();
		// set the data of the gecamedPatient to the new patient, starting with
		// the main data
		if ((options & INCLUDE_EXTENDED_MASTER_DATA) > 0) {
			addExtendedMasterDataToPatient(patient, gecamedPatient);
		} else if ((options & INCLUDE_MASTER_DATA) > 0) {
			addMasterDataToPatient(patient, gecamedPatient);
		}
		// add allergies
		if ((options & INCLUDE_ALLERGIES) > 0) {
			try {
				Vector<Allergies> patientAllergies = getHistoryManager().getAllergies(gecamedPatient.getId());
				for (Allergies patientAllergy : patientAllergies) {
					if (checkForValue(patientAllergy.getAllergenName())) {
						Allergy newAllergy = patient.addNewAllergy();
						newAllergy.setAllergen(patientAllergy.getAllergenName());
						if (checkForValue(patientAllergy.getComment())) {
							newAllergy.setComment(patientAllergy.getComment());
						}
					} else {
						logger.warn("Empty allergy found for patient " + gecamedPatient.toLogString() 
								+ ". Allergy will not be exported.");
					}
				}
			} catch (Exception e) {
				logger.error("Error while trying to export allergies of patient " + gecamedPatient.toLogString(), e);
			}
		}
		if ((options & INCLUDE_ANTECEDENTS) > 0) {
			// add antecedents
			try {
				Collection<Antecedents> gecamedAntecedents = getHistoryManager().getAntecedentsByPatientID(gecamedPatient.getId());
				for (Antecedents antecedent : gecamedAntecedents) {
					Antecedent newAntecedent = patient.addNewAntecedent();
					if (checkForValue(antecedent.getShortcut())) {
						newAntecedent.setAntecedentTitle(antecedent.getShortcut());
					} else {
						newAntecedent.setAntecedentTitle("");
					}
					if (checkForValue(antecedent.getDescription())) {
						newAntecedent.setDescription(antecedent.getDescription());
					} else {
						newAntecedent.setDescription("");
					}
				}
			} catch (Exception e) {
				logger.error("Error while trying to export antecedents of patient " + gecamedPatient.toLogString(), e);
			}
		}
		// add incidents
		Collection<Incident> incidents = new ArrayList<Incident>(getHistoryManager().getPatientIncidents(gecamedPatient.getId()));
		// TODO remove!
//		Collections.sort((List<Incident>) incidents, new Comparator<Incident>() {
//			public int compare(Incident o1, Incident o2) {
//				return o1.getId().compareTo(o2.getId());
//			}
//		});
		if (checkForValue(incidents)) {
			//remember the failed files
			Map<String, ErrorStates> fileErrors = new HashMap<String, ErrorStates>();
			File filesFolder = new File(outputFolder.getAbsolutePath() + File.separatorChar + FILE_FOLDER_NAME + File.separatorChar + getPatientIdentifier(gecamedPatient));
			for (Incident incident : incidents) {
				
				lu.gecamed.schemas.ximport.IncidentDocument.Incident newIncident = null;
//				lu.gecamed.schemas.ximport.IncidentDocument.Incident newIncident = patient.addNewIncident();
				// TODO Incident creation later
//				// set the basic information to the incident
//				if (checkForValue(incident.getParentAccidentIncidentId())) {
//					// store the ID of the parent incident
//					if (checkForValue(incident.getParentAccidentIncidentId())) {
//						newIncident.setAccidentParentId(incident.getParentAccidentIncidentId().toString());
//					}
//				} else {
//					if (checkForValue(incident.getAccidentDate())) {
//						newIncident.setAccidentDate(new XmlCalendar(incident.getAccidentDate()));
//					}
//					if (checkForValue(incident.getAccidentNr())) {
//						newIncident.setAccidentNr(incident.getAccidentNr());
//					}
//				}
//				newIncident.setId(incident.getId().toString());
//				if (checkForValue(incident.getIncidentDate())) {
//					newIncident.setIncidentDate(new XmlCalendar(incident.getIncidentDate()));
//				}
//				if (checkForValue(incident.getPhysicianId())) {
//					newIncident.setPhysicianID(incident.getPhysicianId());
//					try {
//						// and add the physician, so that all the info is
//						// available in the XML
//						addPhysician(getOfficeManager().getPhysician(incident.getPhysicianId()), gecamedData);
//					} catch (Exception e) {
//						logger.error("Error while trying to export incidents of patient " + gecamedPatient.toLogString(), e);
//					}
//				} else if(checkForValue(gecamedPatient.getDoctorID())){
//					//try to get the physician of the patient
//					newIncident.setPhysicianID(gecamedPatient.getDoctorID());
//				} else {
//					throw new IllegalArgumentException("Unable to find physician information for prescription " + incident.getId());
//				}
				
				// sort the incident entries
				// Ac S O A P Me M Rest
				/* ------------------------------------------------------- */
				List<IncidentEntry> listIE = new ArrayList<IncidentEntry>();
				listIE = incident.getIncidentEntries();
				Collections.sort(listIE);
				// set the nested elements
				for (IncidentEntry entry : listIE) {
					IncidentEntryType entryType = entry.getEntryType();
					if (checkForValue(entryType)) {
						if ((options & INCLUDE_FORMS) == 0 && entryType.getName().equals(FormTab.NAME)) {
							continue;
						}
						if ((options & INCLUDE_CONSULTATIONS) == 0) {
							// check if the current entry is a SOAP, accident or
							// measurement
							if (entryType.getName().equals(IncidentManager.ACCIDENT) || entryType.getName().equals(IncidentManager.SOAP_S)
									|| entryType.getName().equals(IncidentManager.SOAP_O)
									|| entryType.getName().equals(IncidentManager.SOAP_A)
									|| entryType.getName().equals(IncidentManager.SOAP_P)) {
								// do not write this out
								continue;
							}
						}
					}
					if (checkForValue(entryType) && !entryType.getName().equals(IncidentManager.MEASUREMENT)
							&& !entryType.getName().equals(IncidentManager.PRESCRIPTION)) {
						if ((options & INCLUDE_FILE) > 0 && entryType.getName().equals(IncidentManager.FILE)) {
							// FILE ENTRY
							
							// check if file exists before creating an incident or entry
							try {
								byte[] binary;
								try
								{
									binary = FileOpener.loadBinary(entry);
								}
								catch (Exception e)
								{
									fileErrors.put(entry.getFileName(), ErrorStates.FILE_NOT_FOUND);
									continue;
								}
								if(binary != null) {
									FileUtils.writeByteArrayToFile(new File(filesFolder, entry.getFileName()), binary);
								} else {
									fileErrors.put(entry.getFileName(), ErrorStates.FILE_NOT_FOUND);
									continue;
								}
							} catch (IOException e) {
								fileErrors.put(entry.getFileName(), ErrorStates.IO_EXCEPTION);
								continue;
							}
							
							if(newIncident == null) newIncident = patient.addNewIncident();
							EntryType newEntry = newIncident.addNewEntry();
							// substitute with a file entry type
							FileEntry newFileEntry = (FileEntry) newEntry.substitute(FileEntryDocument.type.getDocumentElementName(),
									FileEntry.type);
							// set the file specific attributes
							if (checkForValue(entry.getOriginalFilename())) {
								newFileEntry.setFileName(entry.getOriginalFilename());
							} else {
								newFileEntry.setFileName(entry.getFileName());
//								fileErrors.put(entry.getFileName(), ErrorStates.ORIGINAL_FILENAME_NULL);
//								continue;
							}
							
							// set the file location
//							newFileEntry.setFileLocation(getPatientIdentifier(gecamedPatient) + File.separatorChar + entry.getFileName());
							// always use '/' for path separation in ZIP files
							newFileEntry.setFileLocation(getPatientIdentifier(gecamedPatient) + "/" + entry.getFileName());
							newFileEntry.setType(EntryType.Type.Member.FILE);
							// copy the file to a folder called "files"
							if (!filesFolder.exists()) {
								filesFolder.mkdirs();
							}
							if (checkForValue(entry.getCode())) {
								newFileEntry.setCode(entry.getCode());
							}
							if (checkForValue(entry.getTextContent())) {
								newFileEntry.setText(entry.getTextContent());
							}
						} else if ((options & INCLUDE_LETTERS) > 0 && entryType.getName().equals(IncidentManager.LETTER)) {
							// TODO: LETTER ENTRY
							
							// check if file exists before creating an incident or entry
							try {
								byte[] binary;
								try
								{
									binary = FileOpener.loadBinary(entry);
								}
								catch (Exception e)
								{
									fileErrors.put(entry.getOriginalFilename(), ErrorStates.FILE_NOT_FOUND);
									continue;
								}
								if(binary != null) {
									FileUtils.writeByteArrayToFile(new File(filesFolder, entry.getOriginalFilename()), binary);
								} else {
									fileErrors.put(entry.getOriginalFilename(), ErrorStates.FILE_NOT_FOUND);
									continue;
								}
							} catch (IOException e) {
								fileErrors.put(entry.getOriginalFilename(), ErrorStates.IO_EXCEPTION);
								continue;
							}
							
							// important: there is a mistake in the database the filename and original filename are reversed by the entry type letter
							if(newIncident == null) newIncident = patient.addNewIncident();
							EntryType newEntry = newIncident.addNewEntry();
							// substitute with a file entry type
							FileEntry newFileEntry = (FileEntry) newEntry.substitute(FileEntryDocument.type.getDocumentElementName(),
									FileEntry.type);
							// set the file specific attributes
							if (checkForValue(entry.getFileName())) {
								newFileEntry.setFileName(entry.getFileName());
							} else {
								newFileEntry.setFileName(entry.getOriginalFilename());
//								fileErrors.put(entry.getOriginalFilename(), ErrorStates.ORIGINAL_FILENAME_NULL);
//								continue;
							}
							
							// set the file location
//							newFileEntry.setFileLocation(getPatientIdentifier(gecamedPatient) + File.separatorChar + entry.getOriginalFilename());
							// always use '/' for path separation in ZIP files
							newFileEntry.setFileLocation(getPatientIdentifier(gecamedPatient) + "/" + entry.getOriginalFilename());
							newFileEntry.setType(EntryType.Type.Member.LETTER);
							// copy the file to a folder called "files"
							if (!filesFolder.exists()) {
								filesFolder.mkdirs();
							}
							if (checkForValue(entry.getCode())) {
								newFileEntry.setCode(entry.getCode());
							}
							if (checkForValue(entry.getTextContent())) {
								newFileEntry.setText(entry.getTextContent());
							}
						} else if(!entryType.getName().equals(IncidentManager.FILE) && !entryType.getName().equals(IncidentManager.LETTER)) {
							if(newIncident == null) newIncident = patient.addNewIncident();
							EntryType newEntry = newIncident.addNewEntry();	
							
							if (checkForValue(entry.getCode())) {
								newEntry.setCode(entry.getCode());
							}
							if (checkForValue(entry.getSickLeaveStartDate())) {
								newEntry.setSickLeaveStartDate(new XmlCalendar(entry.getSickLeaveStartDate()));
							}
							if (checkForValue(entry.getSickLeaveEndDate())) {
								newEntry.setSickLeaveEndDate(new XmlCalendar(entry.getSickLeaveEndDate()));
							}
							if (checkForValue(entry.getTextContent())) {
								newEntry.setText(entry.getTextContent());
							}
							if (checkForValue(entryType) && checkForValue(EntryType.Type.Member.Enum.forString(entryType.toString()))) {
								newEntry.setType(EntryType.Type.Member.Enum.forString(entryType.toString()));
							}
						}
					}
				}
				if ((options & INCLUDE_CONSULTATIONS) > 0) {
					// add new measurements
					Set<MeasurementValue> measurementValues = incident.getMeasurementValues();
					if (checkForValue(measurementValues)) {
						for (MeasurementValue measurement : measurementValues) {
							if(!(checkForValue(measurement.getValueString()) || checkForValue(measurement.getValueNumeric()))) {
								//do not store empty measurements
								continue;
							}
							if(newIncident == null) newIncident = patient.addNewIncident();
							Measurement newMeasurement = newIncident.addNewMeasurement();
							if (checkForValue(measurement.getMeasurementDate())) {
								newMeasurement.setPerformed(new XmlCalendar(measurement.getMeasurementDate()));
							}
							newMeasurement.setIsNumeric(checkForValue(measurement.getValueNumeric()));
							if (checkForValue(measurement.getMeasurementType())) {
								String measurementAlias = measurement.getMeasurementType().getAlias();
								//adjust the measurement alias to a proper name
								if(measurementAlias.equals("POU")) {
									measurementAlias = MeasurementType.Member.PULSE.toString();
								} else if(measurementAlias.equals("WEI")) {
									measurementAlias = MeasurementType.Member.WEIGHT.toString();
								} else if(measurementAlias.equals("HEI")) {
									measurementAlias = MeasurementType.Member.HEIGHT.toString();
								}
								newMeasurement.setMeasurementType(measurementAlias);
								newMeasurement.setUnit(measurement.getMeasurementType().getUnit());
							}
							if (newMeasurement.getIsNumeric()) {
								newMeasurement.setValue(measurement.getValueNumeric().toString());
							} else {
								newMeasurement.setValue(measurement.getValueString());
							}
						}
					}
				}
				if ((options & INCLUDE_PRESCRIPTIONS) > 0) {
					// add the prescriptions for this incident
					List<Prescription> prescriptions = getPrescriptionManager().getPrescriptionByIncidentId(incident.getId());
					if (checkForValue(prescriptions)) {
						for (Prescription prescription : prescriptions) {
							if(newIncident == null) newIncident = patient.addNewIncident();
							lu.gecamed.schemas.ximport.PrescriptionDocument.Prescription newPrescription = newIncident.addNewPrescription();
							if (checkForValue(prescription.getAccidentDate())) {
								newPrescription.setAccidentDate(new XmlCalendar(prescription.getAccidentDate()));
							}
							if (checkForValue(prescription.getAccidentNr())) {
								newPrescription.setAccidentNr(prescription.getAccidentNr());
							}
							if (checkForValue(prescription.getCreationDate())) {
								newPrescription.setCreationTime(new XmlCalendar(prescription.getCreationDate()));
							}
							if (checkForValue(prescription.getExpiryDate())) {
								newPrescription.setExpiryDate(new XmlCalendar(prescription.getExpiryDate()));
							}
							if (checkForValue(prescription.getPhysicianId())) {
								newPrescription.setPhysicianID(prescription.getPhysicianId());
								try {
									// and add the physician, so that all
									// the info is available in the XML
									addPhysician(getOfficeManager().getPhysician(prescription.getPhysicianId()), gecamedData);
								} catch (Exception e) {
									logger.error("Error while trying to export a physician with ID "+prescription.getPhysicianId(), e);
								}
							}
							if (checkForValue(prescription.getTextContent())) {
								newPrescription.setPrescriptionContent(prescription.getTextContent());
							} else {
								newPrescription.setPrescriptionContent("");
							}
							if (checkForValue(prescription.getPrescriptionDate())) {
								newPrescription.setPrescriptionDate(new XmlCalendar(prescription.getPrescriptionDate()));
							} else {
								newPrescription.setPrescriptionDate(new XmlCalendar(prescription.getCreationDate()));
							}
						}
					}
				}
				
				if(newIncident != null)
				{
				// set the basic information to the incident
				if (checkForValue(incident.getParentAccidentIncidentId())) {
					// store the ID of the parent incident
					if (checkForValue(incident.getParentAccidentIncidentId())) {
						
						newIncident.setAccidentParentId(incident.getParentAccidentIncidentId().toString());
					}
				} else {
					if (checkForValue(incident.getAccidentDate())) {
						
						newIncident.setAccidentDate(new XmlCalendar(incident.getAccidentDate()));
					}
					if (checkForValue(incident.getAccidentNr())) {
						
						newIncident.setAccidentNr(incident.getAccidentNr());
					}
				}
				
				newIncident.setId(incident.getId().toString());
				if (checkForValue(incident.getIncidentDate())) {
					newIncident.setIncidentDate(new XmlCalendar(incident.getIncidentDate()));
				}
				if (checkForValue(incident.getPhysicianId())) {
					newIncident.setPhysicianID(incident.getPhysicianId());
					try {
						// and add the physician, so that all the info is
						// available in the XML
						addPhysician(getOfficeManager().getPhysician(incident.getPhysicianId()), gecamedData);
					} catch (Exception e) {
						logger.error("Error while trying to export physician with ID " + incident.getPhysicianId(), e);
					}
				} else if(checkForValue(gecamedPatient.getDoctorID())){
					//try to get the physician of the patient
					newIncident.setPhysicianID(gecamedPatient.getDoctorID());
				} else {
					throw new IllegalArgumentException("Unable to find physician information for prescription " + incident.getId());
				}
				}
			}
			if(!force && fileErrors.size() > 0) {
				//delete the exported files for this patient
				try {
					FileUtils.deleteDirectory(filesFolder);
				} catch (IOException e) {
					//do nothing if this deletion fails, the folder will just remain on disk
					Logger.getLogger(XMLExporter.class.getName()).log(Level.WARN, "Unable to delete folder " + filesFolder.getAbsolutePath(), e);
				}
				throw new PatientFileNotFoundException(fileErrors);
			}
		}
		// add invoices
		if ((options & INCLUDE_INVOICES) > 0) {
			try {
				Collection<Invoice> invoices = getInvoiceManager().getInvoicesByPatient(gecamedPatient);
				for (Invoice invoice : invoices) {
					lu.gecamed.schemas.ximport.InvoiceDocument.Invoice newInvoice = patient.addNewInvoice();
					if (checkForValue(invoice.getAccidentDate())) {
						newInvoice.setAccidentDate(new XmlCalendar(invoice.getAccidentDate()));
					}
					if (checkForValue(invoice.getAccidentNumber())) {
						newInvoice.setAccidentNr(invoice.getAccidentNumber());
					}
					for (Act act : invoice.getActs()) {
						// add and setup acts
						lu.gecamed.schemas.ximport.ActDocument.Act newAct = newInvoice.addNewAct();
						if (checkForValue(act.getACM())) {
							newAct.setACM(act.getACM());
						}
						if (checkForValue(act.getCode())) {
							newAct.setActCode(act.getCode());
						} else {
							newAct.setActCode("");
						}
						if (checkForValue(act.getAPCM())) {
							newAct.setAPCM(act.getAPCM());
						}
						if (act.getCAC()) {
							newAct.setCAC(act.getCAC());
						}
						if (checkForValue(act.getCAT())) {
							newAct.setCAT(act.getCAT());
						}

						if (checkForValue(act.getLabel())) {
							newAct.setLabel(act.getLabel());
						}
						if (checkForValue(act.getPerformedDate())) {
							newAct.setPerformed(new XmlCalendar(act.getPerformedDate()));
						}
						if (checkForValue(act.getHospitalisationClass())) {
							newAct.setClass1(act.getHospitalisationClass());
						}
						if (checkForValue(act.getQuantity())) {
							newAct.setQuantity(act.getQuantity());
						}
						if (act.getFixAmount() != null) {
							if (checkForValue(act.getFixAmount())) {
								newAct.setFixAmount(createBigDecimal(act.getFixAmount(), 2));
							}
						} else {
							if (checkForValue(act.getAmount())) {
								newAct.setAmount(createBigDecimal(act.getAmount(), 2));
							}

							if (checkForValue(act.getCoefficient())) {
								newAct.setCoefficient(createBigDecimal(act.getCoefficient(), 2));
							}
							if (checkForValue(act.getKeyValue())) {
								newAct.setKeyValue(createBigDecimal(act.getKeyValue(), 4));
							}
							if (checkForValue(act.getMajoration())) {
								newAct.setMajoration(createBigDecimal(act.getMajoration(), 2));
							}
						}
						if (checkForValue(act.getShowTime())) {
							newAct.setShowTime(act.getShowTime());
						}
						if (checkForValue(act.getSuffixes())) {
							newAct.setSuffixes(act.getSuffixes());
						}
					}

					if (checkForValue(invoice.getAmount())) {
						newInvoice.setAmount(createBigDecimal(invoice.getAmount(), 2));
					}
					if (invoice.getBalance() != null) {
						newInvoice.setBalance(createBigDecimal(invoice.getBalance(), 2));
					}

					if (checkForValue(invoice.getHospitalisationClass()) && checkForValue(invoice.getHospitalisationClass().getAcronym())) {
						newInvoice.setClass1(invoice.getHospitalisationClass().getAcronym());
					} else {
						newInvoice.setClass1("A");
					}
					if (checkForValue(invoice.getInvoiceDate())) {
						newInvoice.setCreationTime(new XmlCalendar(invoice.getInvoiceDate()));
					}
					if (checkForValue(invoice.getDeduction()) && invoice.getDeduction().intValue() > 0) {
						newInvoice.setDeduction(createBigDecimal(invoice.getDeduction(), 2));
					}
					if (checkForValue(invoice.getDueDate())) {
						newInvoice.setDueDate(new XmlCalendar(invoice.getDueDate()));
					}
					// only set the flag if it is true
					if (checkForValue(invoice.getFirstClassRequired()) && invoice.getFirstClassRequired()) {
						newInvoice.setFirstClassRequired(invoice.getFirstClassRequired());
					}
					if (checkForValue(invoice.getHealthInsurance())) {
						newInvoice.addNewHealthInsurance().setName(invoice.getHealthInsurance().getAcronym());
					}
					if (checkForValue(invoice.getMajoration()) && invoice.getMajoration().doubleValue() != 1d) {
						newInvoice.setMajoration(createBigDecimal(invoice.getMajoration(), 2));
					}
					// add memos
					if (checkForValue(invoice.getMemos())) {
						for (lu.tudor.santec.gecamed.billing.ejb.entity.beans.Memo memo : invoice.getMemos()) {
							Memo newMemo = newInvoice.addNewMemo();
							if (checkForValue(memo.getCreationDate())) {
								newMemo.setCreationTime(new XmlCalendar(memo.getCreationDate()));
							}
							if (checkForValue(memo.getNote())) {
								newMemo.setContent(memo.getNote());
							}
						}
					}
					if (checkForValue(invoice.getPayment())) {
						newInvoice.setPayment(createBigDecimal(invoice.getPayment(), 2));
					}
					newInvoice.setPhysicianID(invoice.getPhysician().getId());
					// add the physician to the config if necessary
					addPhysician(invoice.getPhysician(), gecamedData);
					if (checkForValue(invoice.getReminderDate())) {
						newInvoice.setReminderDate(new XmlCalendar(invoice.getReminderDate()));
					}
					if (checkForValue(invoice.getNumberOfReminders()) && invoice.getNumberOfReminders() > 0) {
						newInvoice.setReminders(invoice.getNumberOfReminders());
					}
					if (checkForValue(invoice.getSettlement())) {
						Settlement newSettlement = newInvoice.addNewSettlement();
						if (invoice.getSettlement().getSettlementMethod() == lu.tudor.santec.gecamed.billing.ejb.entity.beans.Settlement.c_Payment) {
							if (checkForValue(invoice.getSettlement().getPayment())) {
								newSettlement.setPaymentType(invoice.getSettlement().getPayment().getMethod());
							}
						} else {
							if (checkForValue(invoice.getSettlement().getTransferAccount())) {
								newSettlement.setIban(invoice.getSettlement().getTransferAccount().getIban());
								newSettlement.setBic(invoice.getSettlement().getTransferAccount().getBic());
								newSettlement.setName(invoice.getSettlement().getTransferAccount().getBankname());
							}
						}
					}
					if (checkForValue(invoice.getSettlementDate())) {
						newInvoice.setSettlementDate(new XmlCalendar(invoice.getSettlementDate()));
//					} else if(checkForValue(invoice.getInvoiceDate())) {
//						newInvoice.setSettlementDate(new XmlCalendar(invoice.getInvoiceDate()));
					}
					// get the states form their integer representation as they
					// have the same order anyway.
					newInvoice.setState(State.Enum.forInt(invoice.getState() + 1));
					if (checkForValue(invoice.getThirdPartyPayer())) {
						newInvoice.addNewThirdPartyPayer().setName(invoice.getThirdPartyPayer().getName());
					}
				}
			} catch (Exception e) {
				logger.error("Error while trying to export invoices of patient " + gecamedPatient.toLogString(), e);
			}
		}

		// add important data
		if ((options & INCLUDE_ACTIVE_PROBLEMS) > 0 || (options & INCLUDE_CHRONICAL_TREATMENTS) > 0) {
			try {
				PatientDatas patientData = getHistoryManager().getPatientDatas(gecamedPatient.getId());
				if (checkForValue(patientData)) {
					if ((options & INCLUDE_ACTIVE_PROBLEMS) > 0) {
						// add current problems (if given)
						if (checkForValue(patientData.getActiveProblem())) {
							patient.setActiveProblems(patientData.getActiveProblem());
						}
					}
					if ((options & INCLUDE_CHRONICAL_TREATMENTS) > 0) {
						// add chronical treatments
						if (checkForValue(patientData.getChronicalTreatments())) {
							patient.setChronicalTreatments(patientData.getChronicalTreatments());
						}
					}
				}
			} catch (Exception e) {
				logger.error("Error while trying to export active problems and chronical treatments of patient " + gecamedPatient.toLogString(), e);
			}
		}
		zipUpFiles(gecamedPatient, outputFolder);
	}

	/**
	 * Zip up all the files from the given patient into one zip file with the
	 * same identifier. Afterwards the patient's files will be deleted
	 * 
	 * @param gecamedPatient
	 *            The patient to zip the files of
	 * @param outputFolder
	 *            The folder in which the zip file should be placed. It's
	 *            subfolder "files" has to contain a folder with the patient
	 *            identifier that will be zipped up and deleted.
	 */
	private static void zipUpFiles(lu.tudor.santec.gecamed.patient.ejb.entity.beans.Patient gecamedPatient, File outputFolder) {
		String patientIdentifier = getPatientIdentifier(gecamedPatient);
		FileOutputStream fos = null;
		BufferedOutputStream bos = null;
		ZipOutputStream zos = null;
		try {
			File patientFolder = new File(outputFolder, FILE_FOLDER_NAME + File.separatorChar + patientIdentifier);
			File[] patientFiles = patientFolder.listFiles();
			if(patientFiles != null && patientFiles.length > 0) {
				fos = new FileOutputStream(new File(outputFolder, patientIdentifier + ".zip"));
				bos = new BufferedOutputStream(fos);
				zos = new ZipOutputStream(bos);
				//zip up all files inside the folder
				for(File patientFile : patientFiles) {
					ZipEntry zipEntry = new ZipEntry(patientIdentifier + "/" + patientFile.getName());
					zos.putNextEntry(zipEntry);
					zos.write(FileUtils.readFileToByteArray(patientFile));
					zos.flush();
					zos.closeEntry();
				}
				//delete the tmp files folder
				FileUtils.deleteDirectory(new File(outputFolder, FILE_FOLDER_NAME));
				//delete the folder if there was no exception until here
				FileUtils.deleteDirectory(patientFolder);
			}
		} catch (FileNotFoundException e) {
			logger.error("Error while trying to export files of patient " + gecamedPatient.toLogString(), e);
		} catch (IOException e) {
			logger.error("Error while trying to export files of patient " + gecamedPatient.toLogString(), e);
		} finally {
			if (zos != null) {
				try {
					zos.close();
				} catch (IOException e) {
					Logger.getLogger(XMLExporter.class.getSimpleName()).log(Level.WARN, "Unable to close zip output stream.", e);
				}
			}
			if (bos != null) {
				try {
					bos.close();
				} catch (IOException e) {
					Logger.getLogger(XMLExporter.class.getSimpleName()).log(Level.WARN, "Unable to close buffered output stream.", e);
				}
			}
			if (fos != null) {
				try {
					fos.close();
				} catch (IOException e) {
					Logger.getLogger(XMLExporter.class.getSimpleName()).log(Level.WARN, "Unable to close file output stream.", e);
				}
			}
		}
	}

	private static String getPatientIdentifier(lu.tudor.santec.gecamed.patient.ejb.entity.beans.Patient gecamedPatient) {
		return String.valueOf(gecamedPatient.getId()) + "_" + gecamedPatient.getFirstName().trim().replace(" ", "_") + "_" + gecamedPatient.getSurName().trim().replace(" ", "_")  + "_" + gecamedPatient.getSocialSecurityNumber();
	}

	/**
	 * Add the extended set of master data to the xml patient. This includes the
	 * simple master data.
	 * 
	 * @param patient
	 *            The xml representation of the patient which should already be
	 *            added to a gecamedData section.
	 * @param gecamedPatient
	 *            The gecamed representation of the patient.
	 */
	private static void addExtendedMasterDataToPatient(Patient patient,
			lu.tudor.santec.gecamed.patient.ejb.entity.beans.Patient gecamedPatient) {
		// first add the basic master data to the patient
		addMasterDataToPatient(patient, gecamedPatient);
		// now add the rest of the data
		// add spouse(s)
		if (checkForValue(gecamedPatient.getSpouseId())) {
			try {
				lu.tudor.santec.gecamed.patient.ejb.entity.beans.Patient spouse = getPatientManager().getPatient(
						gecamedPatient.getSpouseId());
				if (checkForValue(spouse)) {
					initializePersonTypeWithPatient(spouse, patient.addNewSpouse());
				}
			} catch (Exception e) {
				logger.error("Error while trying to export spouse of patient " + gecamedPatient.toLogString(), e);
			}
		} else if(checkForValue(gecamedPatient.getSpouseName())){
			PersonType newSpouse = patient.addNewSpouse();
			newSpouse.setLastName(gecamedPatient.getSpouseName());
		}
		// add children if necessary
		if (gecamedPatient.getChildren().size() > 0) {
			// create the children array
			Children children = patient.addNewChildren();
			for (lu.tudor.santec.gecamed.patient.ejb.entity.beans.Patient child : gecamedPatient.getChildren()) {
				// add the children
				initializePersonTypeWithPatient(child, children.addNewPerson());
			}
		}
		// add parents if necessary
		if (checkForValue(gecamedPatient.getParentName()) || 
				gecamedPatient.getParents().size() > 0) {
			// create the parents array
			Parents parents = patient.addNewParents();
			for (lu.tudor.santec.gecamed.patient.ejb.entity.beans.Patient parent : gecamedPatient.getParents()) {
				// add the parents
				initializePersonTypeWithPatient(parent, parents.addNewPerson());
			}
			if(checkForValue(gecamedPatient.getParentName())) {
				String[] parentNames = gecamedPatient.getParentName().split("\n");
				for(String parentName : parentNames) {
					if(checkForValue(parentName)) {
						parents.addNewPerson().setLastName(parentName);
					}
				}
			}
		}
		// add memos
		try {
			Collection<PatientMemo> patientMemos = getMemoManager().getMemosByPatientID(gecamedPatient.getId());
			for (PatientMemo gecamedMemo : patientMemos) {
				Memo newMemo = patient.addNewMemo();
				if (checkForValue(gecamedMemo.getAuthor())) {
					newMemo.setAuthor(gecamedMemo.getAuthor().getName());
				}
				if (checkForValue(gecamedMemo.getCreationDate())) {
					newMemo.setCreationTime(new XmlCalendar(gecamedMemo.getCreationDate()));
				}
				if (checkForValue(gecamedMemo.getNote())) {
					newMemo.setContent(gecamedMemo.getNote());
				}
			}
		} catch (Exception e) {
			logger.error("Error while trying to export memo of patient " + gecamedPatient.toLogString(), e);
		}
		// add otherattending physicians
		if (checkForValue(gecamedPatient.getOtherPhysicians())) {
			patient.setOtherPhysicians(gecamedPatient.getOtherPhysicians());
		}
		// add IDs
	}

	/**
	 * Initialize a person type with the master data of a gecamed patient
	 * 
	 * @param gecamedPatient
	 *            The patient to read the data from
	 * @param person
	 *            The person to be set up
	 */
	private static void initializePersonTypeWithPatient(lu.tudor.santec.gecamed.patient.ejb.entity.beans.Patient gecamedPatient,
			PersonType person) {
		if (checkForValue(gecamedPatient.getFirstName()))
			person.setFirstName(gecamedPatient.getFirstName());
		if (checkForValue(gecamedPatient.getSurName()))
			person.setLastName(gecamedPatient.getSurName());
		if (checkForValue(gecamedPatient.getMaidenName()))
			person.setMaidenName(gecamedPatient.getMaidenName());
		if (checkForValue(gecamedPatient.getSocialSecurityNumber()))
			person.setMatricule(gecamedPatient.getSocialSecurityNumber());
	}

	/**
	 * Add a minimum set of master data to the given xml patient.
	 * 
	 * @param patient
	 *            The xml patient that will be filled
	 * @param gecamedPatient
	 *            The gecamed representation of the patient
	 */
	private static void addMasterDataToPatient(Patient patient, lu.tudor.santec.gecamed.patient.ejb.entity.beans.Patient gecamedPatient) {
		// add an ID if needed
		// patient.addNewId();
		if (checkForValue(gecamedPatient.getSocialSecurityNumber())) {
			patient.setMatricule(gecamedPatient.getSocialSecurityNumber());
		}
		if (checkForValue(gecamedPatient.getBirthDate())) {
			patient.setBirthday(new XmlCalendar(gecamedPatient.getBirthDate()));
		}
		if (checkForValue(gecamedPatient.getFirstName())) {
			patient.setFirstName(gecamedPatient.getFirstName());
		}
		if (checkForValue(gecamedPatient.getSurName())) {
			patient.setLastName(gecamedPatient.getSurName());
		}
		if (checkForValue(gecamedPatient.getMaidenName())) {
			patient.setMaidenName(gecamedPatient.getMaidenName());
		}
		if (checkForValue(gecamedPatient.getGender())) {
			patient.setGender(Gender.Enum.forString(gecamedPatient.getGender()));
		}
		if (checkForValue(gecamedPatient.getBirthLocality())) {
			patient.setBirthLocality(gecamedPatient.getBirthLocality());
		}
		if (checkForValue(gecamedPatient.getTitle())) {
//			patient.setTitle(gecamedPatient.getTitle());
			// TODO get translation
			TitleTranslation newTitle = patient.addNewTitle();
			newTitle.setTranslation(Translatrix.getTranslationString("Title." + gecamedPatient.getTitle()));
			newTitle.setStringValue(gecamedPatient.getTitle());
			
		}
		//set the ids
		if(checkForValue(gecamedPatient.getMrDeclarationNo())) {
			Id newId = patient.addNewId();
			newId.setType(IdDocument.Id.Type.MEDECIN_REFERENT);
			newId.setStringValue(gecamedPatient.getMrDeclarationNo());
		}
		if(checkForValue(gecamedPatient.getIdLuxembourg())) {
			Id newId = patient.addNewId();
			newId.setType(IdDocument.Id.Type.LUXEMBOURG);
			newId.setStringValue(gecamedPatient.getIdLuxembourg());
		}
		if(checkForValue(gecamedPatient.getIdEuropean())) {
			Id newId = patient.addNewId();
			newId.setType(IdDocument.Id.Type.EUROPE);
			newId.setStringValue(gecamedPatient.getIdEuropean());
		}
		if(checkForValue(gecamedPatient.getIdFutureNational())) {
			Id newId = patient.addNewId();
			newId.setType(IdDocument.Id.Type.FUTURE_NATIONAL);
			newId.setStringValue(gecamedPatient.getIdFutureNational());
		}
		if(checkForValue(gecamedPatient.getIdRIS())) {
			Id newId = patient.addNewId();
			newId.setType(IdDocument.Id.Type.RIS);
			newId.setStringValue(gecamedPatient.getIdRIS());
		}
		//add the original gecamed database ID
		Id newId = patient.addNewId();
		newId.setType(IdDocument.Id.Type.GECAMED_ORIGIN);
		newId.setStringValue(gecamedPatient.getId().toString());
		
		if(checkForValue(gecamedPatient.getStatus())) {
			switch(gecamedPatient.getStatus()) {
				case lu.tudor.santec.gecamed.patient.ejb.entity.beans.Patient.STATUS_NEW :
					patient.setStatus(StatusDocument.Status.NEW);
					break;
				case lu.tudor.santec.gecamed.patient.ejb.entity.beans.Patient.STATUS_DEPARTED :
					patient.setStatus(StatusDocument.Status.DEPARTED);
					break;
				case lu.tudor.santec.gecamed.patient.ejb.entity.beans.Patient.STATUS_INACTIVE :
					patient.setStatus(StatusDocument.Status.INACTIVE);
					break;
				case lu.tudor.santec.gecamed.patient.ejb.entity.beans.Patient.STATUS_ACTIVE :
					patient.setStatus(StatusDocument.Status.ACTIVE);
					break;
				default:
				break;
			}
			
		}
		// get the physician
		if (checkForValue(gecamedPatient.getDoctorID())) {
			patient.setPhysicianID(gecamedPatient.getDoctorID());
			try {
				// and add the physician, so that all the infos are
				// available in the XML
				XmlCursor cursor = patient.newCursor();
				GecamedDataType gecamedData = null;
				if (cursor.toParent()) {
					// the patient is added to the gecameddata object, so it
					// is available as its parent (no need ot pass it in)
					gecamedData = (GecamedDataType) cursor.getObject();
				}
				if (checkForValue(gecamedData)) {
					addPhysician(getOfficeManager().getPhysician(gecamedPatient.getDoctorID()), gecamedData);
				}
			} catch (Exception e) {
				logger.error("Error while trying to export physicians of patient " + gecamedPatient.toLogString(), e);
			}
		}
		// add addresses
		for (PatientAddress address : gecamedPatient.getAddress()) {
			Address newAddress = patient.addNewAddress();
			setUpAdress(newAddress, address);
		}
		// create the insurance
		if (checkForValue(gecamedPatient.getInsurance())) {
			patient.addNewInsurance().setName(gecamedPatient.getInsurance().getAcronym());
		}
		// add the policyNumber if necessary
		// patient.setPolicyNumber(gecamedPatient.getPolicyNumber());
		if (checkForValue(gecamedPatient.getComplementary())) {
			patient.addNewComplementaryInsurance().setName(gecamedPatient.getComplementary().getName());
		}
		if (checkForValue(gecamedPatient.getMaritalStatus())) {
			patient.setMaritalStatus(MaritalStatus.Enum.forString(gecamedPatient.getMaritalStatus()));
		}
		if (checkForValue(gecamedPatient.getChildrenNumber())) {
			patient.setChildrenNumber(gecamedPatient.getChildrenNumber());
		}
		if (checkForValue(gecamedPatient.getJob())) {
			patient.setJob(gecamedPatient.getJob());
		}
		if (checkForValue(gecamedPatient.getNationality())) {
			patient.setNationality(gecamedPatient.getNationality());
		}
		if (checkForValue(gecamedPatient.getLanguage())) {
			patient.setLanguage(gecamedPatient.getLanguage());
		}
		if (checkForValue(gecamedPatient.getCreationDate())) {
			patient.setCreationTime(new XmlCalendar(gecamedPatient.getCreationDate()));
		}
		if (checkForValue(gecamedPatient.getLastModification())) {
			patient.setModificationTime(new XmlCalendar(gecamedPatient.getLastModification()));
		}
		// write out user name
		if (checkForValue(gecamedPatient.getModifiedBy())) {
			GecamedUser user = null;
			try {
				user = getUserManager().getUser(gecamedPatient.getModifiedBy());
			} catch (NamingException e) {
				logger.error("Error while trying to export users of patient " + gecamedPatient.toLogString(), e);
			} catch (FinderException e) {
				logger.error("Error while trying to export users of patient " + gecamedPatient.toLogString(), e);
			}
			if (checkForValue(user)) {
				patient.setModifiedBy(user.getName());
			}
		}
		// add the photo, if there is one
		if (gecamedPatient.getFotos() != null && gecamedPatient.getFotos().size() > 0) {
			// add the first photo
			patient.setPhoto(gecamedPatient.getFotos().iterator().next().getData());
		}
		// add phone numbers
		if (checkForValue(gecamedPatient.getPhones())) {
			for (PatientPhone phone : gecamedPatient.getPhones()) {
				if (checkForValue(phone.getNumber())) {
					PhoneWithTypeType newPhone = patient.addNewPhone();
					if (checkForValue(phone.getType())) {
						newPhone.setType(PhoneWithTypeType.Type.Enum.forString(phone.getType()));
					} else {
						newPhone.setType(PhoneWithTypeType.Type.PRIVATE);
					}
					newPhone.setStringValue(phone.getNumber());
				}
			}
		}
		if (checkForValue(gecamedPatient.getEmail())) {
			patient.setEmail(gecamedPatient.getEmail());
		}
		// add the billing address if necessary
		if (checkForValue(gecamedPatient.getPatientContact())) {
			Guarantor guarantor = patient.addNewGuarantor();
			PatientContact gecamedGuarantor = gecamedPatient.getPatientContact();
			if (checkForValue(gecamedGuarantor.getName())) {
				guarantor.setGuarantorName(gecamedGuarantor.getName());
			}
			Address billingAddress = guarantor.addNewAddress();
			billingAddress.setType(AddressType.Enum.forString("billing"));
			if (checkForValue(gecamedGuarantor.getCountry())) {
				billingAddress.setCountry(gecamedGuarantor.getCountry());
			}
			if (checkForValue(gecamedGuarantor.getLocality())) {
				billingAddress.setLocality(gecamedGuarantor.getLocality());
			}
			if(checkForValue(gecamedGuarantor.getStreetName()) || checkForValue(gecamedGuarantor.getStreetNumber())) {
				Street street = billingAddress.addNewStreet();
				if (checkForValue(gecamedGuarantor.getStreetName())) {
					street.setName(gecamedGuarantor.getStreetName());
				}
				if (checkForValue(gecamedGuarantor.getStreetNumber())) {
					street.setNumber(gecamedGuarantor.getStreetNumber());
				}
			}
			if (checkForValue(gecamedGuarantor.getZip())) {
				billingAddress.setZip(gecamedGuarantor.getZip());
			}
		}
	}

	/**
	 * Add a physician entry to the given gecamedData element if it is not
	 * already present. Physicians with an empty or the default ID will always
	 * be added.
	 * 
	 * @param gecamedPhysician
	 *            The gecamed representation of the physician to be added
	 * @param gecamedData
	 *            The gecamedData element of the generated XML
	 */
	private static void addPhysician(Physician gecamedPhysician, GecamedDataType gecamedData) {
		// check if the physician already exists
		for (lu.gecamed.schemas.ximport.PhysicianDocument.Physician physician : gecamedData.getPhysicianArray()) {
			if (physician.getPhysicianID() == gecamedPhysician.getId()) {
				// the doctor already exists, so he will not be added again.
				return;
			}
		}
		lu.gecamed.schemas.ximport.PhysicianDocument.Physician newPhysician = gecamedData.addNewPhysician();
		// set the id
		newPhysician.setPhysicianID(gecamedPhysician.getId());
		// set the address
		if (checkForValue(gecamedPhysician.getPhysicianAddress())) {
			Address newAddress = newPhysician.addNewAddress();
			setUpAdress(newAddress, gecamedPhysician.getPhysicianAddress());
			newAddress.setType(AddressType.WORK);
		}
		// add the rest of the properties
		if (checkForValue(gecamedPhysician.getColor())) {
			Color physicianColor = new Color(gecamedPhysician.getColor());
			lu.gecamed.schemas.ximport.ColorDocument.Color newColor = newPhysician.addNewColor();
			newColor.setRed(physicianColor.getRed());
			newColor.setGreen(physicianColor.getGreen());
			newColor.setBlue(physicianColor.getBlue());
			newColor.setAlpha(physicianColor.getAlpha());
		}
		if (checkForValue(gecamedPhysician.getEmail())) {
			newPhysician.setEmail(gecamedPhysician.getEmail());
		}
		if (checkForValue(gecamedPhysician.getFax())) {
			newPhysician.setFax(gecamedPhysician.getFax());
		}
		if (checkForValue(gecamedPhysician.getFirstName())) {
			newPhysician.setFirstName(gecamedPhysician.getFirstName());
		}
		if (checkForValue(gecamedPhysician.getGsm())) {
			newPhysician.setGsm(gecamedPhysician.getGsm());
		}
		if (checkForValue(gecamedPhysician.getName())) {
			newPhysician.setLastName(gecamedPhysician.getName());
		}
		if (checkForValue(gecamedPhysician.getPhoneExtension())) {
			newPhysician.setPhoneExtension(gecamedPhysician.getPhoneExtension());
		}
		if (checkForValue(gecamedPhysician.getUcmCode())) {
			newPhysician.setPhysicianUCM(gecamedPhysician.getUcmCode());
		} else {
			//set a UCM code in any case
			newPhysician.setPhysicianUCM(Physician.UCM_DEFAULT);
		}
		if (checkForValue(gecamedPhysician.getSpeciality())) {
			newPhysician.setSpecialty(gecamedPhysician.getSpeciality());
		}
		if (checkForValue(gecamedPhysician.getTitle())) {
//			newPhysician.setTitle(gecamedPhysician.getTitle());
			// TODO get translation
			TitleTranslation newTitle = newPhysician.addNewTitle();
			// no translation set
			newTitle.setTranslation(gecamedPhysician.getTitle());
			newTitle.setStringValue(gecamedPhysician.getTitle());
		}
	}

	private static boolean checkForValue(Object objectToCheck) {
		if (objectToCheck != null) {
			if (objectToCheck instanceof String) {
				return ((String) objectToCheck).length() > 0;
			} else if (objectToCheck instanceof Boolean) {
				return (Boolean) objectToCheck;
			}
			return true;
		}
		return false;
	}

	/**
	 * Do the setup of an already added address
	 * 
	 * @param address
	 *            The XML address to be set up
	 * @param gecamedAddress
	 *            The gecamed address beans providing the address data.
	 */
	private static void setUpAdress(Address address, GECAMedAddressBean gecamedAddress) {
		if (checkForValue(gecamedAddress.getType())) {
			address.setType(AddressType.Enum.forString(gecamedAddress.getType()));
		}
		if(checkForValue(gecamedAddress.getCountry())) {
			address.setCountry(gecamedAddress.getCountry());
		}
		if(checkForValue(gecamedAddress.getLocality())) {
			address.setLocality(gecamedAddress.getLocality());
		}
		if(checkForValue(gecamedAddress.getStreetName()) || checkForValue(gecamedAddress.getStreetNumber())) {
			Street street = address.addNewStreet();
			if(checkForValue(gecamedAddress.getStreetName())) {
				street.setName(gecamedAddress.getStreetName());
			}
			if(checkForValue(gecamedAddress.getStreetNumber())) {
				street.setNumber(gecamedAddress.getStreetNumber());
			}
		}
		if(checkForValue(gecamedAddress.getZip())) {
			address.setZip(gecamedAddress.getZip());
		}
	}

	/**
	 * Get the UCM code of a physician with the given ID
	 * 
	 * @param physicianID
	 *            The internal ID of the physician to be found
	 * @return The physician code if a physician with the given ID exists or
	 *         null if not.
	 */
	public static String getPhysicianUCM(Integer physicianID) {
		try {
			Physician physician = getOfficeManager().getPhysician(physicianID);
			if (checkForValue(physician)) {
				return physician.getUcmCode();
			}
		} catch (Exception e) {
			logger.error("Error while trying to get the CNS code of physician with ID " + physicianID, e);
		}
		return null;
	}

	public static BigDecimal createBigDecimal(double value, int numberOfDigits) {
		BigDecimal bigDecimal = new BigDecimal(value);
		return bigDecimal.setScale(numberOfDigits, RoundingMode.HALF_UP);
	}

	/**
	 * Getter and lazy initializer for the office manager
	 * 
	 * @return The office manager to be used within this class
	 */
	private static OfficeManagerInterface getOfficeManager() {
		if (officeManager == null) {
			officeManager = (OfficeManagerInterface) ManagerFactory.getRemote(OfficeManagerBean.class);
		}
		return officeManager;
	}

	/**
	 * Getter and lazy initializer for the memo interface
	 * 
	 * @return The patient memo interface to be used within this class
	 */
	private static PatientMemoInterface getMemoManager() {
		if (memoManager == null) {
			memoManager = (PatientMemoInterface) ManagerFactory.getRemote(PatientMemoManagerBean.class);
		}
		return memoManager;
	}

	/**
	 * Getter and lazy initializer for the prescription manager
	 * 
	 * @return The prescription manager to be used within this class
	 */
	private static PrescriptionManager getPrescriptionManager() {
		if (prescriptionManager == null) {
			prescriptionManager = (PrescriptionManager) ManagerFactory.getRemote(PrescriptionManagerBean.class);
		}
		return prescriptionManager;
	}

	/**
	 * Getter and lazy initializer for the history manager
	 * 
	 * @return The history manager to be used within this class
	 */
	private static HistoryManager getHistoryManager() {
		if (historyManager == null) {
			historyManager = (HistoryManager) ManagerFactory.getRemote(HistoryManagerBean.class);
		}
		return historyManager;
	}

	/**
	 * Getter and lazy initializer for the invoice manager
	 * 
	 * @return The invoice manager to be used within this class
	 */
	private static InvoiceInterface getInvoiceManager() {
		if (invoiceManager == null) {
			invoiceManager = (InvoiceInterface) ManagerFactory.getRemote(InvoiceBean.class);
		}
		return invoiceManager;
	}

	/**
	 * Getter and lazy initializer for the patient manager
	 * 
	 * @return The patient manager to be used within this class
	 */
	private static PatientAdminInterface getPatientManager() {
		if (patientManager == null) {
			patientManager = (PatientAdminInterface) ManagerFactory.getRemote(PatientAdminBean.class);
		}
		return patientManager;
	}

	/**
	 * Getter and lazy initializer for the user manager
	 * 
	 * @return The user manager to be used within this class
	 */
	private static UserAdminInterface getUserManager() {
		if (userManager == null) {
			userManager = (UserAdminInterface) ManagerFactory.getRemote(UserAdminBean.class);
		}
		return userManager;
	}
}
