/*******************************************************************************
 * 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.importexport.gui.importer;

import java.awt.EventQueue;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.Vector;
import java.util.regex.Pattern;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;

import javax.swing.JFileChooser;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.filechooser.FileFilter;

import lu.tudor.santec.gecamed.billing.ejb.entity.beans.Settlement;
import lu.tudor.santec.gecamed.core.gui.MainFrame;
import lu.tudor.santec.gecamed.core.gui.utils.StringHelper;
import lu.tudor.santec.gecamed.core.gui.widgets.CheckBoxEditorField;
import lu.tudor.santec.gecamed.core.gui.widgets.progress.ProgressDialog;
import lu.tudor.santec.gecamed.core.utils.entitymapper.XML2EntityMapper;
import lu.tudor.santec.gecamed.importexport.utils.PatientAllreadyExitsException;
import lu.tudor.santec.gecamed.importexport.utils.XPathAPI;
import lu.tudor.santec.gecamed.office.ejb.entity.beans.Physician;
import lu.tudor.santec.i18n.Translatrix;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXParseException;

/**
 * @author martin.heinemann@tudor.lu
 * 15.07.2008
 * 16:47:04
 *
 *
 * @version
 * <br>$Log: ImportControler.java,v $
 * <br>Revision 1.24  2014-02-17 15:36:40  ferring
 * <br>While exporting file entries they will now be referenced correctly in the ZIP file (path is always separated with a "/", instead of system dependent).
 * <br>In addition the import checks, if file is available, by switching all '\' to '/'
 * <br>
 * <br>Revision 1.23  2013-12-27 18:08:06  donak
 * <br>Cleanup of imports
 * <br>
 * <br>Revision 1.22  2013-07-15 06:18:34  ferring
 * <br>logging changed
 * <br>
 * <br>Revision 1.21  2013-05-17 12:12:19  ferring
 * <br>Labo module changed to use the CA chain of the labo server to verify the labo and physician certificates.
 * <br>
 * <br>Revision 1.20  2013-03-08 15:07:59  kutscheid
 * <br>fix some UI glitches
 * <br>add functionalities tothe import table
 * <br>add a method to calculate string widths easily
 * <br>
 * <br>Revision 1.19  2013-03-07 07:47:13  kutscheid
 * <br>some more fixes for the importer (it now checks if all added files are present)
 * <br>
 * <br>Revision 1.18  2013-02-20 09:50:04  kutscheid
 * <br>minor modifications in the importer classes + javadoc
 * <br>
 * <br>Revision 1.17  2013-02-19 08:52:49  kutscheid
 * <br>add payment method matching and the possibility to add new bank accounts
 * <br>
 * <br>Revision 1.16  2013-02-18 13:25:32  kutscheid
 * <br>add a choice dialog for payment methods
 * <br>
 * <br>Revision 1.15  2013-02-18 07:22:11  kutscheid
 * <br>improve the import module
 * <br>fix a NullPointerException in the LineColorCellRenderer
 * <br>update the gecamedData xsd file and libs
 * <br>
 * <br>Revision 1.14  2013-02-14 09:54:54  kutscheid
 * <br>first commit of the new/remodelled importer implementation
 * <br>fix some nullpointer exceptions
 * <br>
 * <br>Revision 1.13  2012-03-15 08:16:07  ferring
 * <br>space added between job description and filename
 * <br>
 * <br>Revision 1.12  2012-02-07 10:45:25  ferring
 * <br>checking dialog will now always be closed
 * <br>
 * <br>Revision 1.11  2012-02-02 15:19:27  ferring
 * <br>unnecessary NullpointerException prevented
 * <br>
 * <br>Revision 1.10  2008-10-15 09:53:00  heinemann
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.9  2008-10-08 09:37:26  heinemann
 * <br>fixed icons
 * <br>
 * <br>Revision 1.8  2008-10-02 15:09:41  heinemann
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.7  2008-09-25 09:43:08  heinemann
 * <br>fixed copyrights
 * <br>
 * <br>Revision 1.6  2008-09-03 14:08:37  hermen
 * <br>changed xml validator to show line/column of error
 * <br>
 * <br>Revision 1.5  2008-09-03 13:57:29  heinemann
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.4  2008-07-23 09:44:53  heinemann
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.3  2008-07-22 15:10:21  hermen
 * <br>updated mappings
 * <br>
 * <br>Revision 1.2  2008-07-18 15:41:05  heinemann
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.1  2008-07-18 13:44:32  heinemann
 * <br>*** empty log message ***
 * <br>
 *   
 */
public class ImportControler implements ActionListener, MouseListener, ListSelectionListener {

	/** the logger Object for this class */
	private static Logger logger = Logger.getLogger(ImportControler.class.getName());
	
	private ImportPanel panel;
	
	private List<FileStatus> fileContainer = new ArrayList<FileStatus>();

	private ImportTableModel tableModel;

	private File[] selectedFiles;
	
	private static FileFilter	xmlFileFilter;
	
	private static final Map<PaymentMethod, Settlement> knownPaymentMethods = new HashMap<PaymentMethod, Settlement>();
	
	private static final Map<PaymentMethod, Pattern> PATTERN_CACHE = new HashMap<PaymentMethod, Pattern>();
	private static final Map<PaymentMethod, Pattern> IBAN_PATTERN_CACHE = new HashMap<PaymentMethod, Pattern>();

	private boolean simulationIsRunning = false;
	
	
	public static enum Status {
		VALIDE, INVALIDE, PARSER_OK, PARSE_ERROR, EXISTS, SIMULATE_OK, SIMULATE_ERROR, WORKING, IMPORTED, IMPORT_ERROR
	}
	
	private static enum GuiState {
		INIT, CHECK, SIMULATING, IMPORTING, FINISH, SIMULATE_OK
	}
	
	private GuiState state;
	
	
	private CheckBoxEditorField boxEditor = new CheckBoxEditorField();


	private Thread importThread;
	
	/**
	 * 
	 */
	public ImportControler() {
		/* ================================================== */

		/* ================================================== */
	}
	
	
	public void setPanel(ImportPanel panel) {
		/* ================================================== */
		this.panel = panel;
		registerActions();
		setState(GuiState.INIT);
		/* ================================================== */
	}
	
	
	/**
	 * 
	 */
	private void registerActions() {
		/* ================================================== */
		this.panel.getChooserButton().addActionListener(   this);
		this.panel.getRevalidateButton().addActionListener(this);
		this.panel.getSimulateButton().addActionListener(  this);
		this.panel.getImportButton().addActionListener(	   this);
		
		
		this.panel.getTable().addMouseListener(this);
		this.panel.getTable().getSelectionModel().addListSelectionListener(this);
		/* ================================================== */
	}

	
	private void startValidation(final File[] files) {
		/* ================================================== */
		if (this.tableModel != null)
			tableModel.setData(null);
		this.fileContainer.clear();
		// show the progress dialog
		final ProgressDialog pd = new ProgressDialog();
		pd.setClosable(false);
		pd.setCancelable(false);
		pd.setProgressBarSpan(0,files.length);
	
		pd.setTitle("import.validatefiles");
//		pd.setMessage("ReminderInvoicesPanel.FetchingInvoicesMessage",null);
//		pd.setTask("import.validatefiles", l_Filler);
		pd.pack();
		
		
		pd.setVisible(true);
		/* ------------------------------------------------------- */
		// create a new thread to do the validation
		// and to update the progress bar in the dialog
		/* ------------------------------------------------------- */
		Thread t = new Thread() {
			
			public void run() {
				/* ================================================== */
				XMLFileImporter fileImporter = new XMLFileImporter();
				Set<PaymentMethod> paymentMethods = new HashSet<PaymentMethod>();
				try {
					int progressBarSpan = files.length;
					int counter = 0;
					for (File f : files) {
						pd.setProgress(counter++,Translatrix.getTranslationString("import.validate") + " " + f.getName());
						/* ------------------------------------------------------- */
						Collection<File> listFiles = fileImporter.getImportFiles(f);
						/* ------------------------------------------------------- */
						if (listFiles == null)
							continue;
						/* ------------------------------------------------------- */
						Document document = null;
						int countOk    = 0;
						int countError = 0;
						//adjust the size of the progress bar
						progressBarSpan += listFiles.size()-1;
						pd.setProgressBarSpan(0, progressBarSpan);
						//operate on a copy as elements are removed from the list during the run 
						for (File foundFile : new ArrayList<File>(listFiles)) {
							/* ------------------------------------------------------- */
							// send each file to the parser
							/* ------------------------------------------------------- */
							if (!foundFile.exists())
							{
								listFiles.remove(foundFile);
								continue;
							}
							
							
							FileStatus fileStatus = new FileStatus();
							fileStatus.setFile(foundFile);
							document = null;
							if(listFiles.size() > 1) {
								pd.setProgress(counter++,Translatrix.getTranslationString("import.validate") + " " + foundFile.getName());
							}
							
							try {
								/* ------------------------------------------------------- */
								document  = fileImporter.parseFile(foundFile);
								NodeList paymentTypeList = XPathAPI.selectNodeIterator(document, "/gecamedData/patient/invoice/settlement/paymentType");
								for(int i = 0; i < paymentTypeList.getLength(); i++) {
									paymentMethods.add(PaymentMethod.getPaymentMethod(paymentTypeList.item(i).getTextContent(), false));
								}
								//get the new IBAN entries
								NodeList ibanList = XPathAPI.selectNodeIterator(document, "/gecamedData/patient/invoice/settlement/iban");
								for(int i = 0; i < ibanList.getLength(); i++) {
									paymentMethods.add(PaymentMethod.getPaymentMethod(ibanList.item(i).getTextContent(), true));
								}
								//check if all files of the patient can be retrieved from the accompanying zip file
								NodeList allFileNames = XPathAPI.selectNodeIterator(document, "/gecamedData/patient/incident/fileEntry/fileLocation");
								if(allFileNames.getLength() > 0) {
									ZipFile zipFile = null;
									try {
										File zipFilePath = XMLFileImporter.getZipFileForImportFile(foundFile);
										try {
											//try to find the zip file
											zipFile = new ZipFile(zipFilePath);
										} catch (ZipException ex) {
											throw new Exception("Unable to open the zip file " + zipFilePath.getAbsolutePath(), ex);
										} catch (IOException ex) {
											throw new Exception("Unable to find the zip file " + zipFilePath.getAbsolutePath(), ex);
										}
										if(zipFile != null) {
											String fileName;
											for(int i = 0; i < allFileNames.getLength(); i++) {
												fileName = allFileNames.item(i).getTextContent();
												if(zipFile.getEntry(fileName) == null) {
													fileName = fileName.replace("\\", "/");
													if (zipFile.getEntry(fileName) == null) {
														//stop the validation here
														throw new Exception("The file " + allFileNames.item(i).getTextContent() + " could not be found in the zip file");
													} else {
														allFileNames.item(i).setTextContent(fileName);
														logger.warn("Path separators of ZIP file entry corrected");
													}
												}
											}
										}
									} finally {
										if (zipFile != null)
											zipFile.close();
									}
								}
								fileStatus.setStatus(Status.PARSER_OK);
								fileStatus.setSelected4Import(true);
								/* ------------------------------------------------------- */
							} catch (Exception e) {
								/* ------------------------------------------------------- */
								fileStatus.setStatus(Status.PARSE_ERROR);
								fileStatus.setMessage(e.getLocalizedMessage());
								fileStatus.setSelected4Import(false);
								logger.log(Level.ERROR, e.getMessage(), e);
								countError++;
								/* ------------------------------------------------------- */
							}
							/* ------------------------------------------------------- */
							// send the file to the validator if parsing was ok
							/* ------------------------------------------------------- */
							if (fileStatus.getStatus() == Status.PARSER_OK) {
								/* ------------------------------------------------------- */
								try {
									/* ------------------------------------------------------- */
									boolean valid = fileImporter.validateDocument(foundFile);
									if (valid) {
										fileStatus.setStatus(Status.VALIDE);
										countOk++;
									}
									else {
										fileStatus.setStatus(Status.INVALIDE);
										countError++;
									}
									/* ------------------------------------------------------- */
								} catch (SAXParseException e) {
									/* ------------------------------------------------------- */
									fileStatus.setStatus(Status.INVALIDE);
									fileStatus.setMessage(
										"Line: " +e.getLineNumber()+
										" Column:"+e.getColumnNumber() + 
										"  " +e.getLocalizedMessage());
									logger.log(Level.ERROR, e.getMessage());
									countError++;
									/* ------------------------------------------------------- */
								} catch (Exception e) {
									/* ------------------------------------------------------- */
									fileStatus.setStatus(Status.INVALIDE);
									fileStatus.setMessage(e.getLocalizedMessage());
									logger.log(Level.ERROR, e.getMessage(), e);
									countError++;
									/* ------------------------------------------------------- */
								}
								/* ------------------------------------------------------- */
								// set the patient info
								/* ------------------------------------------------------- */
								fileStatus.setInfo(fileImporter.getPatientInfo(document));
								/* ------------------------------------------------------- */
							}
							/* ------------------------------------------------------- */
							// add the parsed and validated file to the filecontainer
							/* ------------------------------------------------------- */
							fileContainer.add(fileStatus);
							/* ------------------------------------------------------- */
						}
						
						setCountInfo(countOk, countError, null);
						/* ------------------------------------------------------- */
					}
				}
				finally
				{
					/* ------------------------------------------------------- */
					// hide the dialog
					/* ------------------------------------------------------- */
					pd.setVisible(false);
					/* ------------------------------------------------------- */
					// show the table
					showTable();
					setState(GuiState.CHECK);
					/* ================================================== */
					//let the user assign the payment methods that have been found
					if(paymentMethods.size() > 0) {
						boolean showAgain = false;
						for(PaymentMethod paymentMethod : paymentMethods) {
							if(!knownPaymentMethods.containsKey(paymentMethod)) {
								knownPaymentMethods.put(paymentMethod, null);
								showAgain = true;
							}
						}
						if(showAgain) {
							//let the user adjust the mapping
							new PaymentMethodAssignmentDialog(MainFrame.getInstance(), knownPaymentMethods).showCenteredDialog();
						}
					}
				}
			}
		};
		pd.setVisible(true);
		t.start();
		/* ================================================== */
	}
	
	private void setCountInfo(Integer countOk, Integer countError, Integer countWarning) {
		/* ================================================== */
		StringBuffer buff = new StringBuffer();
		/* ------------------------------------------------------- */
		if (countError != null)
			buff.append(countError + " " + Translatrix.getTranslationString("import.error") + "  " );
		/* ------------------------------------------------------- */
		if (countOk != null)
			buff.append(countOk + " " + Translatrix.getTranslationString("import.ok") + "  ");
		/* ------------------------------------------------------- */
		if (countWarning != null)
			buff.append(countWarning + " " + Translatrix.getTranslationString("import.warning"));
		
		panel.setResultInfoText(buff.toString());
		/* ================================================== */
	}
	
	private void showTable() {
		/* ================================================== */
		if (this.tableModel == null) {
			this.tableModel = new ImportTableModel();
			panel.getTable().setModel(tableModel);
		}
		
		tableModel.setData(fileContainer);
		
		panel.showTablePanel();
		tableModel.fireTableDataChanged();
		/* ================================================== */
	}
	

	public void actionPerformed(ActionEvent e) {
		/* ====================================================== */
		if (e.getSource().equals(panel.getChooserButton())) {
			/* ------------------------------------------------------- */
			JFileChooser chooser = MainFrame.getFileChooser();
			File[] fileChooserSelectedFiles;
			
			chooser.setMultiSelectionEnabled(true);
			chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
			chooser.setSelectedFiles(null);
			try
			{
				chooser.setFileFilter(getXmlFileFilter());
				chooser.showOpenDialog(MainFrame.getInstance());
				fileChooserSelectedFiles = chooser.getSelectedFiles();
			}
			finally
			{
				chooser.resetChoosableFileFilters();
			}
			/* ------------------------------------------------------- */
			// get the dirs and files
			/* ------------------------------------------------------- */
			//remove files that do not exist (invalid names) from the list
			List<File> existingFiles = new ArrayList<File>();
			for(File selectedFile : fileChooserSelectedFiles) {
				if (selectedFile.exists()) {
					existingFiles.add(selectedFile);
				}
			}
			this.selectedFiles = existingFiles.toArray(new File[existingFiles.size()]);
			/* ------------------------------------------------------- */
			// if empty, disable the panel
			/* ------------------------------------------------------- */
			if (selectedFiles == null || selectedFiles.length < 1) {
				setState(GuiState.INIT);
				return;
			} else {
				/* ------------------------------------------------------- */
				// get the first file and copy its path to the textfield
				File first = selectedFiles[0];
				
				panel.getChoosertextField().setText(first.getAbsolutePath());
				
				startValidation(selectedFiles);
				/* ------------------------------------------------------- */
			}
			/* ------------------------------------------------------- */
		}
		if (e.getSource().equals(panel.getRevalidateButton())) {
			/* ------------------------------------------------------- */
			panel.setInfoText("");
			startValidation(selectedFiles);
			/* ------------------------------------------------------- */
		}
		if (e.getSource().equals(panel.getSimulateButton())) {
			/* ------------------------------------------------------- */
			startSimulation();
			/* ------------------------------------------------------- */
		}
		if (e.getSource().equals(panel.getImportButton())) {
			/* ------------------------------------------------------- */
			if (this.state == GuiState.IMPORTING)
				stopImport();
			else
				startImport();
			/* ------------------------------------------------------- */
		}
		/* ====================================================== */
	}
	
	/**
	 * 
	 */
	private void startSimulation() {
		/* ====================================================== */
		if (this.simulationIsRunning) {
			/* ------------------------------------------------------- */
			// abort
			/* ------------------------------------------------------- */
			setState(GuiState.CHECK);
			/* ------------------------------------------------------- */
		} else {
			/* ------------------------------------------------------- */
			// disable all buttons
			// set the busywheel icon 
			/* ------------------------------------------------------- */
			
			Thread t = new Thread() {
				
				public void run() {
					/* ------------------------------------------------------- */
					setState(GuiState.SIMULATING);
					simulationIsRunning = true;
					XMLFileImporter fileImporter = new XMLFileImporter();
					
					/* ------------------------------------------------------- */
					// iterate over all files and use only the ones that are valid
					/* ------------------------------------------------------- */
					PatientMapper   patientMapper   = new PatientMapper();
					/* ------------------------------------------------------- */
					// remove the invalide ones
					/* ------------------------------------------------------- */
					List<FileStatus> invalide = new ArrayList<FileStatus>();
					int countOk    = 0;
					int countError = 0;
					int countWarning = 0;
					for (FileStatus file : new ArrayList<FileStatus>(fileContainer)) {
						if(state != GuiState.CHECK) {
							/* ------------------------------------------------------- */
							if (!file.isSelected4Import())
								continue;
							/* ------------------------------------------------------- */
							if (!(file.getStatus() == Status.VALIDE)) {
								invalide.add(file);
								continue;
							}
							/* ------------------------------------------------------- */
							// create a document
							/* ------------------------------------------------------- */
							try {
								/* ------------------------------------------------------- */
								Document doc = fileImporter.parseFile(file.getFile());
								boolean importOk = patientMapper.importPatientFromDocument(file.getFile(), doc, true, false);
								
								if (importOk) {
										file.setStatus(Status.SIMULATE_OK);
										countOk++;
								} else {
									file.setStatus(Status.EXISTS);
									file.setMessage("Patient in " + file.getFile().getAbsolutePath() + " allready exists in the Database");
									countWarning++;
								}
								/* ------------------------------------------------------- */
							}
							catch (Exception e) {
								/* ------------------------------------------------------- */
								file.setStatus(Status.SIMULATE_ERROR);
								file.setMessage(e.getLocalizedMessage());
								countError++;
								/* ------------------------------------------------------- */
							}
							//update the table
							int rowIndex = fileContainer.indexOf(file);
							tableModel.fireTableRowsUpdated(rowIndex, rowIndex);
						}
						/* ------------------------------------------------------- */
					}
					fileContainer.removeAll(invalide);
					
					setCountInfo(countOk, countError, countWarning);
					/* ------------------------------------------------------- */
					simulationIsRunning = false;
					if(state == GuiState.SIMULATING) {
						//only mark as OK if the simulation has not been aborted
						setState(GuiState.SIMULATE_OK);
					}
				}
			};
			t.start();
		}
		/* ====================================================== */
	}
	
	private void stopImport() {
		/* ================================================== */
		setState(GuiState.SIMULATE_OK);
		/* ================================================== */
	}
	
	
	private void startImport() {
		/* ================================================== */
		setState(GuiState.IMPORTING);
		this.importThread = new Thread() {
			
			public void run() {
				/* ------------------------------------------------------- */
				XMLFileImporter fileImporter = new XMLFileImporter();
				/* ------------------------------------------------------- */
				// iterate over all files and use only the ones that are valid
				/* ------------------------------------------------------- */
				PatientMapper   patientMapper   = new PatientMapper();
				/* ------------------------------------------------------- */
				// remove the invalide ones
				/* ------------------------------------------------------- */
				Vector<FileStatus> invalide = new Vector<FileStatus>();
				int countOk    = 0;
				int countError = 0;
				for (int i = 0; i < fileContainer.size(); i++) {
					FileStatus file = fileContainer.get(i);
					/* ------------------------------------------------------- */
					if (ImportControler.this.state != GuiState.IMPORTING)
						return;
					
					if (!file.isSelected4Import())
						continue;
					/* ------------------------------------------------------- */
					// if exits, check if forced to import
					/* ------------------------------------------------------- */
					if (file.getStatus() == Status.EXISTS)
						if (!file.getForceImport()) {
							fileImporter.move2Existing(file.getFile());
							continue;
						}
					/* ------------------------------------------------------- */
					file.setStatus(Status.WORKING);
					final int index = i;
					EventQueue.invokeLater(new Runnable() {
						
						public void run() {
							tableModel.fireTableRowsUpdated(index, index);
							Rectangle rect = panel.table.getCellRect(index, 1, true);
							panel.table.scrollRectToVisible(rect);
						}
					});
					/* ------------------------------------------------------- */
					// create a document
					/* ------------------------------------------------------- */
					try {
						/* ------------------------------------------------------- */
						//adjust the file to make sure the mapped bank account data is used
						Document doc;
						if(knownPaymentMethods.size() > 0) {
							//read the file content
							String fileContent = FileUtils.readFileToString(file.getFile(), "UTF-8");
							for(Entry<PaymentMethod, Settlement> entry : knownPaymentMethods.entrySet()) {
								Pattern pattern;
								if(entry.getKey().isBankAccount()) {
									pattern = IBAN_PATTERN_CACHE.get(entry.getKey());
									if(pattern == null) {
										pattern = Pattern.compile("(<settlement>)" +
												"\\s*<iban>(" + entry.getKey().getValue() + ")</iban>" +
												"\\s*<bic>.+</bic>" +
												"\\s*<name>.+</name>" +
												"\\s*(</settlement>)");
										IBAN_PATTERN_CACHE.put(entry.getKey(), pattern);
									}
								} else {
									pattern = PATTERN_CACHE.get(entry.getKey());
									if(pattern == null) {
										pattern = Pattern.compile("(<settlement>)\\s*<paymentType>(" + entry.getKey().getValue().toString() + ")</paymentType>\\s*(</settlement>)");
										PATTERN_CACHE.put(entry.getKey(), pattern);
									}
								}
								if(entry.getValue().getTransferAccount() != null) {
									//else we need to insert the whole new account information
									fileContent = pattern.matcher(fileContent).replaceAll(
											"$1" +
													"<iban>" + entry.getValue().getTransferAccount().getIban() + "</iban>" +
													"<bic>" + entry.getValue().getTransferAccount().getBic() + "</bic>" +
													"<name>" + entry.getValue().getTransferAccount().getBankname() + "</name>" +
											"$3");
								} else {
									//if the given settlement references to a payment type the replacement can be done by simply replacing the old payment type with the new one
									fileContent = pattern.matcher(fileContent).replaceAll("$1<paymentType>" + entry.getValue() + "</paymentType>$3");
								}
							}
							doc = fileImporter.parseFile(fileContent);
						} else {
							doc = fileImporter.parseFile(file.getFile());
						}
						PhysicianMapper physMapper = new PhysicianMapper();
						Collection<Physician> physicians = physMapper.getPhysicians(new XML2EntityMapper(doc));
						for(Physician physician : physicians) {
							if(!physMapper.checkPhysicianExists(physician)) {
								physMapper.insertPhysician(physician);
							}
						}
						boolean importOk = patientMapper.importPatientFromDocument(file.getFile(), doc, false, true);
						if (importOk) {
							file.setStatus(Status.IMPORTED);
							fileImporter.move2Imported(file.getFile());
							countOk++;
						} else {
							throw new PatientAllreadyExitsException("Patient in " + file.getFile().getAbsolutePath() + " allready exists in the Database");
						}
						/* ------------------------------------------------------- */
					}
					catch (Exception e) {
						/* ------------------------------------------------------- */
						file.setStatus(Status.IMPORT_ERROR);
						file.setMessage(e.getLocalizedMessage());
						
						fileImporter.move2Error(file.getFile());
						invalide.add(file);
						countError++;
						/* ------------------------------------------------------- */
					}
					/* ------------------------------------------------------- */
				}
				fileContainer.clear();
				fileContainer.addAll(invalide);
				showTable();
				setCountInfo(countOk, countError, null);
				/* ------------------------------------------------------- */
				setState(GuiState.FINISH);
			}
		};
		this.importThread.start();
		/* ================================================== */
	}
	
	/**
	 * @param s
	 */
	public void setState(GuiState s) {
		/* ================================================== */
		this.state = s;
		if (s == GuiState.INIT) {
			/* ------------------------------------------------------- */
			panel.enableBottom(false);
			setCountInfo(null, null, null);
			adjustTable();
			/* ------------------------------------------------------- */
		}
		if (s == GuiState.CHECK) {
			/* ------------------------------------------------------- */
			panel.enableBottom(true);
			panel.getRevalidateButton().setEnabled(true);
			panel.getSimulateButton().  setEnabled(true);
			panel.getImportButton().	setEnabled(false);
			
			panel.getSimulateButton().setIcon(ImportPanel.simulateIcon);
			panel.getSimulateButton().setText(Translatrix.getTranslationString("import.simulate"));
			adjustTable();
			/* ------------------------------------------------------- */
		}
		if (s == GuiState.SIMULATING) {
			/* ------------------------------------------------------- */
			panel.enableBottom(true);
			panel.getRevalidateButton().setEnabled(false);
			panel.getSimulateButton().  setEnabled(true);
			panel.getImportButton().	setEnabled(false);
			
			panel.getSimulateButton().setIcon(ImportPanel.busyWheelIcon);
			panel.getSimulateButton().setText(Translatrix.getTranslationString("import.cancel"));
			adjustTable();
			/* ------------------------------------------------------- */
		}
		if (s == GuiState.SIMULATE_OK) {
			/* ------------------------------------------------------- */
			panel.enableBottom(true);
			panel.getRevalidateButton().setEnabled(true);
			panel.getSimulateButton().  setEnabled(false);
			panel.getImportButton().	setEnabled(true);
			SwingUtilities.invokeLater(new Runnable() {
				public void run() {
					panel.getImportButton().setIcon(ImportPanel.importIcon);
					panel.getImportButton().setText(Translatrix.getTranslationString("import.tab"));
					adjustTable();
				}
			});
			panel.getSimulateButton().setIcon(ImportPanel.simulateIcon);
			panel.getSimulateButton().setText(Translatrix.getTranslationString("import.simulate"));

			adjustTable();
			/* ------------------------------------------------------- */
		}
		if (s == GuiState.IMPORTING) {
			/* ------------------------------------------------------- */
			panel.enableBottom(true);
			panel.getRevalidateButton().setEnabled(false);
			panel.getSimulateButton().  setEnabled(false);
			panel.getImportButton().	setEnabled(true);
			SwingUtilities.invokeLater(new Runnable() {
				public void run() {
					panel.getImportButton().setIcon(ImportPanel.busyWheelIcon);
					panel.getImportButton().setText(Translatrix.getTranslationString("import.cancel"));
					adjustTable();
				}
			});
			
			/* ------------------------------------------------------- */
		}
		if (s == GuiState.FINISH) {
			/* ------------------------------------------------------- */
			panel.enableBottom(true);
			panel.getRevalidateButton().setEnabled(true);
			panel.getSimulateButton().  setEnabled(false);
			panel.getImportButton().	setEnabled(false);
			SwingUtilities.invokeLater(new Runnable() {
				public void run() {
				panel.getImportButton().setIcon(ImportPanel.importIcon);
				panel.getImportButton().setText(Translatrix.getTranslationString("import.tab"));
				adjustTable();
			}});
			/* ------------------------------------------------------- */
		}
		/* ================================================== */
	}
	
	
	/**
	 * 
	 */
	private void adjustTable() {
		/* ================================================== */
		panel.getTable().createDefaultColumnsFromModel();
		
		
		if (panel.getTable().getColumnModel().getColumnCount() == 2) {
			/* ------------------------------------------------------- */
			//calculate the width of the first column
			int firstWidth = StringHelper.getTextWidth(panel, Translatrix.getTranslationString("import.table.firstCol")) + 20;
			panel.getTable().getColumnModel().getColumn(0).setMinWidth(firstWidth);
			panel.getTable().getColumnModel().getColumn(0).setMaxWidth(firstWidth);
			panel.getTable().getColumnModel().getColumn(0).setCellEditor(boxEditor);
			/* ------------------------------------------------------- */
		}
		if (panel.getTable().getColumnModel().getColumnCount() == 3) {
			/* ------------------------------------------------------- */
			int firstWidth = StringHelper.getTextWidth(panel, Translatrix.getTranslationString("import.table.firstCol")) + 20;
			int thirdWidth = StringHelper.getTextWidth(panel, Translatrix.getTranslationString("import.table.thirdCol")) + 20;
			panel.getTable().getColumnModel().getColumn(0).setMinWidth(firstWidth);
			panel.getTable().getColumnModel().getColumn(0).setMaxWidth(firstWidth);
			
			panel.getTable().getColumnModel().getColumn(2).setMinWidth(thirdWidth);
			panel.getTable().getColumnModel().getColumn(2).setMaxWidth(thirdWidth);
			
			panel.getTable().getColumnModel().getColumn(0).setCellEditor(boxEditor);
			panel.getTable().getColumnModel().getColumn(2).setCellEditor(boxEditor);
			/* ------------------------------------------------------- */
		}
		/* ================================================== */
	}

	/**
	 * @param row
	 */
	private void showLine(int row) {
		/* ================================================== */
		if (row < 0)
			return;
		FileStatus s = fileContainer.get(row);
		
		panel.setInfoText(s.getMessage());
//		panel.setInfoFileName(s.getFile().getName());
		/* ================================================== */
	}
	
	
	private static FileFilter getXmlFileFilter ()
	{
		if (xmlFileFilter == null)
		{
			xmlFileFilter = new FileFilter()
			{
				@Override
				public String getDescription ()
				{
					return ".xml";
				}
				
				
				@Override
				public boolean accept (File f)
				{
					return "xml".equalsIgnoreCase(FilenameUtils.getExtension(f.getName()))
							|| f.isDirectory();
				}
			};
		}
		
		return xmlFileFilter;
	}
	
	
	/**
	 * for the list selectionlistener on the jtable
	 * Should do the same like the mouse clicked event 
	 */
	public void valueChanged(ListSelectionEvent e) {
		/* ====================================================== */
		int row = panel.getTable().getSelectedRow();
		showLine(row);
		/* ====================================================== */
	}

	
	public void mouseClicked(MouseEvent e) {
		/* ====================================================== */
		JTable table = panel.getTable();
		
		int row = table.rowAtPoint(e.getPoint());
		showLine(row);
		
		/* ====================================================== */
	}


	public void mouseEntered(MouseEvent e) {}
	public void mouseExited(MouseEvent e) {}
	public void mousePressed(MouseEvent e) {}
	public void mouseReleased(MouseEvent e) {}
	
	
	
	/**
	 * Store infos of a file
	 * 
	 * @author martin.heinemann@tudor.lu
	 * 16.07.2008
	 * 09:09:31
	 *
	 *
	 * @version
	 * <br>$Log: ImportControler.java,v $
	 * <br>Revision 1.24  2014-02-17 15:36:40  ferring
	 * <br>While exporting file entries they will now be referenced correctly in the ZIP file (path is always separated with a "/", instead of system dependent).
	 * <br>In addition the import checks, if file is available, by switching all '\' to '/'
	 * <br>
	 * <br>Revision 1.23  2013-12-27 18:08:06  donak
	 * <br>Cleanup of imports
	 * <br>
	 * <br>Revision 1.22  2013-07-15 06:18:34  ferring
	 * <br>logging changed
	 * <br>
	 * <br>Revision 1.21  2013-05-17 12:12:19  ferring
	 * <br>Labo module changed to use the CA chain of the labo server to verify the labo and physician certificates.
	 * <br>
	 * <br>Revision 1.20  2013-03-08 15:07:59  kutscheid
	 * <br>fix some UI glitches
	 * <br>add functionalities tothe import table
	 * <br>add a method to calculate string widths easily
	 * <br>
	 * <br>Revision 1.19  2013-03-07 07:47:13  kutscheid
	 * <br>some more fixes for the importer (it now checks if all added files are present)
	 * <br>
	 * <br>Revision 1.18  2013-02-20 09:50:04  kutscheid
	 * <br>minor modifications in the importer classes + javadoc
	 * <br>
	 * <br>Revision 1.17  2013-02-19 08:52:49  kutscheid
	 * <br>add payment method matching and the possibility to add new bank accounts
	 * <br>
	 * <br>Revision 1.16  2013-02-18 13:25:32  kutscheid
	 * <br>add a choice dialog for payment methods
	 * <br>
	 * <br>Revision 1.15  2013-02-18 07:22:11  kutscheid
	 * <br>improve the import module
	 * <br>fix a NullPointerException in the LineColorCellRenderer
	 * <br>update the gecamedData xsd file and libs
	 * <br>
	 * <br>Revision 1.14  2013-02-14 09:54:54  kutscheid
	 * <br>first commit of the new/remodelled importer implementation
	 * <br>fix some nullpointer exceptions
	 * <br>
	 * <br>Revision 1.13  2012-03-15 08:16:07  ferring
	 * <br>space added between job description and filename
	 * <br>
	 * <br>Revision 1.12  2012-02-07 10:45:25  ferring
	 * <br>checking dialog will now always be closed
	 * <br>
	 * <br>Revision 1.11  2012-02-02 15:19:27  ferring
	 * <br>unnecessary NullpointerException prevented
	 * <br>
	 * <br>Revision 1.10  2008-10-15 09:53:00  heinemann
	 * <br>*** empty log message ***
	 * <br>
	 * <br>Revision 1.9  2008-10-08 09:37:26  heinemann
	 * <br>fixed icons
	 * <br>
	 * <br>Revision 1.8  2008-10-02 15:09:41  heinemann
	 * <br>*** empty log message ***
	 * <br>
	 * <br>Revision 1.7  2008-09-25 09:43:08  heinemann
	 * <br>fixed copyrights
	 * <br>
	 * <br>Revision 1.6  2008-09-03 14:08:37  hermen
	 * <br>changed xml validator to show line/column of error
	 * <br>
	 * <br>Revision 1.5  2008-09-03 13:57:29  heinemann
	 * <br>*** empty log message ***
	 * <br>
	 * <br>Revision 1.4  2008-07-23 09:44:53  heinemann
	 * <br>*** empty log message ***
	 * <br>
	 * <br>Revision 1.3  2008-07-22 15:10:21  hermen
	 * <br>updated mappings
	 * <br>
	 * <br>Revision 1.2  2008-07-18 15:41:05  heinemann
	 * <br>*** empty log message ***
	 * <br>
	 * <br>Revision 1.1  2008-07-18 13:44:32  heinemann
	 * <br>*** empty log message ***
	 * <br>
	 *   
	 */
	class FileStatus {
		
		private File file;
		private Status status;
		private String message;
		private String info;
		private Boolean selected4Import = true;
		
		private Boolean forceImport = false;
		
		/**
		 * 
		 */
		public FileStatus() {
			/* ================================================== */

			/* ================================================== */
		}
		
		/**
		 * @param f the file
		 * @param status  valide, invalide or unparsable
		 * @param message the message from the parser or the validator
		 */
		public FileStatus(File f, Status status, String message) {
			/* ================================================== */
			this.file 		= f;
			this.status 	= status;
			this.message 	= message;
			/* ================================================== */
		}

		/**
		 * @return the file
		 */
		public File getFile() {
			return file;
		}

		/**
		 * @param file the file to set
		 */
		public void setFile(File file) {
			this.file = file;
		}

		/**
		 * @return the status
		 */
		public Status getStatus() {
			return status;
		}

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

		/**
		 * @return the message
		 */
		public String getMessage() {
			return message;
		}

		/**
		 * @param message the message to set
		 */
		public void setMessage(String message) {
			this.message = message;
		}

		/**
		 * @return the info
		 */
		public String getInfo() {
			return info;
		}

		/**
		 * @param info the info to set
		 */
		public void setInfo(String info) {
			this.info = info;
		}

		/**
		 * @return the selected4Import
		 */
		public Boolean isSelected4Import() {
			return selected4Import;
		}

		/**
		 * @param selected4Import the selected4Import to set
		 */
		public void setSelected4Import(Boolean selected4Import) {
			this.selected4Import = selected4Import;
		}

		/**
		 * @return the forceImport
		 */
		public Boolean getForceImport() {
			return forceImport;
		}

		/**
		 * @param forceImport the forceImport to set
		 */
		public void setForceImport(Boolean forceImport) {
			this.forceImport = forceImport;
		}
	}
}
