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

import java.awt.Color;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;

import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import javax.swing.JTextField;

import lu.tudor.santec.gecamed.core.ejb.entity.beans.Gender;
import lu.tudor.santec.gecamed.core.ejb.entity.beans.Language;
import lu.tudor.santec.gecamed.core.ejb.entity.beans.Title;
import lu.tudor.santec.gecamed.core.gui.utils.AutoCompletion;
import lu.tudor.santec.gecamed.core.gui.utils.GECAMedGuiUtils;
import lu.tudor.santec.gecamed.core.gui.widgets.LimitTextField;
import lu.tudor.santec.gecamed.core.gui.widgets.SSNField;
import lu.tudor.santec.gecamed.core.utils.ManagerFactory;
import lu.tudor.santec.gecamed.core.utils.SSNChecker;
import lu.tudor.santec.gecamed.formeditor.gui.model.ComboBoxElement;
import lu.tudor.santec.gecamed.patient.ejb.entity.beans.Patient;
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.PatientManagerModule;
import lu.tudor.santec.gecamed.patient.gui.simpleview.OverviewPanel;
import lu.tudor.santec.gecamed.patient.utils.SettingConstants;
import lu.tudor.santec.i18n.Translatrix;

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;
import com.toedter.calendar.JTextFieldDateEditor;

/**
 * Panel to display and edit the patients general data, such as 
 * name, gender, language etc...
 * 
 *
 * @author Johannes Hermen johannes.hermen(at)tudor.lu
 *
 * @version
 * <br>$Log: PatientGeneralDataPanel.java,v $
 * <br>Revision 1.72  2014-02-07 14:12:53  ferring
 * <br>show age in months if the patient is younger than 4 years
 * <br>
 * <br>Revision 1.71  2013-05-15 12:56:26  ferring
 * <br>old search string won't be stored in DB any longer. This caused wrong results in the patient search.
 * <br>
 * <br>Revision 1.70  2013-03-26 10:25:49  ferring
 * <br>Option added in admin settings, to format the patient names
 * <br>
 * <br>Revision 1.69  2012-05-07 12:52:02  ferring
 * <br>SSN entering changed
 * <br>
 * <br>Revision 1.68  2010-10-19 14:37:13  troth
 * <br>rename class SimpleViewPanel in OverviewPanel
 * <br>
 * <br>Revision 1.67  2010-09-30 07:27:50  hermen
 * <br>not allow to save patients with only spaces in name
 * <br>
 * <br>Revision 1.66  2010-08-18 13:58:21  troth
 * <br>Add a small patient create dialog to Agenda-, Waitingroom- module | Incomplete - # 608: Agenda/Waitingroom
 * <br>http://santec.tudor.lu/trac/gecamed/ticket/608
 * <br>
 * <br>Revision 1.65  2010-06-07 12:04:43  hermen
 * <br>fixed yellow flickering
 * <br>
 * <br>Revision 1.64  2010-03-23 15:44:44  hermen
 * <br>fixed bug 455, Change of patient title does not activate the save button
 * <br>
 * <br>Revision 1.63  2009-10-06 09:48:21  hermen
 * <br>fixed setting geb. date from matricule
 * <br>
 * <br>Revision 1.62  2009-07-02 12:36:48  hermen
 * <br>enabled lastname field in all cases
 * <br>
 * <br>Revision 1.61  2009-05-29 13:51:21  hermen
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.60  2009-04-03 14:15:09  heinemann
 * <br>fix for Ticket #300: Patient file is not set to "modified" when just the age is entered for a new patient file
 * <br>
 * <br>Revision 1.59  2009-04-03 14:09:57  heinemann
 * <br>fix for ticket #299 Saving new patient not possible when no day of birth is set
 * <br>
 * <br>Revision 1.58  2009-04-03 14:02:16  heinemann
 * <br>fix for ticket #289
 * <br>nullpointer when age contains characters
 * <br>uses now the extract age method from DateUtil
 * <br>
 * <br>Revision 1.57  2009-03-10 09:51:42  hermen
 * <br>small bugfixes
 * <br>
 * <br>Revision 1.56  2009-01-22 07:35:51  hermen
 * <br>improved startup logging and progress dialog
 * <br>
 * <br>Revision 1.55  2009-01-14 14:30:24  hermen
 * <br>fixed age calculation bug id 254
 * <br>
 * <br>Revision 1.54  2009-01-06 14:48:08  hermen
 * <br>small bugfixes
 * <br>
 * <br>Revision 1.53  2008-10-24 12:21:06  hermen
 * <br>Bug #236
 * <br>SSec Field does not commit the value if it does not loose the focus before saving the patient
 * <br>
 * <br>Revision 1.52  2008-10-16 14:53:07  heinemann
 * <br>http://santec.tudor.lu/trac/gecamed/ticket/220
 * <br>a new patient is alway "modified" even if nothing has changed
 * <br>
 * <br>focus handling problem
 * <br>
 * <br>Revision 1.7  2008-09-25 09:43:06  heinemann
 * <br>fixed copyrights
 * <br>
 * <br>Revision 1.6  2008-06-17 10:06:12  hermen
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.5  2008-06-17 09:05:24  hermen
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.4  2008-06-12 08:43:42  hermen
 * <br>changed some setting defaults
 * <br>
 * <br>Revision 1.3  2008-06-05 10:14:18  hermen
 * <br>set Focus to panel if it gets visible
 * <br>
 * <br>Revision 1.2  2008-04-16 14:24:28  heinemann
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.1  2008-04-15 16:01:03  heinemann
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.48  2008-03-17 16:21:23  mack
 * <br>Changes required by moving SSNFormatter into core.utils package
 * <br>
 * <br>Revision 1.47  2008-03-14 08:13:23  hermen
 * <br>enhanced focus traversal
 * <br>
 * <br>Revision 1.46  2008-01-21 14:03:27  hermen
 * <br>updated Javadoc and refactured code
 * <br>
 *
 */
public class PatientGeneralDataPanel extends JPanel implements KeyListener, ItemListener, IPatientDataPanel
{
    //~ Static fields/initializers =============================================


    private static final long serialVersionUID = 1L;
    
    /** the logger Object for this class */
	private static Logger logger = Logger.getLogger(PatientGeneralDataPanel.class.getName());

    //~ Instance fields ========================================================

    private SSNField ssnField;
    private JButton calcSSN13;
    private JComboBox gender;
    private JDateChooser doB;
    private JTextField firstName;
    private JTextField lastName;
    private JTextField maidenName;
    private PatientAdminPanel patientEditPanel;
//    private String[] genderArray;
//	private JComboBox title;
//	private String[] titleArray;
//	private ListManagerInterface manager;
    private JComboBox<ComboBoxElement<Title>> title;
	private boolean listenersActivated = false;
	private JTextField birthLocality;
	private JTextField ageField;
	private Patient patient;
	private JPanel topPanel;
	private CellConstraints cc;
	
	private int textCarretPosition=0;
	private int textLenght=0;
	/**
	 * Flag to get information, if a key was pressed in a field.
	 * Important for the focus listener on the ssn field. It will fire a modification
	 * even when nothing was changed.
	 */
	private boolean firstKeyPressed = false;

    //~ Constructors ===========================================================
    /**
     * builds a new PatientInfo to show/edit general Patient Data
     */
    public PatientGeneralDataPanel(PatientAdminPanel patientEditPanel)
    {	
    	this.setOpaque(false);
        this.patientEditPanel = patientEditPanel;
        this.buildPanel();
    }

    //~ Methods ================================================================

    /* (non-Javadoc)
     * @see lu.tudor.santec.gecamed.patient.gui.administrative.IPatientDataPanel#getPatient(lu.tudor.santec.gecamed.patient.ejb.entity.beans.Patient)
     */
    public void getPatient(Patient patient)
    {
	
	// stop editing of field
	try {
	    ssnField.commitEdit();
	} catch (ParseException e) {
	    e.printStackTrace();
	}
	
	
	
        // row 1
//    	patient.setTitle(getSelectedTitle());
    	
		try {
			Object item = title.getSelectedItem();
			if (item instanceof ComboBoxElement) {
				patient.setTitle(((ComboBoxElement<Title>)item).getValue().getValue());							
			} else {
				patient.setTitle(title.getSelectedItem()+"");
			}
		} catch (Exception e) {
			patient.setTitle(title.getSelectedItem()+"");
		}
        
        patient.setFirstName(this.firstName.getText());
        patient.setSurName(this.lastName.getText());
        patient.setMaidenName(this.maidenName.getText());

        // row 2
        patient.setSocialSecurityNumber((String) this.ssnField.getValue());
        /* ------------------------------------------------------- */
        if (this.doB.getDate() != null)
        	patient.setBirthDate(DateUtil.move2Morning(this.doB.getDate()));
        else
        	patient.setBirthDate(null);
        /* ------------------------------------------------------- */
        patient.setBirthLocality(this.birthLocality.getText());

        // row 3
        patient.setGender(gender.getSelectedIndex() < 0 ? null 
        		: ((ComboBoxElement<Gender>)gender.getSelectedItem()).getValue().getValue());
    }

    /**
     * Returns a list of the components that should be used in the focus cycle
     * 
     * @return
     */
    public List<Component> getComponentsForFocus() {
    	/* ================================================== */
    	ArrayList<Component> focusList = new ArrayList<Component>();
    	/* ------------------------------------------------------- */
    	focusList.add(ssnField);
    	focusList.add(lastName);
    	focusList.add(firstName);
    	focusList.add(maidenName);
    	/* ------------------------------------------------------- */
    	
    	return focusList;
		/* ================================================== */
    }
    
    
    /* (non-Javadoc)
     * @see lu.tudor.santec.gecamed.patient.gui.administrative.IPatientDataPanel#setPatient(lu.tudor.santec.gecamed.patient.ejb.entity.beans.Patient, boolean)
     */
    public void setPatient(Patient patient, boolean editable) {
	    /* ================================================== */
    	this.patient = patient;

    	this.setEditable(editable);

    	listenersActivated = false;
    	
    	this.firstKeyPressed = false;
    	
    	/* ------------------------------------------------------- */
        // row 1
    	/* ------------------------------------------------------- */
    	
//    	this.title.setEditable(true);
//    	AutoCompletion.enableWithFreeText(this.title);
    	
    	/*if (patient.getTitle() != null) {
    		this.title.setSelectedIndex(GECAMedGuiUtils.getIndexByDefaultTranslation(title, patient.getTitle()));
    	} else {
    		try {
    			this.title.setSelectedIndex(0);
			} catch (Exception e) {
			}
    	}*/
    	
    	int idx = GECAMedGuiUtils.getIndexByDefaultTranslation(title, patient.getTitle());
		if (idx >= 0) {
			this.title.setSelectedIndex(idx);
		} else if (patient.getTitle() != null) {
			this.title.setSelectedItem(patient.getTitle());
		} else {
			this.title.setSelectedItem("");
		}
		
        this.firstName.setText(patient.getFirstName());
        this.lastName.setText(patient.getSurName());
        this.maidenName.setText(patient.getMaidenName());
        /* ------------------------------------------------------- */
        // row 2
        /* ------------------------------------------------------- */
        String ssn = patient.getSocialSecurityNumber();
        if (ssn == null) ssn = "00000000000";
        this.ssnField.setValue(ssn);
        
        try {
            this.doB.setDate(patient.getBirthDate());
        } catch (Exception e) {
            this.doB.setDate(DateUtil.move2Morning(new Date()));
        }

        this.birthLocality.setText(patient.getBirthLocality());
        /* ------------------------------------------------------- */
        if (patient.getGender() != null)
        	this.gender.setSelectedIndex(GECAMedGuiUtils.getIndexByDefaultTranslation(gender, patient.getGender()));
        else
        	this.gender.setSelectedIndex(GECAMedGuiUtils.getIndexByDefaultTranslation(gender, Gender.UNKNOWN));
        listenersActivated = true;
        
        if (this.isShowing() && !patient.isPersistent()) {
            this.getFocus();
        }
        
        /* ================================================== */
    }

    /**
     * enables,disables the panel
     * @param editable
     */
    private void setEditable(boolean editable) {
    	/* ================================================== */
    	this.title.setEnabled(editable);
    	this.lastName.setEditable(editable);
    	this.firstName.setEditable(editable);
    	this.maidenName.setEditable(editable);
    	this.ssnField.setEditable(editable);
    	this.doB.setEnabled(editable);
    	this.birthLocality.setEditable(editable);
    	this.gender.setEnabled(editable);
    	/* ================================================== */
	}

	/**
     * adds the components to the panel
     */
    private void buildPanel() {
    	/* ================================================== */
        initComponents();
        this.setLayout(new FormLayout("3dlu,fill:pref,3dlu" , "3dlu,fill:pref,3dlu,bottom:5dlu"));
        // ===============================================================
        // set the header infos, text and icon
        //
        // ===============================================================
//        this.setHeader(Translatrix.getTranslationString("pm.generalInfo")+":");
//        this.setHeaderIcon(PatientManagerModule.getMediumIcon(PatientManagerModule.PATIENT_ADMINSTRATIVE));
        // ================================================================
        
        this.cc = new CellConstraints();
        
        buildTopPanel();
        
        this.add(topPanel,         cc.xy(2, 2));
        this.add(new JSeparator(), cc.xy(2, 4));
        /* ================================================== */
    }
    
    
    
    /**
     * Build the top panel
     */
    private void buildTopPanel() {
    	/* ================================================== */
    	this.topPanel = new JPanel(new FormLayout(
    			// cols
    			"3dlu," +
    			"right:60dlu," +
    			"5dlu," +
    			
    			"fill:80dlu," +
    			"2dlu," + 
    			"fill:pref," + 
    			"3dlu," + // gap to birthdate label
    			"fill:pref," +
    			
    			"3dlu," + // gap to birthdate field
    			"fill:55dlu," +
    			
    			"5dlu:grow," +
    			"right:pref," +
    			"5dlu," +
    			
    			"fill:20dlu," +
    			"fill:45dlu," +
    			"fill:20dlu," +
    			
    			"0dlu",
    			// rows
    			"3dlu," +
    			"fill:pref," +
    			"3dlu," +
    			"fill:pref," +
    			"3dlu," +
    			"fill:pref," +
    			"3dlu," +
    			"fill:pref" 
    			));
    	topPanel.setOpaque(false);
    	// =====================================================
    	// create the labels
    	JLabel scnLabel 	  = OverviewPanel.createLabel("pm.socialNumber");
    	
    	JLabel nameLabel1;
    	JLabel nameLabel2;
    	// ===========================================================
        // Settings -> use maiden name as first name if selected
        // ==========================================================
    	if (PatientManagerModule.isMaidenConfig()) {
    		/* ------------------------------------------------------- */
    		nameLabel1  = OverviewPanel.createLabel("pm.maidenName");
    		nameLabel2  = OverviewPanel.createLabel("pm.familyName");
    		/* ------------------------------------------------------- */
    	} else {
    		/* ------------------------------------------------------- */
    		nameLabel1  = OverviewPanel.createLabel("pm.lastName");
    		nameLabel2  = OverviewPanel.createLabel("pm.maidenName");
    		/* ------------------------------------------------------- */
    	}
    	JLabel firstNameLabel 		= OverviewPanel.createLabel("pm.firstName");
    	JLabel birthdateLabel 		= OverviewPanel.createLabel("pm.dayOfBirth");
    	JLabel ageLabel       		= OverviewPanel.createLabel("pm.age");
    	
    	JLabel genderLabel    		= OverviewPanel.createLabel("pm.gender");
    	JLabel birthLocalityLabel 	= OverviewPanel.createLabel("pm.birthLocality");
    	JLabel titleLabel     		= OverviewPanel.createLabel("pm.titel");
    	
    	// ===================================================
    	// place the labels and the fields
    	// in the form
    	// ===================================================
    	// first column --> labels
    	topPanel.add(scnLabel,       cc.xy(2, 2));
    	topPanel.add(nameLabel1,     cc.xy(2, 4));
    	topPanel.add(firstNameLabel, cc.xy(2, 6));
    	topPanel.add(nameLabel2,     cc.xy(2, 8));
    	// birthdate
    	topPanel.add(birthdateLabel, cc.xy(8, 2));
    	// right column
    	topPanel.add(ageLabel,           cc.xy(12, 2));
    	topPanel.add(genderLabel,        cc.xy(12, 4));
    	topPanel.add(birthLocalityLabel, cc.xy(12, 6));
    	topPanel.add(titleLabel,         cc.xy(12, 8));
    	
    	/* ------------------------------------------------------- */
    	// place the fields
    	// first column
    	topPanel.add(this.ssnField,   cc.xy (4, 2));
    	topPanel.add(this.calcSSN13,  cc.xy (6, 2));
    	topPanel.add(this.lastName,   cc.xyw(4, 4, 7));
    	topPanel.add(this.firstName,  cc.xyw(4, 6, 7));
    	topPanel.add(this.maidenName, cc.xyw(4, 8, 7));
    	// birthdate
    	topPanel.add(this.doB,        cc.xy (10, 2));
    	
    	// right column
    	topPanel.add(this.ageField,      cc.xy (14, 2));
    	topPanel.add(this.gender,        cc.xyw(14, 4, 2));
    	topPanel.add(this.birthLocality, cc.xyw(14, 6, 3));
    	topPanel.add(this.title,         cc.xyw(14, 8, 2));
    	/* ------------------------------------------------------- */
    	// manage the focus cycle
    	/* ------------------------------------------------------- */
    	
    	
		/* ================================================== */
    }
    
    /**
     * initializes the Components
     */
    private void initComponents()
    {
    	
    	// create and fill the title box
//    	title = new JComboBox();
//    	title.addItem(new ComboBoxElement<Title>(Title.EMPTY, new Title[1]));
//    	for (ComboBoxElement<Title> t : GECAMedGuiUtils.getTranslatedList(Title.class))
//    		title.addItem(t);
//        AutoCompletion.enable(this.title);
//        try {
//        	this.title.setSelectedIndex(1);
//		} catch (Exception e) {
//		}
//		this.title.addItemListener(this);
		
        this.title = new JComboBox<ComboBoxElement<Title>>(GECAMedGuiUtils.getTranslatedList(Title.class));
        try {
        	this.title.setSelectedIndex(0);
		} catch (Exception e) {}
        this.title.addItemListener(this);
        this.title.setSelectedItem(Language.LUXEMBOURGISH);
        AutoCompletion.enableWithFreeText(this.title);
		
		
		
        this.firstName = new JTextField();
        this.firstName.addKeyListener(this);
        this.firstName.setDocument(PatientNameDocument.getFirstNameDocument(40));
        this.firstName.addFocusListener(new FocusAdapter() {
        	@Override
        	public void focusLost(FocusEvent e) {
        		try {
        			((PatientNameDocument)firstName.getDocument()).change();					
				} catch (Exception e2) {
				}
        		super.focusLost(e);
        	}
        });
        
        this.lastName = new LimitTextField(40, true);
        this.lastName.addKeyListener(this);
        this.lastName.setDocument(PatientNameDocument.getLastNameDocument(40));
        this.lastName.addFocusListener(new FocusAdapter() {
        	@Override
        	public void focusLost(FocusEvent e) {
        		try {
        			((PatientNameDocument)lastName.getDocument()).change();					
				} catch (Exception e2) {
				}
        		super.focusLost(e);
        	}
        });
       
        this.maidenName = new JTextField();
        this.maidenName.addKeyListener(this);
        this.maidenName.setDocument(PatientNameDocument.getLastNameDocument(40));
        this.maidenName.addFocusListener(new FocusAdapter() {
        	@Override
        	public void focusLost(FocusEvent e) {
        		try {
        			((PatientNameDocument)maidenName.getDocument()).change();					
				} catch (Exception e2) {
				}
        		super.focusLost(e);
        	}
        });
        
//        this.sSecNumber = new SSNField(new SSNFormatter());
        this.ssnField = new SSNField();
        this.ssnField.addKeyListener(this);    
        this.ssnField.requestFocusInWindow();
        /* ------------------------------------------------------- */
        // FocusListener for the SSNField
        // when the field loses the focus, the matricule
        // will be checked for duplicates
        ssnField.addFocusListener(new FocusAdapter() {

			/* (non-Javadoc)
			 * @see java.awt.event.FocusAdapter#focusLost(java.awt.event.FocusEvent)
			 */
			@Override
			public void focusLost (FocusEvent e)
			{
				if (!firstKeyPressed)
					return;
				
				String	ssn	= ssnField.getText().replaceAll("\\s+", "");
				
				if (SSNChecker.PATTERN_EMPTY_SSN.matcher(ssn).matches())
					return;
				
				try
				{
					if (!patient.isPersistent())
					{
						List<Patient>	duplicates	= checkSSN(ssn);
						
						if (duplicates != null)
						{
							DuplicateSSNDialog ssnD = DuplicateSSNDialog.getInstace();
							ssnD.showDialog(duplicates);
							if (ssnD.getSelectedPatient() != null)
								PatientManagerModule.getInstance().addPatient(ssnD.getSelectedPatient(), true);
						}
					}
				}
				catch (Exception ee)
				{
					logger.error("Error while trying to detect a duplicate SSN. This can be safely ignored.", ee);
				}
				
				setDOB(ssn);
				setGender(ssn);
				setTitle();
			}
        });
        
        this.calcSSN13 = new JButton(new AbstractAction("SSN13")
		{
			private static final long	serialVersionUID	= 1L;
			
			public void actionPerformed (ActionEvent e)
			{
				String ssn = ssnField.getText();
				ssn = SSNChecker.get13DigitsSSN(ssn, true);
				if (ssn != null && !ssn.equals(ssnField.getText()))
				{
					patientEditPanel.setModified(true);
					ssnField.setValue(ssn);
				}
			}
		});
        this.calcSSN13.setToolTipText(Translatrix.getTranslationString("pm.calculateSSN13"));
        this.calcSSN13.setMargin(new java.awt.Insets(0, 3, 0, 3));
//        this.calcSSN13.setPreferredSize(new Dimension(64, 24));
//        ModuleHeader.addEffect(calcSSN13);
        /* ------------------------------------------------------- */
        this.ageField = new JTextField();
        this.ageField.setFocusable(false);
        this.ageField.setEditable(false);
        /* ------------------------------------------------------- */
        this.ageField.setBackground(Color.WHITE);
        this.ageField.setHorizontalAlignment(JLabel.RIGHT);
        /* ------------------------------------------------------- */
        this.doB = GECAMedGuiUtils.getDateChooser(false);
        this.doB.setFocusable(false);
        try {
        	((JTextFieldDateEditor)this.doB.getDateEditor()).setFocusable(false);
	} catch (Exception e) {}
		/* ------------------------------------------------------- */
        this.doB.addKeyListener(this);
        this.doB.addPropertyChangeListener(new PropertyChangeListener() {
			public void propertyChange(PropertyChangeEvent evt) {
				try {
					/* ------------------------------------------------------- */
					ageField.setText(calcAge(doB.getDate()));
					if (listenersActivated && "date".equals(evt.getPropertyName()))
						PatientGeneralDataPanel.this.patientEditPanel.setModified(true);
					/* ------------------------------------------------------- */
				} catch (Exception e) {
					ageField.setText("");
				}
			}
        });
        /* ------------------------------------------------------- */
        this.birthLocality = new JTextField(40);
        this.birthLocality.addKeyListener(this);
        /* ------------------------------------------------------- */
        this.gender = new JComboBox(GECAMedGuiUtils.getTranslatedList(Gender.class));
        try {
        	this.gender.setSelectedIndex(0);
		} catch (Exception e) {}
        this.gender.addItemListener(this);
//        this.gender.addItemListener(new ItemListener() {
//			public void itemStateChanged(ItemEvent e) {
//				if (Gender.MALE.equals(gender.getSelectedItemTranslated()))
//					maidenName.setEditable(false);
//				else
//					maidenName.setEditable(true);
//			}
//        });
        AutoCompletion.enable(this.gender);
        /* ================================================== */
    }

	
	protected String calcAge (Date date)
	{
		StringBuilder	ageBuilder	= new StringBuilder();
		int				age			= DateUtil.extractAge(date);
		Calendar		dob;
		Calendar		now;
		
		
		if (age >= 4)
			return ageBuilder.append(age)
					.toString();
		
		// show age of a patient younger than 4 years in month
		dob	= new GregorianCalendar();
		now	= new GregorianCalendar();
		
		dob.setTime(date);
		age = getAge(dob, now, Calendar.MONTH);
		if (age >= 2)
			return ageBuilder.append(age)
					.append(" ")
					.append(Translatrix.getTranslationString("pm.monthShort"))
					.toString();
		
		// show age of a patient younger than 2 month in weeks
		dob.setTime(date);
		age = getAge(dob, now, Calendar.WEEK_OF_YEAR);
		return ageBuilder.append(age)
				.append(" ")
				.append(Translatrix.getTranslationString("pm.weekShort"))
				.toString();
	}
	
	
	private static int getAge (Calendar birthdate, Calendar today, int unit)
	{
		int age = -1;
		while (birthdate.before(today))
		{
			birthdate.add(unit, 1);
			age++;
		}
		
		if (age < 0)
			return 0;
		else
			return age;
	}
	
	
	/* (non-Javadoc)
	 * @see java.awt.event.KeyListener#keyTyped(java.awt.event.KeyEvent)
	 */
	public void keyTyped(KeyEvent e) {
		
//		if(PatientNameDocument.getLastNameDocument(40).getMode()==SettingConstants.PATIENT_NAME_UPPER_CASE 
//				||  PatientNameDocument.getLastNameDocument(40).getMode()==SettingConstants.PATIENT_NAME_UPPER_CASE )
//		{
//			if(e.getSource().equals(this.firstName))
//			{
//				textCarretPosition=this.firstName.getCaretPosition();
//				textLenght=this.firstName.getText().length();
//			}
//			else if(e.getSource().equals(this.lastName))
//			{
//				textCarretPosition=this.lastName.getCaretPosition();
//				textLenght=this.lastName.getText().length();
//			}
//			else if(e.getSource().equals(this.maidenName))
//			{
//				textCarretPosition=this.maidenName.getCaretPosition();
//				textLenght=this.maidenName.getText().length();
//			}
//		}
		if (listenersActivated ) {
			this.patientEditPanel.setModified(true);
			this.firstKeyPressed = true;
		}
	}
	public void keyPressed(KeyEvent e) {
	}
	public void keyReleased(KeyEvent e) {
//		if(PatientNameDocument.getLastNameDocument(40).getMode()==SettingConstants.PATIENT_NAME_UPPER_CASE 
//				||  PatientNameDocument.getLastNameDocument(40).getMode()==SettingConstants.PATIENT_NAME_UPPER_CASE )
//		{
//			if(e.getSource().equals(this.firstName))
//			{
//				
//				if(this.firstName.getText().length()>textLenght)
//				{
//					this.firstName.setCaretPosition(textCarretPosition+1);
//				}
//				else
//				{
//					this.firstName.setCaretPosition(textCarretPosition);
//				}
//			}
//			else if(e.getSource().equals(this.lastName))
//			{
//				if(this.lastName.getText().length()>textLenght)
//				{
//					this.lastName.setCaretPosition(textCarretPosition+1);
//				}
//				else
//				{
//					this.lastName.setCaretPosition(textCarretPosition);
//				}
//			}
//			else if(e.getSource().equals(this.maidenName))
//			{
//				if(this.maidenName.getText().length()>textLenght)
//				{
//					this.maidenName.setCaretPosition(textCarretPosition+1);
//				}
//				else
//				{
//					this.maidenName.setCaretPosition(textCarretPosition);
//				}
//			}
//		}
	}

	private String oldGenderValue;
	
	/* (non-Javadoc)
	 * @see java.awt.event.ItemListener#itemStateChanged(java.awt.event.ItemEvent)
	 */
	public void itemStateChanged (ItemEvent e)
	{
		if (listenersActivated)
		{
			if (gender.equals(e.getSource()))
			{
				String genderValue = ((ComboBoxElement<Gender>)e.getItem()).getValue().getValue();
				
				if (e.getStateChange() == ItemEvent.DESELECTED)
					oldGenderValue = genderValue;
				else if (!genderValue.equals(oldGenderValue))
					setTitle();
			}
			
			if (!this.ssnField.equals(e.getSource()))
				this.patientEditPanel.setModified(true);
		}
	}

	/**
	 * checks if the panel is filled up right
	 * @return
	 */
	public boolean isFilledOK() {
		boolean ok = true;
		if (lastName.getText().trim().equals("")) {
			ok = false;
		}
		return ok;
	}


	/**
	 * Runs a check at the server if the given ssn is already used
	 * by another patient.<br/>
	 * Returns a list of patients that claims the same ssn
	 * @param ssn
	 * @return
	 */
	private List<Patient> checkSSN(String ssn) {
		/* ================================================== */
		PatientAdminInterface pManager =
			(PatientAdminInterface) ManagerFactory.getRemote(PatientAdminBean.class);
		List<Patient> duplicates = pManager.checkDuplicateSSN(ssn);
		return duplicates;
		/* ================================================== */
	}

	/**
	 * checks if both dates are on the same day in the same year
	 * @param d1
	 * @param d2
	 * @return
	 */
	@SuppressWarnings("unused")
	private boolean isSameDate(Date d1, Date d2) {
		Calendar c1 = new GregorianCalendar();
		c1.setTime(d1);
		Calendar c2 = new GregorianCalendar();
		c2.setTime(d2);
		if (c1.get(Calendar.YEAR) != c2.get(Calendar.YEAR))
			return false;
		if (c1.get(Calendar.DAY_OF_YEAR) != c2.get(Calendar.DAY_OF_YEAR))
			return false;
		return true;
	}

	/**
	 * set the DOB by the matricule if it has not been set
	 * @param ssn
	 */
	private void setDOB (String ssn)
	{
		try
		{
			if (ssn == null || SSNChecker.PATTERN_EMPTY_SSN.matcher(ssn).matches() )
				return;
			
			if (!ssn.matches("\\d{8,}"))
				return;
			
			Date date = SSNChecker.getValidDate(ssn, true);
			
			logger.info("ssn " + ssn + " contains date: " + date );
			
			if (date != null)
			{
				Calendar cal = new GregorianCalendar();
				int currYear = cal.get(Calendar.YEAR);
				cal.setTime(date);
				int dateYear = cal.get(Calendar.YEAR);
				
				if (dateYear > 1850 && dateYear < currYear + 2) {
					doB.setDate(date);					
				} else {
					logger.warn("SSN " + ssn + " does not start with a valid Year, skipping birthday calculation.");
					doB.setDate(null);					
				}
			} else {
				logger.warn("SSN " + ssn + " does not start with a valid date, skipping birthday calculation.");
				doB.setDate(null);
			}
		}
		catch (Exception e)
		{
			logger.warn("Error while calculating Birthdate from SSN", e);
			doB.setDate(null);
		}
	}
	
	/**
	 * sets the title corresponding to the Gender
	 */
	private void setTitle()
	{
		if (gender.getSelectedIndex() < 0)
			return;
		
		String titleStr = null;
		try
		{
			String genderValue = ((ComboBoxElement<Gender>)gender.getSelectedItem()).getValue().getValue();
			
			if (genderValue.equals(Gender.MALE))
			{
				titleStr = Title.MISTER;
			}
			else if (genderValue.equals(Gender.FEMALE))
			{
				Calendar	cal	= new GregorianCalendar();
				if (doB != null && doB.getDate() != null) {
					cal.setTime(doB.getDate());					
					cal.add(Calendar.YEAR, 21);
				}
				
				if (cal.after(new GregorianCalendar()))
				{
					titleStr = Title.MISS;
				}
				else
				{
					titleStr = Title.MADAM;
				}
			}
			
			if (titleStr != null) {
				int idx = GECAMedGuiUtils.getIndexByDefaultTranslation(title, titleStr);
				if (idx >= 0) {
					this.title.setSelectedIndex(idx);
				} 				
			}
		} catch (Throwable e) {
			logger.error("Error while setting title for patient according to gender.", e);
		}
	}

	/**
	 * sets the gender corresponding to the ssn
	 */
	private void setGender (String ssn) {
		try {
			
//			if (gender.getSelectedIndex() >= 0 
//					&& !((ComboBoxElement<Gender>)gender.getSelectedItem()).getValue().getValue().equals(Gender.UNKNOWN))
//				return;
//			String ssn = ssnField.getText().replaceAll("\\s", "");
			
			if (!ssn.matches("\\d{10,}"))
				return;
			
			int genderDigit = Integer.parseInt(ssn.substring(9,10));
			if ((genderDigit % 2) == 0) {
				gender.setSelectedIndex(GECAMedGuiUtils.getIndexByDefaultTranslation(gender, Gender.FEMALE));
			} else {
				gender.setSelectedIndex(GECAMedGuiUtils.getIndexByDefaultTranslation(gender, Gender.MALE));
			}
		} catch (Exception e) {
			logger.error("Error while setting the patient's gender.", e);
		}
	}

	public void getFocus() {
	    this.ssnField.requestFocus();
	}
	
	
//	private String getSelectedTitle ()
//	{
//		 return title.getSelectedIndex() < 0 ? title.getSelectedItem()+"" : ((ComboBoxElement<Title>)title.getSelectedItem()).getValue().getValue();
//	      
//		/*
//		if (title == null
//				|| title.getSelectedIndex() == 0)
//			return null;
//		
//		ComboBoxElement<Title> t = (ComboBoxElement<Title>) title.getSelectedItem();
//		
//		  
//		if (t == null)
//			return null;
//		else if (t.getValue() == null)
//			return Title.EMPTY;
//		else
//			return t.getValue().getValue();*/
//	}
}
