/*******************************************************************************
 * 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
 *******************************************************************************/
/**
 * @author Martin Heinemann martin.heinemann@tudor.lu
 * 
 * 
 * 
 * @version
 * <br>
 *          $Log: AgendaCalendarModifyDialog.java,v $
 *          Revision 1.22  2014-02-13 16:55:58  ferring
 *          NewCalendar bug fixed (ticket #1294)
 *
 *          Revision 1.21  2014-02-12 12:12:20  ferring
 *          null pointer exception avoided
 *
 *          Revision 1.20  2013-08-05 08:40:50  ferring
 *          AgendaCalendarModifyDialog fixed:
 *          <ul>
 *           <li>Additional OK and cancel buttons removed</li>
 *           <li>Initialization of color chooser and fields corrected</li>
 *           <li>Cancel button isn't the same as OK button anymore</li>
 *           <li>All changes will now have (immediate) effect</li>
 *          </ul>
 * <br>
 *          Revision 1.19 2013-07-15 06:18:35 ferring <br>
 *          logging changed <br>
 * <br>
 *          Revision 1.18 2013-02-19 12:07:34 ferring <br>
 *          GECAMedLists changed. Will now automatically load list of all beans <br>
 * <br>
 *          Revision 1.17 2012-03-20 14:16:11 troth <br>
 *          Fix two small bugs: <br>
 *          1. Create and delete a calendar causes a null-pointer-exception
 *          because the property-change-listener calls the action performed
 *          method of the gCalendarBox. <br>
 *          2. If closing the CreateCalendarDialog over the window close button
 *          creates a calendar. <br>
 * <br>
 *          Revision 1.16 2009-04-03 13:22:05 heinemann <br>
 *          fix for: Ticket #266 (new enhancement) <br>
 * <br>
 *          If Color of a physician is changed, it will not change the color of
 *          his Calendar <br>
 * <br>
 *          Revision 1.15 2008-09-25 09:42:27 heinemann <br>
 *          fixed copyrights <br>
 * <br>
 *          Revision 1.14 2008-09-08 15:12:32 heinemann <br>
 *          *** empty log message *** <br>
 * <br>
 *          Revision 1.13 2008-09-05 16:52:37 heinemann <br>
 *          fixed possible nullpointer if there are no default appointment types
 *          in the database <br>
 * <br>
 *          Revision 1.12 2008-07-04 13:38:58 heinemann <br>
 *          fixed generic casting that the new eclipse does not want to accept. <br>
 * <br>
 *          Revision 1.11 2008-05-28 16:15:11 heinemann <br>
 *          *** empty log message *** <br>
 * <br>
 *          Revision 1.10 2008-03-28 08:51:34 heinemann <br>
 *          *** empty log message *** <br>
 * <br>
 *          Revision 1.9 2008-01-18 16:09:05 heinemann <br>
 *          code cleanup and java doc <br>
 * <br>
 *          Revision 1.8 2007-11-21 15:17:23 heinemann <br>
 *          checkin without warranty!! <br>
 * <br>
 *          Revision 1.8 2007/08/29 11:05:07 heinemann <br>
 *          *** empty log message *** <br>
 * <br>
 *          Revision 1.7 2007/08/29 07:54:24 heinemann <br>
 *          *** empty log message *** <br>
 * <br>
 *          Revision 1.6 2007/08/28 11:29:58 hermen <br>
 *          do not delete appointment types, set them deprecated <br>
 * <br>
 *          Revision 1.5 2007/08/28 09:16:14 hermen <br>
 *          appointment types per calendar <br>
 * <br>
 *          Revision 1.4 2007/08/27 12:32:52 hermen <br>
 *          appointment types per calendar <br>
 * <br>
 *          Revision 1.3 2007/06/21 09:01:07 hermen <br>
 *          *** empty log message *** <br>
 * <br>
 *          Revision 1.2 2007/06/15 13:10:10 heinemann <br>
 *          *** empty log message *** <br>
 * <br>
 *          Revision 1.1 2007/05/25 13:50:25 heinemann <br>
 *          pres-weekend checkin <br>
 * 
 */
package lu.tudor.santec.gecamed.agenda.gui.widgets;

import java.awt.Color;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.datatransfer.DataFlavor;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetDragEvent;
import java.awt.dnd.DropTargetDropEvent;
import java.awt.dnd.DropTargetEvent;
import java.awt.dnd.DropTargetListener;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Collection;
import java.util.List;
import java.util.Vector;

import javax.jms.JMSException;
import javax.swing.ComboBoxModel;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JColorChooser;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.border.TitledBorder;

import lu.tudor.santec.bizcal.NamedCalendar;
import lu.tudor.santec.gecamed.agenda.ejb.entity.beans.AgendaCalendar;
import lu.tudor.santec.gecamed.agenda.ejb.entity.beans.AppointmentType;
import lu.tudor.santec.gecamed.agenda.ejb.session.beans.AppointmentManagerBean;
import lu.tudor.santec.gecamed.agenda.ejb.session.beans.DoctenaSyncBean;
import lu.tudor.santec.gecamed.agenda.ejb.session.interfaces.AppointmentManager;
import lu.tudor.santec.gecamed.agenda.ejb.session.interfaces.DoctenaSyncInterface;
import lu.tudor.santec.gecamed.agenda.gui.widgets.appointmenttype.AppointmentTypeComboBoxRenderer;
import lu.tudor.santec.gecamed.agenda.gui.widgets.appointmenttype.AppointmentTypeTableCellDurationEditor;
import lu.tudor.santec.gecamed.agenda.gui.widgets.appointmenttype.AppointmentTypeTableCellIconEditor;
import lu.tudor.santec.gecamed.agenda.gui.widgets.appointmenttype.AppointmentTypeTableCellRenderer;
import lu.tudor.santec.gecamed.agenda.gui.widgets.appointmenttype.AppointmentTypeTransferHandler;
import lu.tudor.santec.gecamed.agenda.gui.widgets.appointmenttype.AppointmentTypesTableModel;
import lu.tudor.santec.gecamed.core.gui.GECAMedColors;
import lu.tudor.santec.gecamed.core.gui.GECAMedIconNames;
import lu.tudor.santec.gecamed.core.gui.GECAMedLists;
import lu.tudor.santec.gecamed.core.gui.GECAMedModule;
import lu.tudor.santec.gecamed.core.gui.MainFrame;
import lu.tudor.santec.gecamed.core.gui.widgets.GECAMedBaseDialog;
import lu.tudor.santec.gecamed.core.gui.widgets.GECAMedBaseDialogImpl;
import lu.tudor.santec.gecamed.core.gui.widgets.NamedComponent;
import lu.tudor.santec.gecamed.core.utils.ManagerFactory;
import lu.tudor.santec.gecamed.office.ejb.entity.beans.Physician;
import lu.tudor.santec.gecamed.usermanagement.ejb.entity.beans.GecamedUser;
import lu.tudor.santec.i18n.Translatrix;

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

import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;
import com.jgoodies.validation.Severity;
import com.jgoodies.validation.ValidationResult;
import com.jgoodies.validation.ValidationResultModel;
import com.jgoodies.validation.message.SimpleValidationMessage;
import com.jgoodies.validation.util.DefaultValidationResultModel;
import com.jgoodies.validation.util.ValidationUtils;
import com.jgoodies.validation.view.ValidationResultViewFactory;

/**
 * Dialog to modify AgendaCalendar objects.
 * 
 * 
 * @author martin.heinemann@tudor.lu
 * 23.05.2007
 * 15:59:58
 *
 *
 * @version
 * <br>$Log: AgendaCalendarModifyDialog.java,v $
 * <br>Revision 1.22  2014-02-13 16:55:58  ferring
 * <br>NewCalendar bug fixed (ticket #1294)
 * <br>
 * <br>Revision 1.21  2014-02-12 12:12:20  ferring
 * <br>null pointer exception avoided
 * <br>
 * <br>Revision 1.20  2013-08-05 08:40:50  ferring
 * <br>AgendaCalendarModifyDialog fixed:
 * <br><ul>
 * <br> <li>Additional OK and cancel buttons removed</li>
 * <br> <li>Initialization of color chooser and fields corrected</li>
 * <br> <li>Cancel button isn't the same as OK button anymore</li>
 * <br> <li>All changes will now have (immediate) effect</li>
 * <br></ul>
 * <br>
 * <br>Revision 1.19  2013-07-15 06:18:35  ferring
 * <br>logging changed
 * <br>
 * <br>Revision 1.18  2013-02-19 12:07:34  ferring
 * <br>GECAMedLists changed. Will now automatically load list of all beans
 * <br>
 * <br>Revision 1.17  2012-03-20 14:16:11  troth
 * <br>Fix two small bugs:
 * <br>1. Create and delete a calendar causes a null-pointer-exception because the  property-change-listener calls the action performed method of the gCalendarBox.
 * <br>2. If closing the CreateCalendarDialog over the window close button creates a calendar.
 * <br>
 * <br>Revision 1.16  2009-04-03 13:22:05  heinemann
 * <br>fix for: Ticket #266 (new enhancement)
 * <br>
 * <br>If Color of a physician is changed, it will not change the color of his Calendar
 * <br>
 * <br>Revision 1.15  2008-09-25 09:42:27  heinemann
 * <br>fixed copyrights
 * <br>
 * <br>Revision 1.14  2008-09-08 15:12:32  heinemann
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.13  2008-09-05 16:52:37  heinemann
 * <br>fixed possible nullpointer if there are no default appointment types in the database
 * <br>
 * <br>Revision 1.12  2008-07-04 13:38:58  heinemann
 * <br>fixed generic casting that the new eclipse does not want to accept.
 * <br>
 * <br>Revision 1.11  2008-05-28 16:15:11  heinemann
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.10  2008-03-28 08:51:34  heinemann
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.9  2008-01-18 16:09:05  heinemann
 * <br>code cleanup and java doc
 * <br>
 * <br>Revision 1.8  2007-11-21 15:17:23  heinemann
 * <br>checkin without warranty!!
 * <br>
 * <br>Revision 1.6  2007/08/28 11:29:58  hermen
 * <br>do not delete appointment types, set them deprecated
 * <br>
 * <br>Revision 1.5  2007/08/28 09:16:14  hermen
 * <br>appointment types per calendar
 * <br>
 * <br>Revision 1.4  2007/08/27 12:32:52  hermen
 * <br>appointment types per calendar
 * <br>
 * <br>Revision 1.1  2007/05/25 13:50:25  heinemann
 * <br>pres-weekend checkin
 * <br>
 *
 */
public class AgendaCalendarModifyDialog extends GECAMedBaseDialogImpl implements ActionListener, DropTargetListener
{
	/* ======================================== */
	// CONSTANTS
	/* ======================================== */
	
	private static final long	serialVersionUID	= 1L;
	
	/**
	 * static logger for this class
	 */
	private static Logger		logger				= Logger.getLogger(AgendaCalendarModifyDialog.class.getName());
	
	
	
	/* ======================================== */
	// MEMBERS
	/* ======================================== */
	
	private static AgendaCalendarModifyDialog	instance	= new AgendaCalendarModifyDialog();
	
	
	private JTextField					nameTextField;
	
	private JComboBox<Physician>		physicianComboBox;
	
	private JLabel						colorDisplay;
	
	private JButton						colorButton;
	
	private JComboBox<GecamedUser>		userComboBox;
	
	private JCheckBox					userPrivate;
	
	private JTable						calendarAppointmentTypeTable;
	
	private AppointmentManager			apManager;
	
	private AppointmentTypesTableModel	calendarTypesModel;
	
	private JButton						addTypeButton;
	
	private JButton						newTypeButton;
	
	private JButton						deleteTypeButton;
	
	private JList<AppointmentType>		globalList;
	
	private ValidationResultModel		validationResultModel;
	
	private boolean						occured;
	
	private boolean						updatingDialog	= false;

	private JTextField doctenaUsername;

	private JPasswordField doctenaPassword;

	private JButton doctenaTest;

	private JLabel doctenaStatus;

	private AgendaCalendar agenda;
	
	
	
	/* ======================================== */
	// CONSTRUCTORS
	/* ======================================== */
	
	/**
	 * Private constructor
	 */
	private AgendaCalendarModifyDialog ()
	{
		super(MainFrame.getInstance(), Translatrix.getTranslationString(
				"calendar.management.editCalendar"), OK_CANCEL_BUTTON_MODE);
		initComponent();
		initComboBoxes();
		initActions();
	}
	
	
	/**
	 * Get instance
	 *
	 * @return
	 */
	public static AgendaCalendarModifyDialog getInstance ()
	{
		return instance;
	}
	
	
	
	/* ======================================== */
	// GETTER & SETTER
	/* ======================================== */
	
	/**
	 * Returns the calendar
	 *
	 * @return
	 */
	public Collection<AppointmentType> getTypes ()
	{
		return this.calendarTypesModel.getElements();
	}
	
	
	
	/* ======================================== */
	// CLASS BODY
	/* ======================================== */
	
	/**
	 *
	 */
	public AgendaCalendar showDialog ()
	{
		AgendaCalendar newCalendar = new AgendaCalendar();
		if (showDialog(newCalendar) != GECAMedBaseDialog.OK_OPTION)
			return null;
		else
			return newCalendar;
	}
	
	
	/**
	 * @param calendar
	 */
	public int showDialog (AgendaCalendar calendar)
	{
		// load the data from the calendar into the view
		refresh(calendar);
		
		this.pack();
		MainFrame.showDialogCentered(instance);
		
		return buttonOption;
	}
	
	
	public AgendaCalendar updateCalendar (AgendaCalendar aCal, NamedCalendar nCal)
	{
		// get the data from the view to the currentCalendar
		aCal.setTitle(nameTextField.getText());
		aCal.setColor(colorDisplay.getBackground().getRGB());
		
		aCal.setDoctenaLogin(doctenaUsername.getText());
		aCal.setDoctenaPasswordClearText(new String(doctenaPassword.getPassword()));
		
		// physician
		if (physicianComboBox.getSelectedItem() instanceof Physician)
			aCal.setPhysicianId(((Physician) physicianComboBox.getSelectedItem()).getId());
		else
			aCal.setPhysicianId(null);
		
		// user
		if (userComboBox.getSelectedItem() instanceof GecamedUser)
			aCal.setUserId(((GecamedUser) userComboBox.getSelectedItem()).getId());
		else
			aCal.setUserId(null);
		
		if (nCal != null) {
			nCal.setName(aCal.getTitle());
			nCal.setColor(new Color(aCal.getColor()));
			if (nCal.getCheckBox() != null)
				nCal.getCheckBox().setText(aCal.getTitle());			
		}

		// save Types
		aCal	= saveCalendar(aCal);
		saveAppointmentTypes(getTypes(), aCal);
		
		GECAMedLists.resetListAndNotifyListener(AppointmentType.class);
		
		return aCal;
	}
	
	
	/* ---------------------------------------- */
	// BUTTON ACTIONS
	/* ---------------------------------------- */
	
	@Override
	public void okActionCalled ()
	{
		ValidationResult result = doValidate();
		if ((result != null && result.size() > 0) && occured == false)
		{
			occured = true;
			validationResultModel.setResult(result);
			pack();
			return;
		}
		occured = false;
		
		super.okActionCalled();
	}
	
	
	@Override
	public void cancelActionCalled ()
	{
		super.cancelActionCalled();
	}
	
	
	@Override
	public void closeActionCalled ()
	{
		cancelActionCalled();
	}
	
	
	/* ---------------------------------------- */
	// DROP TARGET METHODS
	/* ---------------------------------------- */
	
	public void drop (DropTargetDropEvent event)
	{
		try
		{
			Object[] types = (Object[]) event.getTransferable().getTransferData(DataFlavor.stringFlavor);
			for (int i = 0; i < types.length; i++)
			{
				AppointmentType at = (AppointmentType) types[i];
				AppointmentType atNew = new AppointmentType();
				atNew.setAppointmentTypeClass(at.getAppointmentTypeClass());
				atNew.setDuration(at.getDuration());
				atNew.setIcon(at.getIcon());
				atNew.setName(at.getName());
				atNew.setColor(at.getColor());
				calendarTypesModel.addElement(atNew);
			}
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
		event.dropComplete(true);
	}
	
	public void dragEnter (DropTargetDragEvent dtde) {}
	public void dragExit (DropTargetEvent dte) {}
	public void dragOver (DropTargetDragEvent dtde) {}
	public void dropActionChanged (DropTargetDragEvent dtde) {}
	
	
	
	/* ======================================== */
	// HELP METHODS
	/* ======================================== */
	
	/**
	 * Init components
	 */
	private void initComponent ()
	{
		// define the main panel layout
		mainPanel.setLayout(new FormLayout(
				// cols
				"3dlu," +
				"fill:40dlu," +
				"3dlu," +
				"fill:pref," +
				"5dlu:grow," +
				"3dlu," +
				"5dlu:grow," +
				"88dlu," +
				"3dlu",
				// rows
				"3dlu," +
				"fill:pref," +
				"2dlu," +
				"fill:pref," +
				"5dlu," +
				"fill:pref," +
				"2dlu," +
				"fill:pref," +
				"3dlu," +
				"fill:pref," +
				"20dlu," +
				"fill:pref," +
				"5dlu," +
				"fill:pref," +
				"5dlu," +
				"25dlu"));
		CellConstraints cc = new CellConstraints();
		mainPanel.setOpaque(false);
		
		// calendar name
		JLabel nameLabel = new JLabel(Translatrix.getTranslationString("calendar.management.name") + ":");
		this.nameTextField = new JTextField();
		
		// physician select
		JLabel physicianLabel = new JLabel(Translatrix.getTranslationString("calendar.management.physician") + ":");
		this.physicianComboBox = new JComboBox<Physician>();
		
		// Color chooser
		JLabel colorLabel = new JLabel(Translatrix.getTranslationString("calendar.management.color") + ":");
		this.colorDisplay = new JLabel();
		this.colorDisplay.setOpaque(true);
		this.colorButton = new JButton(Translatrix.getTranslationString("calendar.management.colorChange") + ":");
		
		// User chooser
		JLabel userLabel = new JLabel(Translatrix.getTranslationString("calendar.management.user") + ":");
		this.userComboBox = new JComboBox<GecamedUser>();
		this.userPrivate = new JCheckBox(Translatrix.getTranslationString("calendar.management.userPrivate"));
		this.userPrivate.setOpaque(false);
		
		// assemble the panel
		this.mainPanel.add(nameLabel,			cc.xy(2, 2));
		this.mainPanel.add(nameTextField,		cc.xyw(2, 4, 3));
		this.mainPanel.add(physicianLabel,		cc.xy(8, 2));
		this.mainPanel.add(physicianComboBox,	cc.xy(8, 4));
		this.mainPanel.add(colorLabel,			cc.xy(2, 6));
		this.mainPanel.add(colorDisplay,		cc.xywh(2, 8, 1, 3));
		this.mainPanel.add(colorButton,			cc.xywh(4, 8, 1, 3));
		this.mainPanel.add(userLabel,			cc.xy(8, 6));
		this.mainPanel.add(userComboBox,		cc.xy(8, 8));
//		this.mainPanel.add(userPrivate, 		cc.xy  (8, 10));
		
		JSeparator sep = new JSeparator(SwingConstants.VERTICAL);
		mainPanel.add(sep, cc.xywh(6, 2, 1, 9));
		
		// AppointmentType Panel
		mainPanel.add(createAppointmentTypePanel(), cc.xyw(2, 12, 7));
		
		// Doctena Panel 
		mainPanel.add(createDoctenaPanel(), cc.xyw(2, 14, 7));
		
		// create the validation things
		this.validationResultModel = new DefaultValidationResultModel();
		JComponent reportList = ValidationResultViewFactory
				.createReportList(validationResultModel);
		mainPanel.add(reportList, cc.xyw(2, 16, 7));
	}
	
	
	private Component createDoctenaPanel() {
		CellConstraints cc = new CellConstraints();
		JPanel panel = new JPanel(new FormLayout(
				"2dlu, pref:grow, 2dlu, pref:grow, 2dlu, pref, 2dlu",
				"2dlu, fill:pref, 2dlu, pref, 2dlu"));
		panel.setOpaque(false);
		
		panel.setBorder(new TitledBorder(Translatrix.getTranslationString("calendar.doctena")));
		
		doctenaUsername = new JTextField();
		panel.add(new NamedComponent(Translatrix.getTranslationString("calendar.doctena.user"), doctenaUsername), cc.xy(2,2));
		
		doctenaPassword = new JPasswordField();
		panel.add(new NamedComponent(Translatrix.getTranslationString("calendar.doctena.password"), doctenaPassword), cc.xy(4,2));
		
		doctenaTest = new JButton(Translatrix.getTranslationString("calendar.doctena.test"));
		panel.add(doctenaTest, cc.xy(6,2));
		doctenaTest.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				new Thread() {
					public void run() {
						testDoctena();
					}
				}.start();
			}
		});
		
		doctenaStatus = new JLabel();
		panel.add(doctenaStatus, cc.xyw(2,4, 6));
		
		return panel;
	}

	
	private void testDoctena() {
		new Thread() {
			public void run() {
				doctenaStatus.setText("Sync Running....");
				setWaitCursor(true);
				AgendaCalendarModifyDialog.this.doctenaTest.setEnabled(false);
				String log = null;
				String title = Translatrix.getTranslationString("calendar.doctena.syncdone");
				
				boolean ok = true;
				try {
					DoctenaSyncInterface doctenaManager = (DoctenaSyncInterface) ManagerFactory.getStatefulRemote(DoctenaSyncBean.class);
					
					agenda = updateCalendar(agenda, null);
			
					doctenaManager.intSyncBean(agenda);
					
					if (doctenaManager.connectFTP()) {
						ok = doctenaManager.syncDoctena(true, true);
						
						log = doctenaManager.getLog();

						agenda = doctenaManager.getAgenda();
						doctenaStatus.setText(Translatrix.getTranslationString("calendar.doctena.lastsync") + agenda.getDoctenaLastSync());

						try {
							AppointmentManager apManager = (AppointmentManager) ManagerFactory.getRemote(AppointmentManagerBean.class);
							apManager.sendCalendarUpdateMessage("doctenaImport", AppointmentManager.MSG_UPDATE_CALENDAR_EVENTS, agenda.getId(), null);
						} catch (JMSException e) {
							logger.warn("Error updating calendar after Doctena Sync", e);
						}
					} else {
						ok = false;
						title = Translatrix.getTranslationString("calendar.doctena.syncfailed") + " connection failed";
					}
					
					logger.info(log);
					
				} catch (Throwable ex) {
					if (log == null) {
						log = ex.getMessage();
					}
					title = Translatrix.getTranslationString("calendar.doctena.syncfailed");
					doctenaStatus.setText(title);
					logger.error(title, ex);
				} finally {
					JOptionPane.showMessageDialog(AgendaCalendarModifyDialog.this,
							log, 
							title, 
							(ok?JOptionPane.INFORMATION_MESSAGE:JOptionPane.ERROR_MESSAGE));
					AgendaCalendarModifyDialog.this.doctenaTest.setEnabled(true);
					setWaitCursor(false);
				}
			}
		}.start();
	}

	/**
	 * Fills the comboboxes with physicians and users
	 */
	private void initComboBoxes ()
	{
		// physician combo box
		// clear
		physicianComboBox.removeAllItems();
		
		// fill
		physicianComboBox.addItem(new Physician("-"));
		List<Physician> physicians = GECAMedLists.getListReference(Physician.class);
		if (physicians != null)
		{
			for (Physician p : physicians)
			{
				physicianComboBox.addItem(p);
			}
		}
		
		physicianComboBox.addActionListener(this);

		// user combo box
		// clear
		userComboBox.removeAllItems();
		
		// fill
		userComboBox.addItem(new GecamedUser("-"));
		GecamedUser[] users = GECAMedLists.getArray(GecamedUser.class);
		if (users != null)
		{
			for (int i = 0; i < users.length; i++)
			{
				userComboBox.addItem(users[i]);
			}
		}
	}
	
	
	/**
	 * Init actions
	 */
	private void initActions ()
	{
		// color chooser
		this.colorButton.addActionListener(new ActionListener()
		{
			public void actionPerformed (ActionEvent e)
			{
				chooseColor();
			}
		});
		
		// =============================================
		// Listener, updates the physician combobox
		// when physicians are changed
		// =============================================
		GECAMedLists.addPropertyChangeListener(new PropertyChangeListener()
		{
			public void propertyChange (PropertyChangeEvent evt)
			{
				physicianComboBox.removeAllItems();
				physicianComboBox.addItem(new Physician("-"));
				for (Physician p : (Physician[]) evt.getNewValue())
				{
					physicianComboBox.addItem(p);
				}
			}
		}, Physician.class);
		
		// Listener, updates the user combobox when users are changed
		GECAMedLists.addPropertyChangeListener(new PropertyChangeListener()
		{
			public void propertyChange (PropertyChangeEvent evt)
			{
				userComboBox.removeAllItems();
				userComboBox.addItem(new GecamedUser("-"));
				for (GecamedUser gu : (GecamedUser[]) evt.getNewValue())
				{
					userComboBox.addItem(gu);
				}
			}
		}, GecamedUser.class);
		
		
		// Listener for the global appointment types
		GECAMedLists.addPropertyChangeListener(new PropertyChangeListener()
		{
			public void propertyChange (PropertyChangeEvent evt)
			{
				refreshGlobalTypes();
			}
		}, AppointmentType.class);
	}
	
	
	/**
	 * Updates the view with the data from currentCalendar
	 */
	private void refresh (AgendaCalendar calendar)
	{
		@SuppressWarnings("rawtypes")
		ComboBoxModel	model;
		Integer			id;
		Physician		p;
		GecamedUser		u;
		
		
		updatingDialog = true;
		
		// initialise the calendar, if it's a new one
		if (calendar == null)
		{
			calendar = new AgendaCalendar();
		}
		
		this.agenda = calendar;
		
		// set the calendar name
		if (calendar.getTitle() != null)
		{
			this.nameTextField.setText(calendar.getTitle());
		}
		else
		{
			this.nameTextField.setText("");
		}
		
		try {
			this.doctenaUsername.setText(calendar.getDoctenaLogin());	
		} catch (Exception e) {
			this.doctenaUsername.setText("");
			logger.warn("Error setting doctena username", e);
		}
		
		try {
			this.doctenaPassword.setText(calendar.getDoctenaPasswordClearText());
		} catch (Exception e) {
			this.doctenaPassword.setText("");
			logger.warn("Error decoding password", e);
		}
		
		if (calendar.getDoctenaLastSync() != null) {
			this.doctenaStatus.setText(Translatrix.getTranslationString("calendar.doctena.lastsync") + calendar.getDoctenaLastSync());
		}
		
		// set the calendar color
		if (calendar.getColor() != null)
			this.colorDisplay.setBackground(new Color(calendar.getColor()));
		
		// select the physician
		id		= calendar.getPhysicianId();
		model	= physicianComboBox.getModel();
		
		physicianComboBox.setSelectedIndex(0);
		if (id != null)
		{
			for (int index = 0; index < model.getSize(); index++)
			{
				p = (Physician) model.getElementAt(index);
				if (p != null && p.getId() != null 
						&& p.getId().equals(id))
				{
					physicianComboBox.setSelectedIndex(index);
					break;
				}
			}
		}
		
		// select the user
		id		= calendar.getUserId();
		model	= userComboBox.getModel();
		
		userComboBox.setSelectedIndex(0);
		if (id != null)
		{
			for (int index = 0; index < model.getSize(); index++)
			{
				u = (GecamedUser) model.getElementAt(index);
				if (u != null && u.getId() != null
						&& u.getId().equals(id))
				{
					userComboBox.setSelectedIndex(index);
					break;
				}
			}
		}
		
		// select the appointment types
		Collection<AppointmentType> calendarTypes = null;
		if (calendar.isPersistent())
		{
			calendarTypes = apManager.getAppointmentTypesByID(AppointmentType.GENERAL, calendar.getId(), false);
		}
		this.calendarTypesModel.setTypes(calendarTypes);
//		if (calendarTypesModel.getRowCount() == 0) {
//			this.okButton.setEnabled(false);
//		}
		
		this.validationResultModel.setResult(ValidationResult.EMPTY);
		
		updatingDialog = false;
	}
	
	
	/**
	 * @return
	 */
	private ValidationResult doValidate ()
	{
		ValidationResult validationResult = new ValidationResult();
		if (calendarTypesModel.getRowCount() < 1)
		{
			validationResult.add(new SimpleValidationMessage(
					Translatrix.getTranslationString("Agenda.validation.missing_type"), Severity.ERROR));
		}
		if (ValidationUtils.isEmpty(nameTextField.getText()))
		{
			validationResult.add(new SimpleValidationMessage(
					Translatrix.getTranslationString("Agenda.validation.missing_name"), Severity.ERROR));
		}
		
		return validationResult;
	}
	
	
	private JPanel createAppointmentTypePanel ()
	{
		// AppointmentType Panel
		CellConstraints cc = new CellConstraints();
		JPanel appointmentTypePanel = new JPanel(new FormLayout(
				"100dlu, 2dlu, 20dlu, 2dlu, 140dlu",
				"2dlu, fill:200dlu, 2dlu"));
		appointmentTypePanel.setOpaque(false);
		
		ActionListener al = new ActionListener()
		{
			public void actionPerformed (ActionEvent e)
			{
				shiftType(e);
			}
		};
		
		try
		{
			apManager = (AppointmentManager) ManagerFactory
					.getRemote(AppointmentManagerBean.class);
		}
		catch (Exception e)
		{
			logger.log(Level.WARN, "error getting APPOINTMENTMANAGER", e);
		}
		
		AppointmentTypeTableCellRenderer renderer = new AppointmentTypeTableCellRenderer();
		AppointmentTypeTableCellIconEditor ie = new AppointmentTypeTableCellIconEditor();
		AppointmentTypeTableCellDurationEditor de = new AppointmentTypeTableCellDurationEditor();
		
		
		globalList = new JList<AppointmentType>();
		globalList.setCellRenderer(new AppointmentTypeComboBoxRenderer());
		globalList.setDragEnabled(true);
		globalList.setTransferHandler(new AppointmentTypeTransferHandler());
		/* ------------------------------------------------------- */
		// init the global types
		refreshGlobalTypes();
		/* ------------------------------------------------------- */
		
		JScrollPane jsp1 = new JScrollPane(globalList);
		jsp1.setBorder(new TitledBorder(Translatrix.getTranslationString("calendar.management.global")));
		jsp1.setOpaque(false);
		jsp1.getViewport().setOpaque(false);
		appointmentTypePanel.add(jsp1, cc.xy(1, 2));
		
		JPanel buttonPanel = new JPanel(new FormLayout("pref", "pref:grow, pref, 20dlu, pref, 20dlu, pref, pref:grow"));
		addTypeButton = new JButton(GECAMedModule.getMediumIcon(GECAMedIconNames.RIGHT));
		addTypeButton.setToolTipText(Translatrix.getTranslationString("core.add"));
		addTypeButton.setMargin(new java.awt.Insets(0, 2, 0, 2));
		addTypeButton.addActionListener(al);
		
		newTypeButton = new JButton(GECAMedModule.getMediumIcon(GECAMedIconNames.ADD));
		newTypeButton.setToolTipText(Translatrix.getTranslationString("core.new"));
		newTypeButton.setMargin(new java.awt.Insets(0, 2, 0, 2));
		newTypeButton.addActionListener(al);
		
		deleteTypeButton = new JButton(GECAMedModule.getMediumIcon(GECAMedIconNames.REMOVE));
		deleteTypeButton.setToolTipText(Translatrix.getTranslationString("core.delete"));
		deleteTypeButton.setMargin(new java.awt.Insets(0, 2, 0, 2));
		deleteTypeButton.addActionListener(al);
		
		buttonPanel.setOpaque(false);
		buttonPanel.add(addTypeButton, cc.xy(1, 2));
		buttonPanel.add(newTypeButton, cc.xy(1, 4));
		buttonPanel.add(deleteTypeButton, cc.xy(1, 6));
		appointmentTypePanel.add(buttonPanel, cc.xy(3, 2));
		
		calendarTypesModel = new AppointmentTypesTableModel(null, false);
		calendarAppointmentTypeTable = new JTable(calendarTypesModel);
		calendarAppointmentTypeTable.getColumnModel().getColumn(0).setCellRenderer(renderer);
		calendarAppointmentTypeTable.getColumnModel().getColumn(1).setMaxWidth(50);
		calendarAppointmentTypeTable.getColumnModel().getColumn(1).setCellRenderer(renderer);
		calendarAppointmentTypeTable.getColumnModel().getColumn(1).setCellEditor(de);
		calendarAppointmentTypeTable.getColumnModel().getColumn(2).setMaxWidth(50);
		calendarAppointmentTypeTable.getColumnModel().getColumn(2).setCellRenderer(renderer);
		calendarAppointmentTypeTable.getColumnModel().getColumn(2).setCellEditor(ie);
		calendarAppointmentTypeTable.getTableHeader().setReorderingAllowed(false);
		calendarAppointmentTypeTable.setDragEnabled(true);
		calendarAppointmentTypeTable.setDropTarget(new DropTarget(calendarAppointmentTypeTable, this));
		
		JScrollPane jsp2 = new JScrollPane(calendarAppointmentTypeTable);
		jsp2.setBorder(new TitledBorder(Translatrix.getTranslationString("calendar")));
		jsp2.setOpaque(false);
//		jsp2.getViewport().setOpaque(false);
		jsp2.getViewport().setBackground(GECAMedColors.c_GECAMedBackground);
		jsp2.setDropTarget(new DropTarget(jsp2, this));
		
		appointmentTypePanel.add(jsp2, cc.xy(5, 2));
		return appointmentTypePanel;
	}
	
	
	private void refreshGlobalTypes ()
	{
		// get appointment types from GECAMedLists
		Vector<AppointmentType> newApps = new Vector<AppointmentType>();
		if (GECAMedLists.getListReference(AppointmentType.class) != null)
		{
			for (AppointmentType at : GECAMedLists.getListReference(AppointmentType.class))
			{
				if (at.getCalendarId() == null
						&& at.getAppointmentTypeClass().equals(AppointmentType.GENERAL))
					newApps.add(at);
			}
		}
		globalList.setListData(newApps);
	}
	
	
	public void actionPerformed (ActionEvent e)
	{
		if (physicianComboBox.equals(e.getSource()))
		{
			// change the color of the calendar to the color of the physician
			Physician phy = (Physician) physicianComboBox.getSelectedItem();
			if (phy != null && phy.getColor() != null)
			{
				// set color of calendar
				setColor(new Color(phy.getColor()));
			}
		}
	}
	
	
	private void setColor (Color c)
	{
		if (c != null && !updatingDialog)
		{
			colorDisplay.setBackground(c);
			
			// don't do that or the color will be set without confirming with OK
//			currentCalendar.setColor(c.getRGB());
		}
	}
	
	
	private void chooseColor ()
	{
		Color color = JColorChooser.showDialog(
				this, 
				Translatrix.getTranslationString("calendar.management.color"), 
				colorDisplay.getBackground());
		setColor(color);
	}
	
	
	private void shiftType (ActionEvent e)
	{
		if (e.getSource().equals(addTypeButton))
		{
			try
			{
				Object[] atArr = globalList.getSelectedValues();
				for (int i = 0; i < atArr.length; i++)
				{
					AppointmentType at = (AppointmentType) atArr[i];
					AppointmentType atNew = new AppointmentType();
					atNew.setAppointmentTypeClass(at.getAppointmentTypeClass());
					atNew.setDuration(at.getDuration());
					atNew.setIcon(at.getIcon());
					atNew.setName(at.getName());
					atNew.setColor(at.getColor());
					calendarTypesModel.addElement(atNew);
				}
			}
			catch (Exception ee)
			{
				ee.printStackTrace();
			}
		}
		else if (e.getSource().equals(newTypeButton))
		{
			AppointmentType atNew = new AppointmentType();
			atNew.setAppointmentTypeClass(AppointmentType.GENERAL);
			calendarTypesModel.addElement(atNew);
			
		}
		else if (e.getSource().equals(deleteTypeButton))
		{
			int[] rows = calendarAppointmentTypeTable.getSelectedRows();
			for (int i = 0; i < rows.length; i++)
			{
				try
				{
					AppointmentType at = calendarTypesModel.getElement(rows[i]);
					calendarTypesModel.deleteElement(at);
					if (at != null && at.isPersistent())
					{
						at.setDeprecated(true);
						apManager.saveAppointmentType(MainFrame.getClientId(), at);
					}
				}
				catch (Exception ee)
				{
					ee.printStackTrace();
				}
			}
		}
	}
	
	
	/**
	 * @param calendar
	 */
	private AgendaCalendar saveCalendar (AgendaCalendar calendar) {
		/* ================================================== */
//		 Integer msgType = null;
		 /* ------------------------------------------------------- */
//		 if (calendar.getId() == null)
//		 msgType = AppointmentManager.MSG_ADDED_CALENDAR;
//		 else
//		 msgType = AppointmentManager.MSG_UPDATE_CALENDAR;
		// /* ------------------------------------------------------- */
		try {
			AppointmentManager apManager = (AppointmentManager) ManagerFactory
					.getRemote(AppointmentManagerBean.class);
			/* ------------------------------------------------------- */
			AgendaCalendar agSaved = apManager.saveCalendar(MainFrame
					.getClientId(), calendar);

//			informCalendarChanges(agSaved, msgType);
			return agSaved;
			/* ------------------------------------------------------- */
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}
	
	
	private void saveAppointmentTypes(Collection<AppointmentType> types, AgendaCalendar cal)
	{
		if (!cal.isPersistent())
		{
			logger.error("Couldn't store appointment types for calendar, because the calendar is not persistent");
			return;
		}
		
		AppointmentManager apManager = (AppointmentManager) ManagerFactory.getRemote(AppointmentManagerBean.class);
		for (AppointmentType at : types) 
		{
			at.setCalendarId(cal.getId());
			apManager.saveAppointmentType(MainFrame.getClientId(), at);
		}
	}
	
	/**
	 * sets the Mousecursor of the MainFrame to a WaitCursor and Back
	 *
	 * @param on true=waitcursor false=normalcursor
	 */
	public void setWaitCursor(boolean on) {
		if (on) {
			this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
		} else {
			this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
		}
	}
}
