/*******************************************************************************
 * This file is part of GECAMed.
 * 
 * GECAMed is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License (L-GPL) as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * GECAMed is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License (L-GPL)
 * along with GECAMed.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * GECAMed is Copyrighted by the Centre de Recherche Public Henri Tudor (http://www.tudor.lu)
 * (c) CRP Henri Tudor, Luxembourg, 2008
 *******************************************************************************/
package lu.tudor.santec.gecamed.patient.gui.patientexport;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Iterator;

import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.border.TitledBorder;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import lu.tudor.santec.gecamed.billing.gui.TextWrappingCellRenderer;
import lu.tudor.santec.gecamed.core.gui.GECAMedIconNames;
import lu.tudor.santec.gecamed.core.gui.GECAMedLists;
import lu.tudor.santec.gecamed.core.gui.GECAMedLog;
import lu.tudor.santec.gecamed.core.gui.GECAMedModule;
import lu.tudor.santec.gecamed.core.gui.IconFetcher;
import lu.tudor.santec.gecamed.core.gui.MainFrame;
import lu.tudor.santec.gecamed.core.gui.utils.GECAMedGuiUtils;
import lu.tudor.santec.gecamed.core.gui.utils.LineColorCellRenderer;
import lu.tudor.santec.gecamed.core.gui.utils.TableSorter;
import lu.tudor.santec.gecamed.core.gui.widgets.GECAMedBaseDialogImpl;
import lu.tudor.santec.gecamed.core.utils.GECAMedUtils;
import lu.tudor.santec.gecamed.core.utils.ManagerFactory;
import lu.tudor.santec.gecamed.importexport.gui.export.ExportDialog;
import lu.tudor.santec.gecamed.office.ejb.entity.beans.Physician;
import lu.tudor.santec.gecamed.patient.ejb.entity.beans.PatientStub;
import lu.tudor.santec.gecamed.patient.ejb.session.beans.PatientAdminBean;
import lu.tudor.santec.gecamed.patient.ejb.session.interfaces.PatientAdminInterface;
import lu.tudor.santec.gecamed.patient.gui.PatientListModule;
import lu.tudor.santec.gecamed.patient.gui.PatientManagerModule;
import lu.tudor.santec.gecamed.patient.gui.patientlist.PatientListPanel;
import lu.tudor.santec.gecamed.patient.gui.patientlist.PatientSearchSettingsPlugin;
import lu.tudor.santec.i18n.Translatrix;

import org.apache.log4j.Level;
import org.apache.log4j.Logger;

import bizcal.util.DateUtil;

import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;
import com.toedter.calendar.JDateChooser;

/**
 * @author Thorsten Roth thorsten.roth(at)tudor.lu
 * 
 * @version <br>
 *          $Log: PatientExportPanel.java,v $
 *          Revision 1.37  2013-12-27 18:09:26  donak
 *          Cleanup of imports
 *
 *          Revision 1.36  2013-07-22 08:06:03  troth
 *          Add treated and  attending physician to the query of the invoice.
 *
 *          Revision 1.35  2013-07-15 06:18:39  ferring
 *          logging changed
 *
 *          Revision 1.34  2013-06-27 13:00:29  troth
 *          Add dialog if too many patients have been found and causes a EJBException.
 *
 *          Revision 1.33  2013-06-26 15:59:30  troth
 *          *** empty log message ***
 *
 *          Revision 1.32  2013-06-26 15:30:16  troth
 *          Add function to load xsl-fo template form server.
 *
 *          Revision 1.31  2013-06-18 11:55:32  troth
 *          Add CurrentPhysician as value to the fo-document.
 *
 *          Revision 1.30  2013-04-30 14:20:19  troth
 *          Fix NullPointerException if start or end date not set.
 *
 *          Revision 1.29  2013-04-25 09:49:54  troth
 *          1. Checkboxes in exportpanel now deselect if patient is export.
 *          2. Add applybox to the 'Export-Done'-Dialog and function to open the directory where the export files are save.
 *
 *          Revision 1.28  2013-04-24 13:00:06  troth
 *          Bug Fix: Find not patient if start and end date was the same date.
 *
 *          Revision 1.27  2013-04-24 07:43:07  troth
 *          Check in light version for release.
 *
 *          Revision 1.26  2013-04-24 07:20:07  troth
 *          Fix Bug: DB-query select patients with acts and invoices when the condition attending or treated physician was select.
 *
 *          Revision 1.25  2013-04-23 12:26:42  troth
 *          Bug Fix: Export all and not the selected Patients.
 *
 *          Revision 1.24  2013-04-23 09:57:55  troth
 *          Remove Syso.
 *
 *          Revision 1.23  2013-04-23 09:57:15  troth
 *          Bug Fix: If only 'Patients Physician' was selected the DB-Query was build wrong.
 *
 *          Revision 1.22  2013-04-22 12:58:26  troth
 *          GUI changes.
 *
 *          Revision 1.21  2013-04-22 10:35:46  troth
 *          Add message-dialog 'no patient found'.
 *
 *          Revision 1.20  2013-04-22 10:02:11  troth
 *          Smaller export version for 1.3.02 release.
 *
 *          Revision 1.19  2013-04-18 14:58:08  troth
 *          Add patient to the export query which have a act in the table billing in the database.
 *
 *          Revision 1.18  2013-04-16 16:28:44  troth
 *          Fix Bug: If search result was under the max search value the result was not show.
 *
 *          Revision 1.17  2013-04-15 09:44:39  troth
 *          Add some translations.
 *          Correct the count of patients which are successfully exported / opened.
 *          Code clearup.
 *
 *          Revision 1.16  2013-03-25 10:15:26  troth
 *          Change the behavior of the search limit reach dialog. If user now press cancel no search results find.
 *
 *          Revision 1.15  2013-03-21 15:35:44  troth
 *          1. Add a dialog inform the user if patienten search limit is reach.
 *          2. Make some GUI changes.
 *
 *          Revision 1.14  2013-03-20 10:41:19  troth
 *          Add translation. Add icon to popup.
 *
 *          Revision 1.13  2013-03-11 14:37:28  troth
 *          Add column with physician.
 *
 *          Revision 1.12  2013-03-11 10:08:14  troth
 *          Little GUI changes.
 *
 *          Revision 1.11  2013-02-25 11:03:17  troth
 *          Fix: Patientlist update after add patient.
 *
 *          Revision 1.10  2013-02-25 10:32:17  troth
 *          Add function to add patients from the patientsearch tab the patientexport tab.
 *
 *          Revision 1.9  2013-02-19 15:08:58  troth
 *          Add functionality to export the first patient in list in the syso, by press ok-button only for testing.
 *
 *          Revision 1.8  2013-02-19 13:58:03  troth
 *          Add the patient export dialog GUI.
 *
 *          Revision 1.6  2013-02-14 16:28:48  troth
 *          Change the export search data for patient to patientStub
 * <br>
 *          Revision 1.5 2013-02-13 15:18:23 troth <br>
 *          Code clearup. <br>
 * <br>
 *          Revision 1.4 2013-02-13 14:26:48 troth <br>
 *          add new GUI elements for the MM Export tab in the
 *          PatientExportPanel. <br>
 * <br>
 *          Revision 1.3 2013-02-13 11:38:43 troth <br>
 *          add new GUI elements for the MM Export tab in the
 *          PatientExportPanel. <br>
 * <br>
 *          Revision 1.2 2013-02-12 17:22:14 troth <br>
 *          add new function for the MM Export tab to search for patient. <br>
 * <br>
 *          Revision 1.1 2013-01-23 16:50:50 troth <br>
 *          add new GUI for the MM Export tab the PatientExportPanel. <br>
 */
public class PatientExportPanel extends JPanel implements MouseListener {

	private static final long 				serialVersionUID = 1L;
	
	private static Logger 					logger = Logger.getLogger(PatientExportPanel.class.getName());
	
	protected static final long 			SEARCH_WAIT_TIMEOUT = 300;

	private PatientExportStubListTableModel patientListTableModel;

	private TableSorter 					tableSorter;

	private JTable 							patientTable;

	private PatientAdminInterface 			manager;

	private PatientListModule 				patientListModule;

	private ArrayList<PatientStub> 			patients = new ArrayList<PatientStub>();
	
	private ArrayList<Integer> 				selectedPatients = new ArrayList<Integer>();
	
	private PatientManagerModule 			patientManagerModule;

	private JScrollPane 					jsp;

	private JPopupMenu 						popup;

	private boolean 						searchRunning;

	private Font 							bgFont = new Font("Plain", Font.BOLD, 64);

	private boolean 						BIG_FONTS;

	protected boolean 						openPatient;

	private JPanel 							inputPanel;

	private JPanel 							outputPanel;

	private JPanel 							setPanel;

	private CellConstraints 				cc;

	private JCheckBox 						dateConditionCheckBox;

	private JDateChooser 					dateConditionStartDateChooser;

	private JDateChooser 					dateConditionEndDateChooser;

	private JCheckBox 						attendingPhyConditionCheckBox;

	private JComboBox 						attendingPhyConditionComboBox;

	private JCheckBox 						treatedPhyConditionCheckBox;

	private JComboBox			 			treatedPhyConditionComboBox;

	private JButton 						searchButton;

	private JButton 						openExportPatientsDialog;
	
	private JLabel 							selectedAndCountedPatientLabel;
	
	private int 							maxPatientsToshow;

	public static int 						exportDialogOptions = 0;
	
	public static File 						startDirectory = null;

	public PatientExportPanel(final PatientListModule patientListModule,final PatientManagerModule patientManagerModule)
	{
		this.setOpaque(false);

		try {
			BIG_FONTS = (Boolean) patientListModule.patientListSettingsPlugin.getValue(PatientSearchSettingsPlugin.SEARCH_BIG_FONTS);
		} catch (Exception e) {
			logger.log(Level.WARN, "Can't load BIG_FONTS", e);
		}

		this.patientListModule = patientListModule;
		this.patientManagerModule = patientManagerModule;

		this.cc = new CellConstraints();
		buildInputPanel();
		buildOutputPanel();
		buildSetPanel();
		buildPanel();
	}

	private void buildPanel() {
		this.setLayout(new FormLayout("3px, fill:pref:grow, 3px",
				"3px, fill:pref, 3px, fill:pref:grow, 3px, fill:pref"));
		this.add(this.inputPanel, cc.xy(2, 2));
		this.add(this.outputPanel, cc.xy(2, 4));
		this.add(this.setPanel, cc.xy(2, 6));
	}

	/**
	 * Build the input panel where the user can set the search conditions.
	 */
	private void buildInputPanel() {
		this.inputPanel = new JPanel(new FormLayout(
				"3px, pref, 3px, 130px, 3px, 130px, 15px, 36px, 3px, 36px, 3px",
				"3px, pref, 3px, 36px, 3px, pref, 3px"));
		this.inputPanel.setBorder(new TitledBorder(""));
		this.inputPanel.setOpaque(false);
		// condition date
		dateConditionCheckBox = new JCheckBox(Translatrix.getTranslationString("patientExport.conditionDate"));
		dateConditionCheckBox.setToolTipText(Translatrix.getTranslationString("patientExport.conditionDate.toolTip"));
		dateConditionCheckBox.setOpaque(false);
		dateConditionCheckBox.addItemListener(new ItemListener()
		{
			public void itemStateChanged(ItemEvent e)
			{
				if(e.getStateChange() == ItemEvent.DESELECTED)
				{
					dateConditionStartDateChooser.setEnabled(false);
					dateConditionEndDateChooser.setEnabled(false);
				}
				if(e.getStateChange() == ItemEvent.SELECTED)
				{
					dateConditionStartDateChooser.setEnabled(true);
					dateConditionEndDateChooser.setEnabled(true);
				}
//				setSearchButtonUsability();
			}
		});
		Calendar now = new GregorianCalendar();
		dateConditionStartDateChooser = GECAMedGuiUtils.getDateChooser(false);
		dateConditionStartDateChooser.setDate(now.getTime());
		dateConditionEndDateChooser = GECAMedGuiUtils.getDateChooser(false);
		dateConditionEndDateChooser.setDate(now.getTime());
		dateConditionStartDateChooser.setEnabled(false);
		dateConditionEndDateChooser.setEnabled(false);
		
		this.inputPanel.add(dateConditionCheckBox, cc.xy(2, 2));
		this.inputPanel.add(dateConditionStartDateChooser, cc.xy(4, 2));
		this.inputPanel.add(dateConditionEndDateChooser, cc.xy(6, 2));

		// condition attending physician
		attendingPhyConditionCheckBox = new JCheckBox(Translatrix.getTranslationString("patientExport.conditionAttendingPhysician"));
		attendingPhyConditionCheckBox.setToolTipText(Translatrix.getTranslationString("patientExport.conditionAttendingPhysician.toolTip"));
		attendingPhyConditionCheckBox.setOpaque(false);
		attendingPhyConditionCheckBox.addItemListener(new ItemListener()
		{	
			public void itemStateChanged(ItemEvent e)
			{
				if(e.getStateChange() == ItemEvent.DESELECTED)
				{
					attendingPhyConditionComboBox.setEnabled(false);
				}
				if(e.getStateChange() == ItemEvent.SELECTED)
				{
					attendingPhyConditionComboBox.setEnabled(true);
				}
//				setSearchButtonUsability();
			}
		});
		Physician[] phys = GECAMedLists.getArray(Physician.class);
		PhysicianComboBoxModel attendingphyComboBoxModel = new PhysicianComboBoxModel(phys);
		attendingPhyConditionComboBox = new JComboBox(attendingphyComboBoxModel);
		//attendingPhyConditionComboBox.setFont(attendingPhyConditionComboBox.getFont().deriveFont(Font.BOLD, 16));
		attendingPhyConditionComboBox.setOpaque(true);
		attendingPhyConditionComboBox.setEnabled(false);
		this.inputPanel.add(attendingPhyConditionCheckBox, cc.xy(2, 4));
		this.inputPanel.add(attendingPhyConditionComboBox, cc.xyw(4, 4, 3));
		// condition been treated by physician
		treatedPhyConditionCheckBox = new JCheckBox(Translatrix.getTranslationString("patientExport.conditionTreatedByPhysician"));
		treatedPhyConditionCheckBox.setToolTipText(Translatrix.getTranslationString("patientExport.conditionTreatedByPhysician.toolTip"));
		treatedPhyConditionCheckBox.setOpaque(false);
		treatedPhyConditionCheckBox.addItemListener(new ItemListener()
		{	
			public void itemStateChanged(ItemEvent e)
			{
				if(e.getStateChange() == ItemEvent.DESELECTED)
				{
					treatedPhyConditionComboBox.setEnabled(false);	
				}
				if(e.getStateChange() == ItemEvent.SELECTED)
				{
					treatedPhyConditionComboBox.setEnabled(true);
				}
//				setSearchButtonUsability();
			}
		});
		PhysicianComboBoxModel treatedphyComboBoxModel = new PhysicianComboBoxModel(phys);
		treatedPhyConditionComboBox = new JComboBox(treatedphyComboBoxModel);
		//treatedPhyConditionComboBox.setFont(treatedPhyConditionComboBox.getFont().deriveFont(Font.BOLD, 16));
		treatedPhyConditionComboBox.setOpaque(true);
		treatedPhyConditionComboBox.setEnabled(false);
		this.inputPanel.add(treatedPhyConditionCheckBox, cc.xy(2, 6));
		this.inputPanel.add(treatedPhyConditionComboBox, cc.xyw(4, 6, 3));

		// search button
		searchButton = new JButton(GECAMedModule.getIcon(GECAMedIconNames.SEARCH));
		searchButton.addActionListener(new ActionListener() {

			public void actionPerformed(ActionEvent e) {
				maxPatientsToshow = 0;
				// count patients to export
				maxPatientsToshow = searchPatients(true);
				// if more patients to export as the search limit than ask user if its ok
				if(maxPatientsToshow > ((Integer) patientListModule.patientListSettingsPlugin.getValue(PatientSearchSettingsPlugin.SEARCH_LIMIT)).intValue())
				{
					String[] para = {"" + maxPatientsToshow };
					int result = GECAMedBaseDialogImpl.showMessageDialog(PatientExportPanel.this, Translatrix.getTranslationString("patientExport.infoMessageTitle"), Translatrix.getTranslationString("patientExport.infoSearchLimitReached",para), GECAMedBaseDialogImpl.YES_NO_BUTTON_MODE);
					if(result == GECAMedBaseDialogImpl.YES_OPTION)
					{
						// search patients to export
						setWaitCursor(true);
						searchPatients(false);
						setWaitCursor(false);
					}	
				}else{
					// search patients to export
					setWaitCursor(true);
					searchPatients(false);
					setWaitCursor(false);
				}
				// show the number of selected and the counted patient in the status bar (SetPanel)
				selectedAndCountedPatientLabel.setText(selectedPatients.size() + " / " + maxPatientsToshow);
			}
		});
		this.inputPanel.add(searchButton, cc.xy(8, 4));
//		searchButton.setEnabled(false);
		
		//open export dialog
		openExportPatientsDialog = new JButton(GECAMedModule.getIcon(GECAMedIconNames.EXPORT));
		openExportPatientsDialog.setSize(32, 32);
		openExportPatientsDialog.addActionListener(new ActionListener() {

			public void actionPerformed(ActionEvent e)
			{
				// open the patients export Dialog
				if(selectedPatients.size() > 0)
				{
//					// set patients list to selected patients
//					searchSelectPatients();
					// open dialog
					ExportDialog exportdialog  = new ExportDialog(PatientExportPanel.this, selectedPatients);
					exportdialog.setOptions(exportDialogOptions);
					exportdialog.setStartDirectory(startDirectory);
					exportdialog.showCenteredDialog();
					exportDialogOptions = exportdialog.getOptions();
					startDirectory = exportdialog.getStartDirectory();
				}
			}
		});
		this.inputPanel.add(openExportPatientsDialog, cc.xy(10, 4));
		openExportPatientsDialog.setEnabled(false);
	}

	private void buildOutputPanel() {
		this.outputPanel = new JPanel();
		this.outputPanel.setLayout(new BorderLayout());
		this.outputPanel.setOpaque(false);
		this.patientListTableModel = new PatientExportStubListTableModel();

		manager = (PatientAdminInterface) ManagerFactory.getRemote(PatientAdminBean.class);

		this.tableSorter = new TableSorter(this.patientListTableModel);

		this.patientTable = new JTable(this.tableSorter);
		this.patientTable.setOpaque(false);
		this.patientTable.addMouseListener(this);
		this.patientTable.getTableHeader().setReorderingAllowed(false);
		int w = this.patientTable.getTableHeader().getPreferredSize().width;
		this.patientTable.getTableHeader().setPreferredSize(new Dimension(w,18));
		this.patientTable.getTableHeader().setSize(w, 18);
		this.patientTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

		int alpha = 150;

		int gap = 0;
		double factor = 1;
		Font font = new JLabel().getFont().deriveFont(Font.PLAIN);
		if (BIG_FONTS) {
			font = font.deriveFont(Font.BOLD, 14);
			gap = 5;
			factor = 1.2;
		}
		LineColorCellRenderer renderer = new LineColorCellRenderer(alpha, font,false);
		LineColorCellRenderer centeredRenderer = new LineColorCellRenderer(alpha, font, true);
		this.patientTable.getColumnModel().getColumn(0).setMaxWidth((int) (38 * factor));
		this.patientTable.getColumnModel().getColumn(0).setResizable(false);
		this.patientTable.getColumnModel().getColumn(1).setCellRenderer(renderer);
		this.patientTable.getColumnModel().getColumn(1).setMinWidth((int) (100 * factor));
		this.patientTable.getColumnModel().getColumn(2).setCellRenderer(renderer);
		this.patientTable.getColumnModel().getColumn(2).setMinWidth((int) (150 * factor));
		this.patientTable.getColumnModel().getColumn(3).setCellRenderer(renderer);
		this.patientTable.getColumnModel().getColumn(3).setMinWidth((int) (150 * factor));
		this.patientTable.getColumnModel().getColumn(4).setCellRenderer(renderer);
		this.patientTable.getColumnModel().getColumn(4).setMinWidth((int) (150 * factor));
		this.patientTable.getColumnModel().getColumn(5).setCellRenderer(centeredRenderer);
		this.patientTable.getColumnModel().getColumn(5).setMaxWidth((int) (20 * factor));
		this.patientTable.getColumnModel().getColumn(6).setCellRenderer(renderer);
		this.patientTable.getColumnModel().getColumn(6).setMinWidth((int) (50 * factor));
		this.patientTable.getColumnModel().getColumn(7).setCellRenderer(new TextWrappingCellRenderer(alpha, font, gap));
		this.patientTable.getColumnModel().getColumn(7).setMinWidth((int) (350 * factor));
		this.patientTable.getColumnModel().getColumn(8).setCellRenderer(new TextWrappingCellRenderer(alpha, font, gap));
		this.patientTable.getColumnModel().getColumn(8).setMinWidth((int) (180 * factor));
		this.patientTable.getColumnModel().getColumn(9).setCellRenderer(renderer);
		this.patientTable.getColumnModel().getColumn(9).setMinWidth((int) (50 * factor));
		this.patientTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);

		this.patientTable.getSelectionModel().addListSelectionListener(new ListSelectionListener()
		{
					public void valueChanged(ListSelectionEvent e)
					{
						patientTable.scrollRectToVisible(patientTable.getCellRect(patientTable.getSelectedRow(), 0, true));
					}
				});
		/* ------------------------------------------------------- */
		// create a popup menu on right clicks
		popup = new JPopupMenu();
		// open in a new tap in the patientview
		JMenuItem openNewtab = new JMenuItem(Translatrix
				.getTranslationString("list.openInNewTab"), IconFetcher
				.getSmallIcon(PatientManagerModule.class,
						PatientManagerModule.OPEN_PATIENT_IN_TAB));
		openNewtab.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				loadPatient(true);
			}
		});
		popup.add(openNewtab);
		/* ------------------------------------------------------- */
		// select or deselect a patient in the exportview
		JMenuItem selectPatient = new JMenuItem(Translatrix.getTranslationString("patientExport.select"),
				GECAMedModule.getSmallIcon(GECAMedIconNames.OK));
		
		selectPatient.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				// Switch CheckBox
				if (patientTable.getSelectedRow() == -1) 
				{
					logger.info("unable to open patient: No patient selected");
					return;
				}

				Integer patientID = patientListTableModel.getPatientIDforRow(tableSorter.modelIndex(patientTable.getSelectedRow()));

				if (selectedPatients.contains(patientID))
				{
					selectedPatients.remove(patientID);
					
					patientTable.repaint();
				} else {
					selectedPatients.add(patientID);
					patientTable.repaint();
				}
				
				if(selectedPatients.size() <= 0)
					openExportPatientsDialog.setEnabled(false);
				else
					openExportPatientsDialog.setEnabled(true);
			}
		});
		popup.add(selectPatient);

		// enable sorting the table
		this.tableSorter.setTableHeader(this.patientTable.getTableHeader());
		jsp = new JScrollPane(this.patientTable);
		jsp.setOpaque(false);
		jsp.getViewport().setOpaque(false);
		jsp.setAutoscrolls(true);
		jsp.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);

		this.outputPanel.add(jsp, BorderLayout.CENTER);

		// load selected patient on ENTER
		this.patientTable.addKeyListener(new KeyListener() {

			public void keyTyped(KeyEvent e) {
				if (e.getKeyCode() == KeyEvent.VK_ENTER)
					e.consume();
			}

			public void keyPressed(KeyEvent e) {
				if (e.getKeyCode() == KeyEvent.VK_ENTER)
					e.consume();
			}

			public void keyReleased(KeyEvent e) {
				if (e.getKeyCode() == KeyEvent.VK_ENTER) {
					e.consume();
					loadPatient((Boolean) patientListModule.patientListSettingsPlugin.getValue(PatientSearchSettingsPlugin.OPEN_PATIENT_IN_NEW_TAB));
				}
			}
		});
	}

	private void buildSetPanel()
	{
		this.setPanel = new JPanel(new FormLayout(
				"3px, pref, 3px, pref, 13px, pref, 3px", "3px, pref, 3px"));
		this.setPanel.setBorder(new TitledBorder(""));
		this.setPanel.setOpaque(false);
		JCheckBox selectAllCheckBox = new JCheckBox(Translatrix.getTranslationString("patientExport.selectAllCheckBox"));
		selectAllCheckBox.setOpaque(false);
		selectAllCheckBox.addActionListener(new ActionListener() {

			public void actionPerformed(ActionEvent e) {
				Object source = e.getSource();
				selectAllPatients(((JCheckBox) source).isSelected());
			}
		});
		this.setPanel.add(selectAllCheckBox, cc.xy(2, 2));

		JButton showSelectedPatients = new JButton(Translatrix.getTranslationString("patientExport.showSelectedPatients"));
		showSelectedPatients.addActionListener(new ActionListener() {

			public void actionPerformed(ActionEvent e) {
				patients.clear();
				searchSelectPatients();
				patientListTableModel.setPatients(patients, selectedPatients);
				// count patients to update label
				maxPatientsToshow = selectedPatients.size();
				selectedAndCountedPatientLabel.setText(selectedPatients.size() + " / " + maxPatientsToshow);
			}
		});
		this.setPanel.add(showSelectedPatients, cc.xy(4, 2));
		selectedAndCountedPatientLabel = new JLabel("0 / 0");
		this.setPanel.add(selectedAndCountedPatientLabel, cc.xy(6, 2));
	}

	
	public synchronized void searchSelectPatients()
	{
		long start = System.currentTimeMillis();
		StringBuffer queryString = new StringBuffer("SELECT DISTINCT OBJECT(p) FROM PatientStub p");
		
		if (selectedPatients.isEmpty())
			queryString.append(" where p.id IN (" + null + ") ");
		else {
			queryString.append(" where p.id IN (");
			for (Iterator<Integer> iterator = selectedPatients.iterator(); iterator
					.hasNext();) {
				Integer patientId = (Integer) iterator.next();
				if (iterator.hasNext())
					queryString.append(patientId + ", ");
				else
					queryString.append(patientId);
			}

			
			queryString.append(")");
		}
		
		try {
			patients = new ArrayList<PatientStub>(manager.findPatientToExport(queryString.toString(), maxPatientsToshow));
		} catch (Exception e) {
			logger.log(Level.WARN, "Can't find patient to export.", e);
		}

		patientListTableModel.setPatients(patients, selectedPatients);
		long took = (System.currentTimeMillis() - start);
		
		
		
		GECAMedLog.user(PatientListModule.MODULE_NAME,PatientManagerModule.SEARCH_PATIENT, "Search for \""
						+ queryString.toString() + " returned "
						+ patientListTableModel.getRowCount() + " results "
						+ "\" took " + took + "ms", took);
//		System.out.println("Search took: " + took + "ms | " + "returned: "
//				+ patientListTableModel.getRowCount()
//				+ " results | query: " + queryString.toString());
	}
	
	public synchronized int searchPatients(Boolean count)
	{
		long start = System.currentTimeMillis();
		
		// check conditions for query
		ArrayList<String> conditions = new ArrayList<String>();
		// int conditionCounter = 0;
		
		Date startDate = new Date();
		Date endDate = new Date();
		String strStartDate = "";
		String strEndDate = "";
		
		if (dateConditionCheckBox.isSelected()) {
			startDate = dateConditionStartDateChooser.getDate();
			endDate = dateConditionEndDateChooser.getDate();
			
			if (startDate != null)
			{
				strStartDate = DateUtil.move2Morning(startDate).toString();
				conditions.add("pi.incident_date >= '" + strStartDate + "'");
			}
			if (endDate != null)
			{
				strEndDate = DateUtil.move2Midnight(endDate).toString();
				conditions.add("pi.incident_date <= '" + strEndDate + "'");
			}
		}

		if (attendingPhyConditionCheckBox.isSelected()) // main doc (doctor_id)
		{
			Physician phy = (Physician) attendingPhyConditionComboBox.getSelectedItem();
			conditions.add("pp.doctor_id = " + phy.getId());
		}

		if (treatedPhyConditionCheckBox.isSelected()) {
			Physician phy = (Physician) treatedPhyConditionComboBox
					.getSelectedItem();
			conditions.add("pi.physician_id = " + phy.getId());
		}
		// Build two several queries one for counting and one for select the objects  
		StringBuffer queryString = new StringBuffer("");
		// select Patient over incident
		if(count) queryString.append("SELECT COUNT(id) FROM ( ");
		else queryString.append("SELECT id FROM ( ");
		queryString.append("SELECT DISTINCT pp.id AS id FROM patient.patient_Stub AS pp");

		if (!dateConditionCheckBox.isSelected()
				&& attendingPhyConditionCheckBox.isSelected()
				&& !treatedPhyConditionCheckBox.isSelected()) {
			queryString.append(" WHERE ");
		} else {
			queryString.append(", patient.incidents AS pi ");
			queryString.append("WHERE pp.id = pi.patient_id ");
		}

		for (int i = 0; i < conditions.size(); i++) {
			if (i == 0 && !dateConditionCheckBox.isSelected()
					&& attendingPhyConditionCheckBox.isSelected()
					&& !treatedPhyConditionCheckBox.isSelected())
				queryString.append(conditions.get(i) + " ");
			else
				queryString.append("AND " + conditions.get(i) + " ");
		}
		
		if (dateConditionCheckBox.isSelected())
		{
			// act & invoice is to be considered only if date is set
			queryString.append("UNION SELECT DISTINCT pp.id AS id FROM patient.patient_stub AS pp, billing.act AS ba, billing.invoice AS bi ");
			queryString.append("WHERE bi.patient_id = pp.id ");
			queryString.append("AND bi.id = ba.invoice_id ");
			if(startDate != null)
			{
				strStartDate = DateUtil.move2Morning(startDate).toString();
				queryString.append("AND ba.performed >= '" + strStartDate + "' ");
			}
			if(endDate != null)
			{
				strEndDate = DateUtil.move2Midnight(endDate).toString();
				queryString.append("AND ba.performed <= '" + strEndDate + "' ");
			}
			
			if(attendingPhyConditionCheckBox.isSelected())
			{
				Physician phy = (Physician) attendingPhyConditionComboBox.getSelectedItem();
				queryString.append("AND pp.doctor_id = " + phy.getId());
			}
			
			if(treatedPhyConditionCheckBox.isSelected())
			{
				Physician phy = (Physician) treatedPhyConditionComboBox.getSelectedItem();
				queryString.append("AND bi.physician_id = " + phy.getId());
			}
		}
		
		if (!selectedPatients.isEmpty())
		{
			queryString.append("UNION SELECT DISTINCT pp.id AS id FROM patient.patient_stub AS pp ");
			queryString.append("WHERE pp.id IN (");

			for (Iterator<Integer> iterator = selectedPatients.iterator(); iterator
					.hasNext();) {
				Integer patientId = (Integer) iterator.next();
				if (iterator.hasNext())
					queryString.append(patientId + ", ");
				else
					queryString.append(patientId);
			}

			queryString.append(")");
		}
		queryString.append(") sub");
		
		if(count)
		{
			BigInteger result = null;
			try {
				result = manager.countPatientToExport(queryString.toString());
			} catch (Exception e1) {
				logger.log(Level.WARN, "Can't count patient to export.", e1);
			}
			return result.intValue();
		}else{
			try {
				ArrayList<Integer> patientIds = new ArrayList<Integer>(manager.findPatientIdsToExport(queryString.toString(), maxPatientsToshow));
				if(patientIds != null)
				{
					if(patientIds.size() > 0)
					{
						queryString.setLength(0);
						queryString.append("SELECT Object(p) FROM PatientStub AS p WHERE p.id IN (");
						for(int i=0;i < patientIds.size();i++)
						{
							if (i < patientIds.size() - 1)
								queryString.append(patientIds.get(i) + ", ");
							else
								queryString.append(patientIds.get(i));
						}
						queryString.append(")");
						patients = new ArrayList<PatientStub>(manager.findPatientToExport(queryString.toString(), maxPatientsToshow));
						patientListTableModel.setPatients(patients, selectedPatients);
					}else{
						// show dialog no Patient for export found
						GECAMedBaseDialogImpl.showMessageDialog(PatientExportPanel.this, Translatrix.getTranslationString("patientExport.infoMessageTitle"), Translatrix.getTranslationString("patientExport.infoNoPatientFound"), GECAMedBaseDialogImpl.OK_BUTTON_MODE);
						patients.clear();
						selectedPatients.clear();
						patientListTableModel.setPatients(patients, selectedPatients);
					}
				}
			} catch (Exception e) {
				GECAMedBaseDialogImpl.showMessageDialog(this, Translatrix.getTranslationString("patientExport.infoMessageTitle"), Translatrix.getTranslationString("patientExport.infoTooManyPatientFound"), GECAMedBaseDialogImpl.OK_BUTTON_MODE);
				logger.log(Level.WARN, "Can't find patient to export.", e);
			}
			long took = (System.currentTimeMillis() - start);
			GECAMedLog.user(PatientListModule.MODULE_NAME,
					PatientManagerModule.SEARCH_PATIENT, "Search for \""
					+ queryString.toString() + " returned "
					+ patientListTableModel.getRowCount() + " results "
					+ "\" took " + took + "ms", took);
				
		}
		return 0;
	}

	/**
	 * load the patient
	 * 
	 * @param inNewTab
	 *            if true patient is loaded in a new tab.
	 */
	private void loadPatient(boolean inNewTab) {

		// wait for search finished
		if (searchRunning) {
			MainFrame.getInstance().showMessage(
					Translatrix.getTranslationString("pm.searchingPleaseWait"));
			return;
		}

		int patientID = -1;
		if (this.patientTable.getSelectedRow() == -1) {
			logger.info("unable to open patient: No patient selected");
			return;
		}

		// if search has been done in the search module, open the last selected
		// module
		if (patientListModule.getName().equals(
				MainFrame.getInstance().getSelectedModule())) {

			// get the last selected module
			String moduleName = (String) patientListModule.patientListSettingsPlugin
					.getValue(PatientSearchSettingsPlugin.OPEN_PATIENT_IN_MODULE);
			if (moduleName.equals(GECAMedModule.LAST_SELECTED_MODULE)) {
				if (MainFrame.getInstance().lastModule != null && MainFrame.getInstance().lastModule.canDisplayPatient())
					moduleName = MainFrame.getInstance().lastModule.getName();
				else
					moduleName = PatientManagerModule.MODULE_NAME;
			}
			// System.out.println("switch Module: " + moduleName);
			MainFrame.getInstance().selectModule(moduleName);
		}

		try {
			// now we load the patient!
			patientID = this.patientListTableModel.getPatientIDforRow(this.tableSorter.modelIndex(this.patientTable.getSelectedRow()));
			this.patientManagerModule.addPatient(this.manager.getPatient(patientID), inNewTab);
		} catch (Exception e1) {
			logger.info("unable to open patient with ID: " + patientID);
			// log
			GECAMedLog.error(PatientListModule.MODULE_NAME, PatientListPanel.OPEN_PATIENT, "unable to open patient with ID: " + patientID, null);
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.awt.event.MouseListener#mouseClicked(java.awt.event.MouseEvent)
	 */
	public void mouseClicked(MouseEvent e) {
		if ((e.getClickCount() >= 2) && this.patientTable.equals(e.getSource())) {
			loadPatient((Boolean) patientListModule.patientListSettingsPlugin
					.getValue(PatientSearchSettingsPlugin.OPEN_PATIENT_IN_NEW_TAB));
		} else if (e.isPopupTrigger()) {
			int row = patientTable.rowAtPoint(e.getPoint());
			patientTable.setRowSelectionInterval(row, row);
			popup.show(e.getComponent(), e.getX(), e.getY());
		} else if (e.getButton() == MouseEvent.BUTTON2) {
			int row = patientTable.rowAtPoint(e.getPoint());
			patientTable.setRowSelectionInterval(row, row);
			loadPatient(true);
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.awt.event.MouseListener#mousePressed(java.awt.event.MouseEvent)
	 */
	public void mousePressed(MouseEvent e) {
		if (e.isPopupTrigger()) {
			int row = patientTable.rowAtPoint(e.getPoint());
			patientTable.setRowSelectionInterval(row, row);
			popup.show(e.getComponent(), e.getX(), e.getY());
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * java.awt.event.MouseListener#mouseReleased(java.awt.event.MouseEvent)
	 */
	public void mouseReleased(MouseEvent e) {
		if (e.isPopupTrigger()) {
			int row = patientTable.rowAtPoint(e.getPoint());
			patientTable.setRowSelectionInterval(row, row);
			popup.show(e.getComponent(), e.getX(), e.getY());
		} else {
			// Switch CheckBox
			int col = patientTable.columnAtPoint(e.getPoint());

			if (col == 0)
			{
				Integer patientID = this.patientListTableModel.getPatientIDforRow(this.tableSorter.modelIndex(this.patientTable.getSelectedRow()));
				
				if (selectedPatients.contains(patientID)) {
					selectedPatients.remove(patientID);
					selectedAndCountedPatientLabel.setText(selectedPatients.size() + " / " + maxPatientsToshow);
					patientTable.repaint();
				} else {
					selectedPatients.add(patientID);
					selectedAndCountedPatientLabel.setText(selectedPatients.size() + " / " + maxPatientsToshow);
					patientTable.repaint();
				}
				if(selectedPatients.size() <= 0)
					openExportPatientsDialog.setEnabled(false);
				else
					openExportPatientsDialog.setEnabled(true);
			}
		}
	}

	public void mouseEntered(MouseEvent e) {}

	public void mouseExited(MouseEvent e) {}
	
	/**
	 * sets the Mousecursor of the MainFrame to a WaitCursor and Back
	 * 
	 * @param on
	 *            true=waitcursor false=normalcursor
	 */
	public void setWaitCursor(boolean on)
	{
		if (on) {
			// MainFrame.getInstance().setWaitCursor(true);

			MainFrame.getInstance().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
			// this.jsp.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
			// this.patientTable.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
			// this.searchTextField.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
			// this.searchAddressPhoneField.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
			// this.searchMatriculeField.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
		} else {
			// MainFrame.getInstance().setWaitCursor(false);

			// MainFrame.getInstance().locked = true;

			MainFrame.getInstance().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
			// this.jsp.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
			// this.patientTable.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
			// this.searchTextField.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
			// this.searchAddressPhoneField.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
			// this.searchMatriculeField.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
		}
	}

	/**
	 * Select or deselect all patient in the list panel.
	 * @param selectAll true = select, false = deselect
	 */
	public void selectAllPatients(Boolean selectAll) {
		selectedPatients.clear();
		selectedAndCountedPatientLabel.setText(selectedPatients.size() + " / " + maxPatientsToshow);
		if (selectAll) {
			for (PatientStub patientStub : patients) {
				selectedPatients.add(patientStub.getId());
			}
			selectedAndCountedPatientLabel.setText(selectedPatients.size() + " / " + maxPatientsToshow);
		}
		if(selectedPatients.size() <= 0)
			openExportPatientsDialog.setEnabled(false);
		else
			openExportPatientsDialog.setEnabled(true);
		this.patientTable.repaint();
	}
	
	public void removeSelectPatient(Integer index)
	{
		this.selectedPatients.remove(index);
		selectedAndCountedPatientLabel.setText(selectedPatients.size() + " / " + maxPatientsToshow);
		this.patientTable.repaint();
	}

	/**
	 * Enable and disable the search button, if no condition is the search button is disable.
	 */
//	private void setSearchButtonUsability()
//	{
//		if(dateConditionCheckBox.isSelected() || treatedPhyConditionCheckBox.isSelected() || attendingPhyConditionCheckBox.isSelected())
//		{
//			searchButton.setEnabled(true);
//		} else {
//			searchButton.setEnabled(false);
//		}
//		
//	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see javax.swing.JComponent#paint(java.awt.Graphics)
	 */
	@Override
	public void paint(Graphics g) {
		if (GECAMedUtils.isDemo()) {
			g.setColor(new Color(0, 0, 0, 100));
			g.setFont(bgFont);
			g.drawString(Translatrix.getTranslationString("core.demo"), 200,350);
		}
		super.paint(g);
	}

	class PhysicianComboBoxModel extends DefaultComboBoxModel {

		private static final long serialVersionUID = 1L;

		public PhysicianComboBoxModel(Physician[] phys) {
			super(phys);
		}

	}

	public void addPatient(Integer pId)
	{
		selectedPatients.add(pId);
		// set maxPatientsToshow 
		maxPatientsToshow = searchPatients(true);
		searchSelectPatients();
		if(selectedPatients.size() <= 0)
			openExportPatientsDialog.setEnabled(false);
		else
			openExportPatientsDialog.setEnabled(true);
	}

	public ArrayList<Integer> getSelectedPatients()
	{
		return this.selectedPatients;
	}
}