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

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.ObjectMessage;
import javax.swing.AbstractAction;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JPopupMenu;
import javax.swing.JSeparator;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.filechooser.FileFilter;

import lu.tudor.santec.bizcal.CalendarIcons;
import lu.tudor.santec.bizcal.CalendarPanel;
import lu.tudor.santec.bizcal.EventModel;
import lu.tudor.santec.bizcal.NamedCalendar;
import lu.tudor.santec.bizcal.listeners.CalendarManagementListener;
import lu.tudor.santec.bizcal.listeners.DateListener;
import lu.tudor.santec.bizcal.listeners.IZoomSliderListener;
import lu.tudor.santec.bizcal.listeners.NamedCalendarListener;
import lu.tudor.santec.bizcal.util.ObservableEventList;
import lu.tudor.santec.bizcal.views.DayViewPanel;
import lu.tudor.santec.bizcal.views.ListViewPanel;
import lu.tudor.santec.bizcal.views.MonthViewPanel;
import lu.tudor.santec.gecamed.agenda.ejb.entity.beans.AgendaCalendar;
import lu.tudor.santec.gecamed.agenda.ejb.entity.beans.Appointment;
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.interfaces.AppointmentManager;
import lu.tudor.santec.gecamed.agenda.gui.widgets.AgendaCalendarModifyDialog;
import lu.tudor.santec.gecamed.agenda.gui.widgets.AppointmentSearchDialog;
import lu.tudor.santec.gecamed.agenda.gui.widgets.FreeAppointmentFindDialog;
import lu.tudor.santec.gecamed.agenda.gui.widgets.FreeAppointmentFinder;
import lu.tudor.santec.gecamed.agenda.utils.IcalImportExporter;
import lu.tudor.santec.gecamed.core.ejb.entity.beans.NationalHoliday;
import lu.tudor.santec.gecamed.core.gui.GECAMedAction;
import lu.tudor.santec.gecamed.core.gui.GECAMedFonts;
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.GECAMedMessage;
import lu.tudor.santec.gecamed.core.gui.GECAMedMessageListener;
import lu.tudor.santec.gecamed.core.gui.GECAMedModule;
import lu.tudor.santec.gecamed.core.gui.GECAMedOptionPane;
import lu.tudor.santec.gecamed.core.gui.IconFetcher;
import lu.tudor.santec.gecamed.core.gui.MainFrame;
import lu.tudor.santec.gecamed.core.gui.PhysicianListener;
import lu.tudor.santec.gecamed.core.gui.RegistrationDesk;
import lu.tudor.santec.gecamed.core.gui.listener.MessageListenerRegister;
import lu.tudor.santec.gecamed.core.gui.utils.GECAMedGuiUtils;
import lu.tudor.santec.gecamed.core.gui.utils.GeneralGECAMedTextMessageReciever;
import lu.tudor.santec.gecamed.core.gui.widgets.GECAMedBaseDialog;
import lu.tudor.santec.gecamed.core.gui.widgets.PasswordChangeDialog;
import lu.tudor.santec.gecamed.core.gui.widgets.RequestFocusListener;
import lu.tudor.santec.gecamed.core.utils.JasperTemplateBean;
import lu.tudor.santec.gecamed.core.utils.ManagerFactory;
import lu.tudor.santec.gecamed.office.ejb.entity.beans.Physician;
import lu.tudor.santec.gecamed.office.ejb.session.beans.OfficeManagerBean;
import lu.tudor.santec.gecamed.office.ejb.session.interfaces.OfficeManagerInterface;
import lu.tudor.santec.gecamed.patient.ejb.entity.beans.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.PatientManagerIconNames;
import lu.tudor.santec.gecamed.usermanagement.ejb.entity.beans.GecamedUser;
import lu.tudor.santec.gecamed.usermanagement.ejb.session.beans.UserAdminBean;
import lu.tudor.santec.gecamed.usermanagement.ejb.session.interfaces.UserAdminInterface;
import lu.tudor.santec.gecamed.usermanagement.gui.AdminModule;
import lu.tudor.santec.gecamed.usermanagement.gui.settings.UserSettingsPlugin;
import lu.tudor.santec.i18n.Translatrix;
import lu.tudor.santec.settings.SettingEvent;
import lu.tudor.santec.settings.SettingListener;

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

import bizcal.common.DayViewConfig;
import bizcal.common.Event;
import bizcal.swing.CalendarListener;
import bizcal.swing.DayView;
import bizcal.swing.DayView.Layout;
import bizcal.swing.PopupMenuCallback;
import bizcal.swing.util.FrameArea;
import bizcal.util.DateInterval;
import bizcal.util.DateUtil;
import bizcal.util.Interval;
import bizcal.util.Tuple;

import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;

/**
 * The Agendamodule offers a calendar to manage appointments for different kind
 * of calendars. Each appointment belongs to a AgendaCalendar and has an
 * AppointmentType. Users can create as many calendars as they wish.. Each
 * AppointmentType belongs to a calendar, for exceptions see AppointmentType.
 * 
 * The GUI of the agenda is divided into two parts. On the left the main window
 * to display the appointments and on the right, a small menu bar containing
 * several buttons, the calendars and a JCalendar calendar widget. We use the
 * bizcal calendar library, available at sourceforge, for the day, week and
 * month views and the whole mouse interaction on events etc. As it is only a
 * framework we have written the backend for bizcal. Bizcal offers the graphical
 * presentation for events and skeletons for the interactions. We had to
 * implement several listeners to create, edit, delete events and calendars as
 * well as the datamodel that manages the events for the view. All clients work
 * on the same calendars. The users can switch unwanted calendars of. The
 * different clients are kept informed of new, deleted or moved events by a JMS
 * topic.
 * 
 * 
 * 
 * @author martin.heinemann@tudor.lu 17.01.2008 09:21:03
 * 
 * 
 * @version <br>
 *          $Log: AgendaModule.java,v $
 *          Revision 1.154  2014-02-21 08:45:10  ferring
 *          Search also for selected, not only for checked calendars
 *
 *          Revision 1.153  2014-02-19 10:03:42  ferring
 *          Time period for list view not taken at GECAMed Startup
 *
 *          Revision 1.152  2014-02-13 16:55:58  ferring
 *          NewCalendar bug fixed (ticket #1294)
 *
 *          Revision 1.151  2013-12-27 18:09:25  donak
 *          Cleanup of imports
 *
 *          Revision 1.150  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>
 *
 *          Revision 1.149  2013-07-15 06:18:36  ferring
 *          logging changed
 *
 *          Revision 1.148  2013-07-10 16:41:09  troth
 *          Fix ticket #1108.
 *
 *          Revision 1.147  2013-02-22 08:46:50  kutscheid
 *          remove the tupel classes (please redeploy)
 *
 *          Revision 1.146  2013-02-19 12:07:34  ferring
 *          GECAMedLists changed. Will now automatically load list of all beans
 *
 *          Revision 1.145  2013-02-06 15:25:02  troth
 *          Fix ticket 1146.
 *          Add the correct messages for add and update a calendar in function informCalendarChanges.
 *
 *          Revision 1.144  2013-01-22 14:21:29  ferring
 *          iReport templates will now be compiled only once until the server is stopped
 *
 *          Revision 1.143  2012-08-09 14:18:49  troth
 *          Ticket #1021 - Unpredictable NAF results and long search delai when no time slot left.
 *
 *          Revision 1.142  2012-07-27 15:41:33  troth
 *          *** empty log message ***
 *
 *          Revision 1.140  2012-07-23 15:41:24  troth
 *          Ticket #873 Point 6 and 7 fixed.
 *
 *          Revision 1.139  2012-07-19 15:10:07  troth
 *          Ticket #873 Point 5, 8, 9 and 10 fixed.
 *
 *          Revision 1.138  2012-07-17 14:36:01  troth
 *          Ticket #873 - Constraints are now static and the dialog is redesigned, add a today and 6 week button.
 *
 *          Revision 1.137  2012-07-16 13:24:06  troth
 *          Init the FreeAppointmentFinderDialog every time before it will be shown to set the time constraints right, because may be they have changed (Physicians office time).
 *
 *          Revision 1.136  2012-07-13 15:54:26  troth
 *          Label the time conditions with the start an end time. (Morning | 08:00 - 10:00)
 *
 *          Revision 1.135  2012-07-09 15:51:17  troth
 *          To mark the moving appointment when they positioned with the NewAppointmentFinder we have moved the flag Event.EVENT_PROPOSAL_STATE in the Event class.
 *
 *          Revision 1.134  2012-06-14 16:37:24  troth
 *          Fix Ticket #959 - Changing physician after copy-paste does strange things.
 *
 *          Revision 1.133  2012-06-12 15:43:51  troth
 *          Fix Ticket #957 - Display inconsistencies when changing the agenda of an entry.
 *
 *          Revision 1.132  2012-06-12 14:12:02  troth
 *          Add focus to password dialog which is when deleting a calendar with entries.
 *
 *          Revision 1.131  2012-06-11 16:12:10  troth
 *          fix Ticket #991 - Visuelle �berbleibsel von Kalender-Eintr�gen nach L�schen eines Kalenders.
 *
 *          Revision 1.130  2012-05-15 14:09:59  troth
 *          Implement Ticket #972.
 *
 *          Revision 1.129  2012-05-15 09:57:32  troth
 *          1. Add new agenda log-messages (admin panel) for calendar modifications.
 *
 *          Revision 1.128  2012-04-24 13:58:13  troth
 *          Better selection of the Calendar when click on a agenda entry | Fix Bug: Sometimes if a agenda entry has been selected the calendar of the entry was not selected. Now: The Calendar will be selected if a entry of the calendar is selected.
 *
 *          Revision 1.127  2012-04-24 08:55:02  troth
 *          1. Fix Ticket #972 - Bordered select Calendar.
 *          2. Better selection of the Calendar when click on a agenda entry (test version).
 *
 *          Revision 1.126  2012-01-24 13:18:41  troth
 *          1. Translations of agenda buttonstitle and tooltips.
 *
 *          Revision 1.125  2012-01-23 16:05:00  troth
 *          Add the old view layout of agenda, now the user can switch between the two layouts old (staircase display) and new (column display).
 *          Bug fix in both layouts of the views. Separate the (1)holiday-, (2)office-, (3)background- and (4)normal events in different layers for the order of drawing ((1) - (4) the order of drawing).
 *
 *          Revision 1.124  2012-01-18 16:31:25  troth
 *          Test: add the old view layout of agenda, now the user can switch between the two layouts old and new.
 *
 *          Revision 1.123  2011-11-30 08:21:01  ferring
 *          NullpointerException caught
 *
 *          Revision 1.122  2011-11-16 16:01:27  troth
 *          fix a warning
 *
 *          Revision 1.121  2011-10-24 14:16:17  troth
 *          Code Cleanup
 *
 *          Revision 1.120  2011-10-20 15:04:28  troth
 *          1. add new functions of ticket #879
 *          2. fix ticket #904
 *          3. new bizcal lib
 *
 *          Revision 1.119  2011-10-05 10:57:43  troth
 *          Ticket #894
 *          add: Log message string formatting
 *
 *          Revision 1.118  2011-10-04 12:13:32  troth
 *          fix Ticket #892 - Patient matricule and treatment type automatically added to agenda entry description
 *
 *          Revision 1.117  2011-09-28 11:28:18  troth
 *          Second Version of function 'logging Agenda modifications in the admin log' Ticket #894 Logging for Agenda modifications
 * <br>
 *          Revision 1.116 2011-09-22 15:28:52 troth <br>
 *          Fist Version of function 'logging Agenda modifications in the admin
 *          log' Ticket #894 Logging for Agenda modifications <br>
 * <br>
 *          Revision 1.115 2011-09-22 13:29:50 hermen <br>
 *          - changed transparencies in appointmentlist renderer <br>
 *          - fixed new column problem im appointmentfinder <br>
 * <br>
 *          Revision 1.114 2011-09-14 12:20:34 troth <br>
 *          Add the new function for printing a appointment overview for the
 *          physician. <br>
 * <br>
 *          Revision 1.113 2011-08-03 14:02:37 troth <br>
 *          code clearup <br>
 * <br>
 *          Revision 1.112 2011-08-02 15:57:47 troth <br>
 *          Fix ticket #871 <br>
 * <br>
 *          Revision 1.111 2011-07-20 13:49:51 troth <br>
 *          fixed Ticket #614 , #635 and new Bizcal lib. <br>
 * <br>
 *          Revision 1.110 2011-07-15 15:12:57 troth <br>
 *          fixed Ticket #416 and new Bizcal lib. <br>
 * <br>
 *          Revision 1.109 2011-06-16 11:58:22 troth <br>
 *          Remove some 'System.out.println' <br>
 * <br>
 *          Revision 1.108 2011-05-31 10:41:56 troth <br>
 *          fix Bug #850 and #861 <br>
 * <br>
 *          Revision 1.107 2011-05-18 13:06:24 troth <br>
 *          Fix ticket #837: Recurring calendar entry gets a date change after
 *          resizing <br>
 * <br>
 *          Revision 1.106 2011-04-05 08:47:46 troth <br>
 *          1. Add new icon for the button 'create new appointment' <br>
 *          2. Add some translations <br>
 *          3. Fix some warnings <br>
 * <br>
 *          Revision 1.105 2011-04-04 11:38:31 troth <br>
 *          Redesign of the appointment create dialog and the right navi bar. <br>
 * <br>
 *          Revision 1.104 2011-02-18 14:25:56 troth <br>
 *          - add some Javadoc <br>
 *          - bug fix - sometimes the DayView was not init when open the agenda <br>
 * <br>
 *          Revision 1.103 2011-02-16 10:47:41 troth <br>
 *          check in new bizcal jar and add the new bizcal view layout to the
 *          agenda <br>
 * <br>
 *          Revision 1.102 2011-02-10 15:09:25 troth <br>
 *          Add a new view to the calendar of the agenda the 'Three Day View'
 *          which shows three days per interval. <br>
 * <br>
 *          Revision 1.101 2011-02-09 13:41:30 troth <br>
 *          Some changes in GUI (right navigation bar / head navigation bar). <br>
 * <br>
 *          Revision 1.100 2010-10-08 05:57:43 ferring <br>
 *          NullpointerException at startup fixed <br>
 * <br>
 *          Revision 1.99 2010-04-27 14:36:37 troth <br>
 *          GECAMedOptionPane create now only a simple JOptionPane. May be later
 *          we build our own optionpane. <br>
 * <br>
 *          Revision 1.98 2010-03-19 12:01:06 hermen <br>
 *          improved and unified iconfetching <br>
 * <br>
 *          Revision 1.97 2010-03-17 16:24:17 hermen <br>
 *          fixed bug 444 and others concerning appointments not showing up in
 *          the views of the agenda <br>
 * <br>
 *          Revision 1.96 2009-12-15 11:06:24 hermen <br>
 *          fixed NPE on add Calendar <br>
 * <br>
 *          Revision 1.95 2009-12-01 16:22:34 mack <br>
 *          Changes required by the introduction of locale parameter in
 *          DefaultNamedCalendar <br>
 * <br>
 *          Revision 1.94 2009-07-02 13:09:14 hermen <br>
 *          *** empty log message *** <br>
 * <br>
 *          Revision 1.93 2009-05-15 13:21:17 heinemann <br>
 *          *** empty log message *** <br>
 * <br>
 *          Revision 1.92 2009-05-13 12:57:31 heinemann <br>
 *          *** empty log message *** <br>
 * <br>
 *          Revision 1.91 2009-05-12 11:51:43 heinemann <br>
 *          *** empty log message *** <br>
 * <br>
 *          Revision 1.90 2009-05-11 16:53:41 heinemann <br>
 *          slider position of the zoom in the agenda is stored in the user
 *          settings <br>
 * <br>
 *          Revision 1.89 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.88 2008-10-21 15:12:33 heinemann <br>
 *          *** empty log message *** <br>
 * <br>
 *          Revision 1.87 2008-10-20 11:42:47 heinemann <br>
 *          *** empty log message *** <br>
 * <br>
 *          Revision 1.86 2008-10-09 12:35:37 heinemann <br>
 *          http://santec.tudor.lu/trac/gecamed/ticket/193 <br>
 *          show patient name in the header of an appointment and the
 *          description in the body <br>
 * <br>
 *          Revision 1.85 2008-09-30 14:53:48 heinemann <br>
 *          *** empty log message *** <br>
 * <br>
 *          Revision 1.84 2008-09-25 09:42:27 heinemann <br>
 *          fixed copyrights <br>
 * <br>
 *          Revision 1.83 2008-09-10 15:22:28 heinemann <br>
 *          changed hotkeys to F1,F2 and F4 <br>
 * <br>
 *          Revision 1.82 2008-07-04 13:38:58 heinemann <br>
 *          fixed generic casting that the new eclipse does not want to accept. <br>
 * <br>
 *          Revision 1.81 2008-05-29 12:43:39 heinemann <br>
 *          fixed recurrence bug for appointments that recurr per week. <br>
 *          The days in the current week are now also treated. <br>
 * <br>
 *          Revision 1.80 2008-05-29 08:10:10 heinemann <br>
 *          *** empty log message *** <br>
 * <br>
 *          Revision 1.79 2008-05-27 14:13:41 heinemann <br>
 *          *** empty log message *** <br>
 * <br>
 *          Revision 1.78 2008-05-26 12:45:32 heinemann <br>
 *          Removed debugging <br>
 * <br>
 *          Revision 1.76 2008-04-14 13:11:36 heinemann <br>
 *          *** empty log message *** <br>
 * <br>
 *          Revision 1.75 2008-04-09 09:39:43 heinemann <br>
 *          *** empty log message *** <br>
 * <br>
 *          Revision 1.74 2008-04-08 09:52:33 heinemann <br>
 *          moved creation of new calendar from OfficeBean to AgendaModule <br>
 * <br>
 *          Revision 1.73 2008-03-28 08:51:34 heinemann <br>
 *          *** empty log message *** <br>
 * <br>
 *          Revision 1.72 2008-03-21 08:17:24 heinemann <br>
 *          *** empty log message *** <br>
 * <br>
 *          Revision 1.71 2008-03-21 08:16:46 heinemann <br>
 *          *** empty log message *** <br>
 * <br>
 *          Revision 1.70 2008-02-27 08:21:53 heinemann <br>
 *          added initModule call <br>
 * <br>
 *          Revision 1.69 2008-01-22 12:53:46 heinemann <br>
 *          fixed nullpointer if a calendar has a null value in the color
 *          property <br>
 * <br>
 *          Revision 1.68 2008-01-18 16:09:05 heinemann <br>
 *          code cleanup and java doc <br>
 * 
 */
public class AgendaModule extends GECAMedModule implements
		NamedCalendarListener, DateListener, SettingListener,
		PopupMenuCallback, GECAMedMessageListener, PhysicianListener {
	
	private final static Level LOGLEVEL = Level.DEBUG;
	
	private static DateFormat dayFormatter = new SimpleDateFormat("yyyy-MM-dd");

	private static final long serialVersionUID = 1L;

	public static final String ICON_AGENDA = "agendamodule.png";
	public static final String ICON_DAYVIEW = "cal_day.png";
	public static final String ICON_WEEKVIEW = "cal_week.png";

	public static final String ICON_MONTHVIEW = "cal_month.png";
	public static final String ICON_NEXT_PERIOD = "next_period.png";
	public static final String ICON_PREV_PERIOD = "prev_period.png";

	public static final String ICON_ABSENCE = "absence.png";
	public static final String ICON_BLOCK_PERIOD = "blockperiod.png";

	public static final String ICON_NEW_APPOINTMENT = "cal_new_appointment.png";
	public static final String ICON_FIND_NEW_APPOINTMENT = "cal_appointment.png";
	public static final String ICON_NEW_RECUREVENT = "newrecurevent.png";

	public static final String PATIENT = "patient.png";
	public static final String PATIENT_FILE = "patient_file.png";
	public static final String TIME_START = "time_start.png";
	public static final String TIME_STOP = "time_stop.png";
	public static final String TYPE = "type.png";

	public static final String TYPE_CONSULTATION = "type_consultation.png";
	public static final String TYPE_LABORATORY = "type_laboratory.png";
	public static final String TYPE_RADIOLOGY = "type_radiology.png";
	public static final String TYPE_VISIT = "type_visit.png";
	public static final String TYPE_PRIVATE = "private_appointment.png";

	public static final String NATIONAL_HOLIDAY = "national_holiday.png";
	public static final ImageIcon NATIONAL_HOLIDAY_ICON = getMediumIcon(NATIONAL_HOLIDAY);

	public static final String SEARCH_APPOINTMENT = "search_appointment.png";

	public static final String PREVIOUS = "previous_appointment.png";
	public static final String NEXT = "next_appointment.png";
	public static final String PREVIOUS_DAY = "previous_day.png";
	public static final String NEXT_DAY = "next_day.png";
	
	public static final String RECURRUNCE = "recurricon.png";
	
	public static final String ICON_STAIRCASE_DISPLAY = "staircase_display.png";
	public static final String ICON_COLUMN_DISPLAY = "column_display.png";
	
	protected static final String GENERIC_SETTING_ZOOM_VALUE = "AGENDA_GRID_ZOOM_POSITION";

	public static final String[] TYPE_ICONS = { "type_consultation.png",
			"type_laboratory.png", "type_radiology.png", "type_visit.png",
			"type_heart.png", "type_ill.png", "type_physio.png",
			"type_holiday.png", "type_birthday.png", "type_craft.png",
			"type_craft2.png", "type_remember.png", "type_blue.png",
			"type_green.png", "type_orange.png", "type_purple.png",
			"type_red.png", "type_yellow.png" };

	/**
	 * The name of the module
	 */
	public static final String MODULE_NAME = "Agenda";
	
	/**
	 * The logger Object for this class
	 */
	/** the logger Object for this class */
	private static Logger logger = Logger.getLogger(AgendaModule.class.getName());
	
	/**
	 * Needed beans
	 */
	private static AppointmentManager appointmentManager;

	private static PatientAdminInterface patientManager;

	private static OfficeManagerInterface officeManager;
	
	private static UserAdminInterface userManager;
	
	private HashMap<Integer, Timer> updateTasks = new HashMap<Integer, Timer>();
	
	
	/**
	 * Initialize all needed beans
	 */
	static
	{
		try{
			appointmentManager = (AppointmentManager) ManagerFactory.getRemote(AppointmentManagerBean.class);
			patientManager = (PatientAdminInterface) ManagerFactory.getRemote(PatientAdminBean.class);
			officeManager = (OfficeManagerInterface) ManagerFactory.getRemote(OfficeManagerBean.class);
			userManager = (UserAdminInterface) ManagerFactory.getRemote(UserAdminBean.class);
		} catch (Exception e) {
			logger.log(Level.WARN, "Couldn't set appointment-, patient- and physician- Bean in AgendaModule for log appointment modification.", e);
		}
	}

	private CalendarPanel calendarPanel;

	private JMenu agendaMenu;

	private EventModel dayModel;

	private EventModel dayThreeModel;

	private EventModel weekModel;

	private EventModel monthModel;

	private DayViewPanel dayViewPanel;

	private DayViewPanel dayThreeViewPanel;

	private DayViewPanel weekViewPanel;

	private MonthViewPanel monthViewPanel;

	private ObservableEventList eventDataList;

	private HashMap<NamedCalendar, AgendaCalendar> calendarHash;

	private Map<NamedCalendar, List<Event>> eventHash = Collections
			.synchronizedMap(new HashMap<NamedCalendar, List<Event>>());

	private EventModel listModel;

	private ListViewPanel listViewPanel;

	private int currentMonth = -1;

	private AgendaSettingsPlugin agendaSettingsPlugin;

	@SuppressWarnings("unused")
	private GeneralGECAMedTextMessageReciever topicListener;

	/**
	 * Clipboard for copy&paste
	 */
	private HashSet<Event> clipBoard = null;

	private JPopupMenu eventPopup;

	private AbstractAction modifyEventAction;

	private AbstractAction deleteEventAction;

	protected Event lastClickedEvent;

	private AbstractAction copyEventAction;

	private AbstractAction pasteEventAction;

	private AgendaCalendarListener calListener;

	private List<Event> selectedEvents;

	private DayViewConfig dConfig;

	private AppointmentSearchDialog appointmentSearchDialog;

	private static AgendaModule agendaModule;

	private Event lastProposedEvent;

	private FreeAppointmentFindDialog freeAppointmentFindDialog;

	private FreeAppointmentFinder finder;

	private HashMap<Integer, Appointment> patientNextAppointmentHash = new HashMap<Integer, Appointment>();

	public static AgendaAdminSettingsPlugin agendaAdminSettingsPlugin;

	private HashSet<NamedCalendar> displayingCalendars = new HashSet<NamedCalendar>();

	private JLabel dateLabel;

	private static ArrayList<Event> nationalHolidays;

	// for the logging of the modifications of appointment done by the user action in the agenda  
	public static final String CREATE_APPOINTMENT = "CREATE APPOINTMENT";
	public static final String CHANGE_APPOINTMENT = "CHANGE APPOINTMENT";
	public static final String DELETE_APPOINTMENT = "DELETE APPOINTMENT";
	public static final String CHANGE_APPOINTMENT_BY_DIALOG = "CHANGE APPOINTMENT BY DIALOG";
	
	// for the logging of the modifications of calendar
	public static final String CREATE_CALENDAR = "CREATE CALENDAR";
	public static final String CHANGE_CALENDAR = "CHANGE CALENDAR";
	public static final String DELETE_CALENDAR = "DELETE CALENDAR";
	
	// public static final String

	public static String userAktionToLog = "";

	/**
	 *
	 */
	public AgendaModule() {
		/* ================================================== */
		super(MODULE_NAME, getIcon(ICON_AGENDA), new Color(196, 228, 255));

		agendaModule = this;

		Translatrix.addBundle("lu.tudor.santec.gecamed.agenda.gui.resources.Translatrix");

		RegistrationDesk.addGECAMedMessageListener(this);
		RegistrationDesk.addPhysicianListener(this);
		
		
		/* ================================================== */
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see lu.tudor.santec.gecamed.core.gui.GECAMedModule#initModule()
	 */
	@Override
	protected void initModule() {
		/* ====================================================== */
		agendaAdminSettingsPlugin = new AgendaAdminSettingsPlugin();
		this.addAdminSettingsPlugin(agendaAdminSettingsPlugin);
		/* ------------------------------------------------------- */
		// install a settingslistener for global agenda settings
		/* ------------------------------------------------------- */
		MainFrame.getInstance().adminSettingsPanel.addSettingListener(this);
		MainFrame.getInstance().adminSettingsPanel.addSettingListener(new SettingListener()
		{
			public void settingChanged(SettingEvent evt)
			{
				if (AgendaAdminSettingsPlugin.NAME.equals(evt.getPluginName()))
				{
					if (AgendaAdminSettingsPlugin.HOUR_FRAGMENTATION.equals(evt.getSetting()))
					{
						setHourFragmentation();
					}
					
					if (AgendaAdminSettingsPlugin.AUTO_DESCRIPTION_MATR.equals(evt.getSetting()))
					{
						// TODO if something should triggered if the setting is change put it here
					}
					
					if (AgendaAdminSettingsPlugin.AUTO_DESCRIPTION_TYPE.equals(evt.getSetting()))
					{
						// TODO if something should triggered if the setting is change put it here
					}
					if (AgendaAdminSettingsPlugin.AUTO_DESCRIPTION_ID.equals(evt.getSetting()))
					{
						// TODO if something should triggered if the setting is change put it here
					}
				}
			}
		});
		/* ------------------------------------------------------- */
		agendaSettingsPlugin = new AgendaSettingsPlugin();
		this.addSettingsPlugin(agendaSettingsPlugin);

		MainFrame.getInstance().settingsPanel.addSettingListener(this);

		initComponents();
		initActions();

		initCalendars();
		
		fetchEventsForAllCalendars();

		setDate(new Date());

		initTopicListener();
		initEventPopup();
		initFreeAppointmentFinderDialog();

		calendarPanel.showView((String) agendaSettingsPlugin
				.getValue(AgendaSettingsPlugin.START_VIEW));
		/* ------------------------------------------------------- */
		this.appointmentSearchDialog = new AppointmentSearchDialog(this);
		/* ------------------------------------------------------- */
		// initialy get current physician
		/* ------------------------------------------------------- */
		physicianChanged(MainFrame.getCurrentPhysician());
		/* ====================================================== */
		
		MainFrame.addShutdownHook("storeCheckedCalendars", new Thread() {
			public void run() {
				logger.info("Saving selected Calendars"); 
				try {
					storeCheckedCalendars(calendarPanel.getCalendars());
				} catch (Throwable t) {
					logger.warn("ERROR Saving selected Calendars", t);
				}
			}
		});
	}

	/**
	 *
	 */
	private void initComponents() {
		/* ================================================== */

		this.dateLabel = new JLabel();
		this.dateLabel.setFont(new Font("Helvetica", Font.BOLD, 20));
		this.titlePanel.setHeaderComponent(this.dateLabel);
		
		
		this.agendaMenu = new JMenu(Translatrix
				.getTranslationString("Agenda.Agenda"));
		this.setModuleMenu(agendaMenu);

		calendarPanel = new CalendarPanel();

		/* ------------------------------------------------------- */
		// init calendar views
		/* ------------------------------------------------------- */
		// tuple for half day view
		Tuple halfDayTuple = new Tuple(7, 18);

		// create a list for the models
		this.eventDataList = new ObservableEventList();
		this.dayModel = new EventModel(eventDataList, EventModel.TYPE_DAY,
				halfDayTuple);
		/* ------------------------------------------------------- */
		this.dayThreeModel = new EventModel(eventDataList,
				EventModel.TYPE_THREE_DAY);
		this.weekModel = new EventModel(eventDataList, EventModel.TYPE_WEEK);
		this.monthModel = new EventModel(eventDataList, EventModel.TYPE_MONTH);
		this.listModel = new EventModel(eventDataList, EventModel.TYPE_MONTH);

		// ==================================================================================
		// adjust the config for the day views
		//
		// ==================================================================================
		this.dConfig = new DayViewConfig();
		// hours per day
		dConfig.setDefaultDayStartHour(DateUtil
				.getHourOfDay((Date) agendaSettingsPlugin
						.getValue(AgendaSettingsPlugin.START_HOUR)));
		dConfig.setDefaultDayEndHour(DateUtil
				.getHourOfDay((Date) agendaSettingsPlugin
						.getValue(AgendaSettingsPlugin.STOP_HOUR)));
		/* ------------------------------------------------------- */
		// days of week
		dConfig.setWeekStart((Integer) agendaSettingsPlugin
				.getValue(AgendaSettingsPlugin.WEEK_DAY_START));
		dConfig.setWeekStop((Integer) agendaSettingsPlugin
				.getValue(AgendaSettingsPlugin.WEEK_DAY_STOP));

		dConfig.setDayBreak((Integer) agendaSettingsPlugin
				.getValue(AgendaSettingsPlugin.DAY_BREAK));
		/* ------------------------------------------------------- */
		// the grid alpha
		dConfig.setGridAlpha((Integer) agendaSettingsPlugin
				.getValue(AgendaSettingsPlugin.GRID_ALPHA));
		/* ------------------------------------------------------- */
		// hour fragmentation
		/* ------------------------------------------------------- */
		setHourFragmentation();
		// ==================================================================================

		/* ------------------------------------------------------- */
		// set view layout from settings
		int mode = Layout.DAY_COLUMN_NORMAL;
		if (!(Boolean) agendaSettingsPlugin.getValue(AgendaSettingsPlugin.VIEW_LAYOUT))
			mode = Layout.DAY_COLUMN_SEPARATED_BY_CALENDAR;
		int showListDays = 7;
		if (agendaSettingsPlugin.getValue(AgendaSettingsPlugin.LIST_VIEW_PERIOD) != null)
			showListDays	= ((Integer) agendaSettingsPlugin.getValue(AgendaSettingsPlugin.LIST_VIEW_PERIOD)).intValue();
		
		this.dayViewPanel = new DayViewPanel(dayModel, dConfig, mode);
		this.dayThreeViewPanel = new DayViewPanel(dayThreeModel, dConfig, mode);
		this.weekViewPanel = new DayViewPanel(weekModel, dConfig, mode);
		this.monthViewPanel = new MonthViewPanel(monthModel);
		this.listViewPanel = new ListViewPanel(listModel);
		this.listViewPanel.setShowDays(showListDays);
		/* ------------------------------------------------------- */

		calListener = new AgendaCalendarListener();

		dayViewPanel.addCalendarListener(calListener);
		dayThreeViewPanel.addCalendarListener(calListener);
		weekViewPanel.addCalendarListener(calListener);
		monthViewPanel.addCalendarListener(calListener);
		listViewPanel.addCalendarListener(calListener);

		/* ------------------------------------------------------- */
		calendarPanel.addCalendarView(dayViewPanel);
		calendarPanel.addCalendarView(dayThreeViewPanel);
		calendarPanel.addCalendarView(weekViewPanel);
		calendarPanel.addCalendarView(monthViewPanel);
		calendarPanel.addCalendarView(listViewPanel);
		/* ------------------------------------------------------- */
		// set poupmenu callback to all views
		dayViewPanel.getView().setPopupMenuCallback(this);
		dayThreeViewPanel.getView().setPopupMenuCallback(this);
		weekViewPanel.getView().setPopupMenuCallback(this);
		/* ------------------------------------------------------- */
		calendarPanel.addDateListener(this);
		this.setContentPanel(calendarPanel);
		/* ------------------------------------------------------- */
		// the listener for managing calendars itself
		calendarPanel.addCalendarManagementListener(new CalendarManagementListener()
		{
			// ======================================================
			// delete calendar
			// ======================================================
			public void deleteCalendar(NamedCalendar calendar)
			{
				boolean delete = false;
				// find the events matching the calendar
				// count entrys
				int entryCounter = 0;
				for (Event e : eventDataList) {
					if (e.getId() != null
							&& ((Appointment) e.getId()).getCalendarId() == calendar
									.getId().intValue())
						entryCounter++;
				}
				
				if(entryCounter > 0)
				{
					JPasswordField passwordField = new JPasswordField(10);
			        passwordField.setEchoChar('*');
			        JPanel passwordPanel = new JPanel();
			        JLabel message = new JLabel(Translatrix.getTranslationString("calendar.management.deleteCalendarWithAppointment", new String[] {"" + entryCounter}));
			        passwordPanel.setLayout(new BorderLayout());
			        passwordPanel.add(message, BorderLayout.NORTH);
			        passwordPanel.add(passwordField, BorderLayout.SOUTH);
			        
			        boolean firstTime = true;
			        
			        String userPassword = GECAMedModule.getCurrentUser().getPasswordhash();
			        String password = "";
			        
			        passwordField.addAncestorListener( new RequestFocusListener() );
			        
			        while(!(password).equals(userPassword))
			        {
				        int result = GECAMedOptionPane.showConfirmDialog(
				        		//MessageDialog(
				        		MainFrame.getInstance(),
				                passwordPanel,
				                Translatrix.getTranslationString("calendar.core.remove"),
				                JOptionPane.YES_NO_OPTION);
				        
				        if (result == JOptionPane.NO_OPTION || result == -1)
							return;
				        
				        if (result == JOptionPane.YES_OPTION)
				        {
				        	
				        	try {
								password = PasswordChangeDialog.getEncodedHash(String.valueOf(passwordField.getPassword()));
							} catch (NoSuchAlgorithmException e1) {
								e1.printStackTrace();
							} catch (IOException e1) {
								e1.printStackTrace();
							}
				        	
				        	
				        	if(password.equals(userPassword))
				        	{
				        		delete = true;
				        		break;
				        	}else{
				        		if(firstTime)
				        		{
				        			firstTime = false;
					        		StringBuffer str = new StringBuffer("<HTML><BODY>");
					        		str.append(message.getText());
					        		str.append("<BR><BR>");
					        		str.append(Translatrix.getTranslationString("calendar.management.deleteCalendarTypAgain"));
					        		str.append("</BODY></HTML>");
					        		message.setText(str.toString());
				        		}
				        		passwordField.setText("");
				        	}
				        }
			        }
				}else{
					int reply = GECAMedOptionPane.showOptionDialog(
							MainFrame.getInstance(),
							Translatrix.getTranslationString("calendar.core.remove"),
							Translatrix.getTranslationString("calendar.management.deleteCalendar"),
							JOptionPane.YES_NO_OPTION);
							// GECAMedOptionPane.ICON_QUESTION);
					/* ------------------------------------------------------ */
					if (reply == JOptionPane.NO_OPTION)
						return;
					
					/* ------------------------------------------------------ */
					if (reply == JOptionPane.YES_OPTION)
					{
						delete = true;
					}
				}
				
				if(delete)
				{
					AgendaCalendar agendaCalendar = appointmentManager.getCalendar(calendar.getId());
					logUserActionAgenda(DELETE_CALENDAR, agendaCalendar, null);
					// delete calendar
					AppointmentManager apManager = (AppointmentManager) ManagerFactory.getRemote(AppointmentManagerBean.class);
					// remove from database
					apManager.removeCalendar(MainFrame.getClientId(), calendarHash.get(calendar));
					removeCalendarStructure(calendar);
					try {	
						apManager.sendCalendarUpdateMessage(
								MainFrame.getClientId(),
								AppointmentManager.MSG_REMOVED_CALENDAR,
								calendar.getId(),
								null);
					} catch (JMSException e) {
						logger.error("Error while trying to notify clients about deletion of calendar", e);
					}
					// calendarPanel.triggerUpdate();
				}
				// reload events
				fetchEventsForAllCalendars();
			}
			
			// ======================================================
			// modify calendar
			// ======================================================
			public void modifyCalendar(NamedCalendar calendar)
			{
				AgendaCalendar oldCalendar	= appointmentManager.getCalendar(calendar.getId());
				AgendaCalendar newCalendar	= calendarHash.get(calendar);
				
				AgendaCalendarModifyDialog agd = AgendaCalendarModifyDialog.getInstance();
				if (agd.showDialog(newCalendar) != GECAMedBaseDialog.OK_OPTION)
					return;
				
				newCalendar	= agd.updateCalendar(newCalendar, calendar);
				informCalendarChanges(newCalendar, AppointmentManager.MSG_UPDATE_CALENDAR);
				
//				updateCalendarStructure(newCalendar, false);
				// update the event color
				updateEventCalendarData(calendar);
				logUserActionAgenda(CHANGE_CALENDAR, newCalendar, oldCalendar);
			}
			
			// ======================================================
			// new calendar
			// ======================================================
			public void newCalendar()
			{
				AgendaCalendarModifyDialog agd = AgendaCalendarModifyDialog.getInstance();
				AgendaCalendar	newCalendar	= agd.showDialog();
				
				if (newCalendar == null)
					return;
				
				NamedCalendar	nCal = new DefaultNamedCalendar(newCalendar.getTitle(), newCalendar, GECAMedModule.getDefaultLocale());
				calendarHash.put(nCal, newCalendar);
				
				newCalendar	= agd.updateCalendar(newCalendar, nCal);
				informCalendarChanges(newCalendar, AppointmentManager.MSG_ADDED_CALENDAR);
				
				
				try
				{
					appointmentManager.sendCalendarUpdateMessage(MainFrame.getClientId(),
							AppointmentManager.MSG_ADDED_CALENDAR,
							newCalendar.getId(),
							null);
				}
				catch (JMSException e)
				{
					logger.error("Error while trying to notify clients about creation of calendar", e);
				}
				
				updateCalendarStructure(newCalendar);
				logUserActionAgenda(CREATE_CALENDAR, newCalendar, null);
			}
		});
		/* ================================================== */

		JButton printView = new JButton(Translatrix
				.getTranslationString("Agenda.printView"), GECAMedModule
				.getMediumIcon(GECAMedModule.PRINT));
		printView.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				boolean showPrinterDialog = (Boolean) MainFrame.getInstance().userSettings
						.getValue(UserSettingsPlugin.PRINTER_DIALOG_ENABLED);
				calendarPanel.getCurrentView().print(showPrinterDialog);
			}
		});
		try {
			/* --------------------------------------------- */
			calendarPanel.setZoomPosition(Integer.parseInt(MainFrame
					.getInstance().userSettings
					.readGenericSetting(GENERIC_SETTING_ZOOM_VALUE)));
			/* --------------------------------------------- */
		} catch (Exception e) {
			/* --------------------------------------------- */
			// e.printStackTrace();
			/* --------------------------------------------- */
		}

		calendarPanel.addZoomSliderListener(new IZoomSliderListener() {

			public void zoomPositionchanged(int value) {
				/* ====================================================== */
				// store the position in the database
				/* ------------------------------------------------------- */
				MainFrame.getInstance().userSettings.addGenericSetting(
						GENERIC_SETTING_ZOOM_VALUE, "" + value);
				/* ====================================================== */
			}

		});

		JButton export = new JButton(Translatrix
				.getTranslationString("Agenda.exportCurrentView"),
				GECAMedModule.getMediumIcon(GECAMedModule.SAVE));
		final JFileChooser jfc = new JFileChooser();
		jfc.setLocale(Translatrix.getLocale());
		jfc.setFileFilter(new FileFilter() {
			@Override
			public boolean accept(File f) {
				if (f.getName().toLowerCase().endsWith(".ics"))
					return true;
				else if (f.isDirectory())
					return true;
				return false;
			}

			@Override
			public String getDescription() {
				return "iCalendar (.ics)";
			}
		});
		export.addActionListener(new ActionListener() {

			public void actionPerformed(ActionEvent e) {
				IcalImportExporter exporter = new IcalImportExporter(
						GECAMedLists.getListReference(AgendaCalendar.class),
						GECAMedLists.getListReference(AppointmentType.class)
						);
				File f = new File(System.getProperty("user.home")
						+ File.separator + "gecamed.ics");
				jfc.setSelectedFile(f);
				if (jfc.showSaveDialog(AgendaModule.this) != JFileChooser.APPROVE_OPTION)
					return;
				net.fortuna.ical4j.model.Calendar calendar = exporter.exportEvents(calendarPanel.getCurrentView().getEvents());
				f = jfc.getSelectedFile();
				if (!f.getName().toLowerCase().endsWith(".ics")) {
					f = new File(f.getName() + ".ics");
				}
				exporter.writeICALFile(calendar, f);
			}
		});

		// =======================================================
		// button to create a appointment
		// =======================================================
		JButton createButton = new JButton(Translatrix
				.getTranslationString("Agenda.createNewAppointment"),
				AgendaModule.getMediumIcon(ICON_NEW_APPOINTMENT));

		// new style for the Buttons
		createButton.setHorizontalAlignment(SwingConstants.LEFT);
		createButton.setEnabled(true);
		createButton.setIconTextGap(1);
		createButton.setFont(GECAMedFonts.BUTTON_FONT);
		createButton.setMargin(new java.awt.Insets(0, 0, 0, 0));

		createButton.addActionListener(new ActionListener() {

			public void actionPerformed(ActionEvent e) {

				/* ====================================================== */
				NamedCalendar nc = calendarPanel.getSelectedCalendar();
				/* ------------------------------------------------------- */
				if (nc == null)
					return;
				/* ------------------------------------------------------- */
				Appointment ap = new Appointment();
				ap.setStartDate(new Date());
				/* ------------------------------------------------------- */
				int duration = AgendaModule.getTypeForClassId(
						AppointmentType.GENERAL).getDuration();
				ap.setEndDate(DateUtil
						.moveByMinute(ap.getStartDate(), duration));
				/* ------------------------------------------------------- */
				ap.setTypeId(AgendaModule.getTypeForClassId(
						AppointmentType.GENERAL).getId());
				ap.setCalendarId(calendarPanel.getSelectedCalendar().getId());

				Event ev = AgendaModule.appointment2Event(ap);
				ev.setId(ap);
				/* ------------------------------------------------------- */
				updateEvent(null, nc.saveEvent(MainFrame.getClientId(), ev,
						true));

				/* ====================================================== */
			}

		});

		// =======================================================
		// button to add search appoitments
		// =======================================================
		JButton searchAppointmentButton = new JButton(Translatrix
				.getTranslationString("Agenda.searchAppointment"), AgendaModule
				.getMediumIcon(SEARCH_APPOINTMENT));

		// new style for the Buttons
		searchAppointmentButton.setHorizontalAlignment(SwingConstants.LEFT);
		searchAppointmentButton.setEnabled(true);
		searchAppointmentButton.setIconTextGap(1);
		searchAppointmentButton.setFont(GECAMedFonts.BUTTON_FONT);
		searchAppointmentButton.setMargin(new java.awt.Insets(0, 0, 0, 0));

		searchAppointmentButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				appointmentSearchDialog.showDialog();
			}
		});

		// ===================================================
		// Button to find and create a new Appointment
		// ===================================================
		JButton findCreateButton = new JButton(Translatrix
				.getTranslationString("Agenda.findfree.button"), AgendaModule
				.getMediumIcon(ICON_FIND_NEW_APPOINTMENT));
		// new style for the Buttons
		findCreateButton.setHorizontalAlignment(SwingConstants.LEFT);
		findCreateButton.setEnabled(true);
		findCreateButton.setIconTextGap(1);
		findCreateButton.setFont(GECAMedFonts.BUTTON_FONT);
		findCreateButton.setMargin(new java.awt.Insets(0, 0, 0, 0));

		// the old style of the function buttons
		// findCreateButton.setPreferredSize(new
		// Dimension(findCreateButton.getPreferredSize().width, 70));

		// findCreateButton.setFont(new
		// Font(findCreateButton.getFont().getName(),
		// findCreateButton.getFont().getStyle(),
		// 18));
		/* ------------------------------------------------------- */
		findCreateButton.addActionListener(new ActionListener() {

			public void actionPerformed(ActionEvent e) {
				/* ====================================================== */
				showFreeAppointmentFinderDialog();
				/* ====================================================== */
			}
		});

		/* ================================================== */
		// for align botton =)
		JPanel gluePanel = new JPanel(new FormLayout(
		// cols
				"1dlu,109dlu,1dlu",
				// rows
				"2dlu," + // 1
						"fill:pref," + // 2
						"3dlu," + // 3
						"fill:pref," + // 4
						"3dlu," + // 5
						"fill:pref," + // 6
						"5dlu")); // 11
		gluePanel.setOpaque(false);
		/* ------------------------------------------------------- */
		CellConstraints cc = new CellConstraints();
		/* ------------------------------------------------------- */

		// add button navi panel
		gluePanel.add(findCreateButton, cc.xyw(2, 2, 1));
		gluePanel.add(createButton, cc.xyw(2, 4, 1));
		gluePanel.add(searchAppointmentButton, cc.xyw(2, 6, 1));

		calendarPanel.getFunctionsButtonPanel().add(gluePanel);
		/* ================================================== */
	}

	/**
	 * Obtains all calendars from the database
	 */
	private void initCalendars()
	{
		List<AgendaCalendar>		calendars			= GECAMedLists.getListReference(AgendaCalendar.class);
		Collection<AgendaCalendar>	selectedCalendars	= getCheckedCalendars();
		DefaultNamedCalendar		dnc;
		
		
//		AgendaModule.loadCalendars();
		calendarHash = new HashMap<NamedCalendar, AgendaCalendar>();
		
		// get the selected calendars for this user
		
		for (AgendaCalendar ag : calendars)
		{
			dnc = new DefaultNamedCalendar(ag.getTitle(), ag, 
					(Locale) agendaAdminSettingsPlugin.getValue(AgendaAdminSettingsPlugin.CALENDAR_LOCALE));
			/* ------------------------------------------------------- */
			// check if color is present. If not, take default red
			/* ------------------------------------------------------- */
			if (ag.getColor() != null)
				dnc.setColor(new Color(ag.getColor()));
			else
				dnc.setColor(Color.RED);
			// select the calendar if it is in selectedCalendars
			if (selectedCalendars != null && selectedCalendars.contains(ag))
			{
				dnc.setActive(true);
			}
			calendarPanel.addNamedCalendar(dnc);
			// store the key:value relation
			calendarHash.put(dnc, ag);
		}
		
		// if there are no calendars in the database, create a default one
		if (calendars.size() < 1)
		{
			createDefaultCalendar();
		}
		calendarPanel.addNamedCalendarListener(AgendaModule.this);
		// if (cals.size() != 0)
		// selectCalendar(((AgendaCalendar)cals.get(0)).getId());
		
//		selectedCalendars = getCheckedCalendars();
	}

	/**
	 * Creates a red default calendar
	 */
	private void createDefaultCalendar() {
		/* ================================================== */
		try {
			/* ------------------------------------------------------- */
			AppointmentManager ap = (AppointmentManager) ManagerFactory
					.getRemote(AppointmentManagerBean.class);

			AgendaCalendar defaultCal = ap.createDefaultCalendar();

			informCalendarChanges(defaultCal,AppointmentManager.MSG_ADDED_CALENDAR);
			/* ------------------------------------------------------- */
		} catch (Exception e) {
			e.printStackTrace();
		}
		/* ================================================== */
	}

	/**
	 * Init GECAMedActions for date stepping
	 */
	private void initActions() {
		// =================================================================
		// Print Button
		// =================================================================
		new GECAMedAction(this, "Agenda.printView", GECAMedModule
				.getIcon(GECAMedModule.PRINT), KeyEvent.VK_UNDEFINED, true,
				true, false, KeyEvent.VK_UNDEFINED) {
			private static final long serialVersionUID = 1L;

			public void actionPerformed(ActionEvent e) {
				if (calendarPanel.getCurrentView().getViewName() == ListViewPanel.VIEW_NAME) {
					// extra print function for the ListViewPanel
					List<Event> eventList = calendarPanel.getCurrentView().getEvents();

					AgendaPrinter.print(
									eventList,
									eventList.size(),
//									AgendaPrinter.PHYSICIAN_TEMPLATE_TYPE,
									JasperTemplateBean.AGENDA_PHYSICIAN_APPOINTMENTS,
//									AgendaPrinter.PHYSICIAN_DEFAULT_TEMPLATE_FILE,
									null);
				} else {
					boolean showPrinterDialog = (Boolean) MainFrame
							.getInstance().userSettings
							.getValue(UserSettingsPlugin.PRINTER_DIALOG_ENABLED);
					calendarPanel.getCurrentView().print(showPrinterDialog);
				}
			}
		}.add();

		// =================================================================
		// Export Button
		// =================================================================
		final JFileChooser jfc = new JFileChooser();

		jfc.setLocale(Translatrix.getLocale());
		jfc.setFileFilter(new FileFilter() {
			@Override
			public boolean accept(File f) {
				if (f.getName().toLowerCase().endsWith(".ics"))
					return true;
				else if (f.isDirectory())
					return true;
				return false;
			}

			@Override
			public String getDescription() {
				return "iCalendar (.ics)";
			}
		});

		new GECAMedAction(this, "Agenda.exportCurrentView", GECAMedModule
				.getIcon(GECAMedModule.EXPORT), KeyEvent.VK_UNDEFINED, true,
				true, false, KeyEvent.VK_UNDEFINED) {
			private static final long serialVersionUID = 1L;

			public void actionPerformed(ActionEvent e) {
				IcalImportExporter exporter = new IcalImportExporter(
						GECAMedLists.getListReference(AgendaCalendar.class),
						GECAMedLists.getListReference(AppointmentType.class)
						);
				File f = new File(System.getProperty("user.home")
						+ File.separator + "gecamed.ics");
				jfc.setSelectedFile(f);
				if (jfc.showSaveDialog(AgendaModule.this) != JFileChooser.APPROVE_OPTION)
					return;
				net.fortuna.ical4j.model.Calendar calendar = exporter.exportEvents(calendarPanel.getCurrentView().getEvents());
				f = jfc.getSelectedFile();
				if (!f.getName().toLowerCase().endsWith(".ics")) {
					f = new File(f.getName() + ".ics");
				}
				exporter.writeICALFile(calendar, f);
			}
		}.add();

		new GECAMedAction(this, "calendar.actions.previous",
				getIcon(ICON_PREV_PERIOD), KeyEvent.VK_UNDEFINED, true, true,
				false, KeyEvent.VK_F6) {
			private static final long serialVersionUID = 1L;

			public void actionPerformed(ActionEvent e) {
				calendarPanel.pevious();
			}
		}.add();

		new GECAMedAction(this, "calendar.actions.next",
				getIcon(ICON_NEXT_PERIOD), KeyEvent.VK_UNDEFINED, true, true,
				false, KeyEvent.VK_F7) {
			private static final long serialVersionUID = 1L;

			public void actionPerformed(ActionEvent e) {
				calendarPanel.next();
			}
		}.add();
		/* ------------------------------------------------------- */
		new GECAMedAction(this, "calendar.actions.reload", IconFetcher.getIcon(
				GECAMedIconNames.class, GECAMedIconNames.RELOAD),
				KeyEvent.VK_UNDEFINED, true, true, false, KeyEvent.VK_F5) {
			private static final long serialVersionUID = 1L;

			public void actionPerformed(ActionEvent e) {
				/* ================================================== */
				fetchEventsForAllCalendars();
				/* ================================================== */
			}
		}.add();

		/* ------------------------------------------------------- */

		new GECAMedAction(this, "calendar.actions.previouscalendar",
				getIcon(ICON_NEXT_PERIOD), KeyEvent.VK_UNDEFINED, false, false,
				false, KeyEvent.VK_F1) {
			private static final long serialVersionUID = 1L;

			public void actionPerformed(ActionEvent e) {
				calendarPanel.selectPreviousCalendar();
			}
		}.add();
		
		/* ------------------------------------------------------- */
		new GECAMedAction(this, "calendar.actions.nextcalendar",
				getIcon(ICON_NEXT_PERIOD), KeyEvent.VK_UNDEFINED, false, false,
				false, KeyEvent.VK_F2) {
			private static final long serialVersionUID = 1L;

			public void actionPerformed(ActionEvent e) {
				calendarPanel.selectNextCalendar();
			}
		}.add();
		
		/* ------------------------------------------------------- */
		new GECAMedAction(this, "calendar.actions.toggleAllCalendars",
				getIcon(ICON_NEXT_PERIOD), KeyEvent.VK_UNDEFINED, false, false,
				false, KeyEvent.VK_F4) {
			private static final long serialVersionUID = 1L;

			public void actionPerformed(ActionEvent e) {
				calendarPanel.toggleShowAllCalendars();
			}
		}.add();
		
		// =================================================================
		// Switch Viewlayout Button (as toggel button)
		// =================================================================
		String icon = ICON_STAIRCASE_DISPLAY;
		String tooltip = "calendar.actions.staircaseDisplay";
		if ((Boolean) agendaSettingsPlugin.getValue(AgendaSettingsPlugin.VIEW_LAYOUT))
		{
			icon = ICON_COLUMN_DISPLAY;
			tooltip = "calendar.actions.columnDisplay";
		}
		
		new GECAMedAction(this, tooltip, getScaledIcon(icon, NORMALPIX), KeyEvent.VK_UNDEFINED, true, true, false, KeyEvent.VK_UNDEFINED)		//viewLayoutButton = new GECAMedAction(this, "Agenda.printView", getIcon(ICON_DAYVIEW), KeyEvent.VK_UNDEFINED, true, true, false, KeyEvent.VK_UNDEFINED)
		{
			private static final long serialVersionUID = 1L;
			public void actionPerformed(ActionEvent e) {
				
				if (
						calendarPanel.getCurrentView().getViewName() == DayViewPanel.VIEW_NAME_DAY  ||
						calendarPanel.getCurrentView().getViewName() == DayViewPanel.VIEW_NAME_WEEK || 		
						calendarPanel.getCurrentView().getViewName() == DayViewPanel.VIEW_NAME_THREE_DAY
					) {
					
					if ((Boolean) agendaSettingsPlugin.getValue(AgendaSettingsPlugin.VIEW_LAYOUT))
					{
						this.setTopButtonIcon(getIcon(ICON_STAIRCASE_DISPLAY));
						this.setToolTipText(Translatrix.getTranslationString("calendar.actions.staircaseDisplay"));
						((DayView) dayViewPanel.getView()).setLayoutMode(Layout.DAY_COLUMN_SEPARATED_BY_CALENDAR);
						((DayView) dayThreeViewPanel.getView()).setLayoutMode(Layout.DAY_COLUMN_SEPARATED_BY_CALENDAR);
						((DayView) weekViewPanel.getView()).setLayoutMode(Layout.DAY_COLUMN_SEPARATED_BY_CALENDAR);
					}else{
						this.setTopButtonIcon(getIcon(ICON_COLUMN_DISPLAY));
						this.setToolTipText(Translatrix.getTranslationString("calendar.actions.columnDisplay"));
						((DayView) dayViewPanel.getView()).setLayoutMode(Layout.DAY_COLUMN_NORMAL);
						((DayView) dayThreeViewPanel.getView()).setLayoutMode(Layout.DAY_COLUMN_NORMAL);
						((DayView) weekViewPanel.getView()).setLayoutMode(Layout.DAY_COLUMN_NORMAL);	
					}
					// set user setting
					agendaSettingsPlugin.setValueAndSave(AgendaSettingsPlugin.VIEW_LAYOUT, !(Boolean) agendaSettingsPlugin.getValue(AgendaSettingsPlugin.VIEW_LAYOUT));
					// refresch all argenda views
					dayViewPanel.refresh();
					dayThreeViewPanel.refresh();
					weekViewPanel.refresh();		
				}
			}
		}.add();
		
		/* ================================================== */
	}

	/**
	 * Inits the listener for the JMS topic to update the calendars if there are
	 * changes on a loaded calendar by another user
	 */
	private void initTopicListener() {
		/* ================================================== */
		this.topicListener = new GeneralGECAMedTextMessageReciever(
				AppointmentManager.TOPIC_NAME, new MessageListener() {

					@SuppressWarnings("unchecked")
					public void onMessage(Message msg) {
						/*
						 * ======================================================
						 */
						if (msg instanceof ObjectMessage) {
							ObjectMessage om = (ObjectMessage) msg;
							try {
								// run the updater
								if (om.getObject() instanceof ArrayList) {
									ArrayList<Object> baseTupel = (ArrayList<Object>) om.getObject();
									String clientId = (String) baseTupel.get(0);
									// if this is our client id, do nothing
									if (MainFrame.getClientId().equals(clientId)) {
										return;
									}
									int[] t = (int[]) baseTupel.get(1);
									final int updateType = t[0];
									final int calendarID = t[1];
									
									Date changed = null;
									try {										
										if (baseTupel.size() >= 3 ) {
											changed = (Date) baseTupel.get(2);
										}
									} catch (Exception e) {
										logger.warn("Error parsing Calendar Update Message");
									}
									
									final Date changedDate = changed;
									
									// handle update message asynchronous
									TimerTask reloadCal = new TimerTask() {
										public void run() {
											updateCalendar(updateType, calendarID, changedDate);
										}
									};
									
									// check if there is an update Task still queued, then stop that
									Timer timer = updateTasks.get(calendarID);
									if (timer != null) {
										timer.cancel();
									}
									timer = new Timer();
									timer.schedule(reloadCal, 5000);
									updateTasks.put(calendarID, timer);
									
								}
							} catch (Throwable e) {
								logger.error(e.getMessage(), e);
							}
						}
						/*
						 * ======================================================
						 */
					}

				});
		/* ================================================== */
	}

	/**
	 * Shows the FreeAppointmentFinderDialog. It checks if there is already one
	 * visible
	 */
	public void showFreeAppointmentFinderDialog() {
		/* ================================================== */
		if (!freeAppointmentFindDialog.isVisible())
		{
			/* ------------------------------------------------------- */
			NamedCalendar nc = calendarPanel.getSelectedCalendar();
			initFreeAppointmentFinderDialog();
			freeAppointmentFindDialog.showDialog(calendarHash.get(nc));

			freeAppointmentFindDialog.setPatient(GECAMedModule
					.getCurrentPatient());
			/* ------------------------------------------------------- */
		}
		/* ================================================== */
	}

	/**
	 * Inits the FreeAppointmentFinder dialog
	 */
	private void initFreeAppointmentFinderDialog() {
		/* ================================================== */
//		this.finder = new FreeAppointmentFinder();

		this.freeAppointmentFindDialog = new FreeAppointmentFindDialog();
		this.finder = new FreeAppointmentFinder(this.freeAppointmentFindDialog);
		this.freeAppointmentFindDialog.setAppointmentFinder(finder);
		this.freeAppointmentFindDialog.init(false);
		
		freeAppointmentFindDialog.addPropertyChangeListener(new PropertyChangeListener() {

					public void propertyChange(PropertyChangeEvent evt) {
						/*
						 * ======================================================
						 */
						if (FreeAppointmentFindDialog.PROPOSAL_CHANGED == evt.getPropertyName()) {

							// remove old proposal, add new proposal
							eventDataList.setEnableNotify(false);
							eventDataList.remove(lastProposedEvent);
							eventDataList.setEnableNotify(true);

							// if (evt.getNewValue() != null);
							lastProposedEvent = appointment2Event((Appointment) evt
									.getNewValue());
							// set a flag to keep this event away from the
							// normal storing process
							lastProposedEvent.set(Event.EVENT_PROPOSAL_STATE, true);

							// move the calendar view to the date
							calendarPanel.setDate(lastProposedEvent.getStart());

							// add the proposal to the datalist for all events
							eventDataList.add(lastProposedEvent);

						}
						// we must check like this, because the dialog is
						// non-modal
						if (FreeAppointmentFindDialog.DIALOG_CLOSED == evt.getPropertyName()) {
							// remove if cancel was pressed
							if (evt.getNewValue() == null) {
								eventDataList.setEnableNotify(false);
								eventDataList.remove(lastProposedEvent);
								updateEventsForActiveCalendars(true);
							} else {
								// save the appointment
								calendarPanel.getSelectedCalendar().saveEvent(
										MainFrame.getClientId(),
										lastProposedEvent, false);
								// fetch events. Fetch calls
								// updateActiveCalenders inside
								fetchEventsForAllCalendars();
							}

						}
					}

				});
	}

	/**
	 * Init the popup for mouse interactions on events
	 */
	private void initEventPopup() {
		/* ================================================== */
		this.eventPopup = new JPopupMenu();

		// ===============================================
		// M O D I F Y Action
		// ===============================================
		this.modifyEventAction = new AbstractAction(Translatrix
				.getTranslationString("calendar.core.modify"), CalendarIcons
				.getMediumIcon(CalendarIcons.EDIT)) {

			private static final long serialVersionUID = 1L;

			public void actionPerformed(ActionEvent e) {
				/* ====================================================== */
				if (lastClickedEvent != null)
					modifyEvent(lastClickedEvent);
				/* ====================================================== */
			}
		};
		// ===============================================
		// D E L E T E Action
		// ===============================================
		this.deleteEventAction = new AbstractAction(Translatrix
				.getTranslationString("calendar.core.remove"), CalendarIcons
				.getMediumIcon(CalendarIcons.DELETE)) {

			private static final long serialVersionUID = 1L;

			public void actionPerformed(ActionEvent e) {
				/* ====================================================== */
				try {
					calListener.deleteEvents(AgendaModule.this.selectedEvents);
				} catch (Exception e1) {
				}
				/* ====================================================== */
			}
		};
		// ===============================================
		// C O P Y Action
		// ===============================================
		this.copyEventAction = new AbstractAction(Translatrix
				.getTranslationString("calendar.core.copy"), CalendarIcons
				.getMediumIcon(CalendarIcons.COPY)) {

			private static final long serialVersionUID = 1L;

			public void actionPerformed(ActionEvent e) {
				/* ====================================================== */
				try {
					// Harr Harr
					calendarPanel.getCurrentView().getView().copy();
				} catch (Exception e1) {
				}
				/* ====================================================== */
			}
		};

		// ===============================================
		// P A S T E Action
		// ===============================================
		this.pasteEventAction = new AbstractAction(Translatrix
				.getTranslationString("calendar.core.paste"), CalendarIcons
				.getMediumIcon(CalendarIcons.PASTE)) {

			private static final long serialVersionUID = 1L;

			public void actionPerformed(ActionEvent e) {
				/* ====================================================== */
				Integer calID = copyEvents();
				// reload events
				try {
					fetchEvents(getCalendarForId(calID));				
				} catch (Exception e1) {
					logger.warn("Error reloading pasted Events", e1);
					fetchEventsForAllCalendars();	
				}
				/* ====================================================== */
			}
		};

		/* ------------------------------------------------------- */
		this.eventPopup.add(modifyEventAction);
		this.eventPopup.add(new JSeparator());

		this.eventPopup.add(this.copyEventAction);
		this.eventPopup.add(this.pasteEventAction);

		this.eventPopup.add(new JSeparator());
		this.eventPopup.add(deleteEventAction);
		/* ================================================== */
	}

	/**
	 * Copy the events from the clipboard to the selected date
	 */
	@SuppressWarnings("unchecked")
	private Integer copyEvents() {
		Integer calID = null;
		/* ================================================== */
		try {
			// copyEvents();
			if (clipBoard != null) {
				/* ------------------------------------------------------- */
				NamedCalendar nc = calendarPanel.getSelectedCalendar();
				/* ------------------------------------------------------- */
				if (nc == null)
					return calID;
				/* ------------------------------------------------------- */

				int count = 0;
				Date revDate = null;
				Date moveDate = calendarPanel.getCurrentView().getView()
						.getSelectionDate();
				List<Event> copiedEvents = new ArrayList<Event>();
				/* ------------------------------------------------------- */
				List<Event> tempEvents = new ArrayList<Event>(clipBoard);
				Collections.sort(tempEvents);
				// move the copied events
				for (Event ev : tempEvents) {
					/* ------------------------------------------------------- */
					Event en = ev.copy();
					if (count == 0) {
						revDate = new Date(ev.getStart().getTime());
						en.move(moveDate);
						count = 1;
					} else {
						/*
						 * ------------------------------------------------------
						 * -
						 */
						// compute the distance of the event to the rev date
						long diff = DateUtil.getDiffDay(revDate, ev.getStart());
						en.move(new Date(moveDate.getTime() + diff));
						/*
						 * ------------------------------------------------------
						 * -
						 */
					}
					if (en.getId() instanceof Appointment) {
						Appointment ap = (Appointment) en.getId();
						ap.setId(null);
						calID = ap.getCalendarId();
					} else
						en.setId(null);
					// en = nc.saveEvent(MainFrame.getClientId(), en, false);
					copiedEvents.addAll(nc.saveEvent(MainFrame.getClientId(),
							en, false));
					/* ------------------------------------------------------- */
				}

				/* ------------------------------------------------------- */
				eventDataList.addAll(copiedEvents);
			}
			/* ------------------------------------------------------- */
		} catch (Exception e1) {
			logger.warn("Error copying Events", e1);
		}
		return calID;
		/* ================================================== */
	}

	/**
	 * @param event
	 */
	private void modifyEvent(Event event) {
		/* ================================================== */
		// show edit dialog
		NamedCalendar nc = calendarPanel.getSelectedCalendar();
		/* ------------------------------------------------------- */
		if (nc == null)
			return;
		Appointment ap = (Appointment) event.getId();
		/* ------------------------------------------------------- */
		List<Event> newEvents = nc.saveEvent(MainFrame.getClientId(),appointment2Event(ap), true);
		if (newEvents != null) {
			updateEvent(event, newEvents);			
		}
	
//		// reload events for all calendars
//		fetchEventsForAllCalendars();
		
		// TODO JH NO RELOADED NEEDED HERE
//		try {
//			// fetch events for old calendar of event
//			fetchEvents(getCalendarForId(ap.getCalendarId()));
//			
//			if (newEvents != null && newEvents.size() > 0) {
//				Appointment newApp = (Appointment) newEvents.get(0).getId();
//				if (newApp != null && ap.getCalendarId() != newApp.getCalendarId()) {
//					// fetch events for new calendar of event
//					fetchEvents(getCalendarForId(newApp.getCalendarId()));
//				}
//			}
//			
//		} catch (Exception e) {
//			logger.warn("Error reloading Events: ", e);
//		}
		
		/* ================================================== */
	}

	/**
	 * Obtains all events of the calendars
	 */
	public void fetchEventsForAllCalendars() {
		long start = System.currentTimeMillis();
		/* ================================================== */
		if (this.eventHash == null)
			this.eventHash = Collections.synchronizedMap(new HashMap<NamedCalendar, List<Event>>());
		else
			this.eventHash.clear();

		if (calendarPanel.getCalendars() == null)
			return;

		for (final NamedCalendar nc : calendarPanel.getCalendars()) {
			/* ------------------------------------------------------- */
			// TODO JH Active Calendar only
//			if (nc.isActive() || nc.isSelected()) {
				eventHash.put(nc, fetchEventsForCalendar(nc));				
//			}
			/* ------------------------------------------------------- */
		}
		/* ------------------------------------------------------- */
		// eventDataList.setEnableNotify(false);
		updateEventsForActiveCalendars(true);
		/* ------------------------------------------------------- */
		// eventDataList.setEnableNotify(true);
		// dayModel.triggerUpdate();
		/* ================================================== */
		logger.info("Fetching Events For All Calendars [" + getFetchInterval() + "] took " + (System.currentTimeMillis()-start));
	}

	/**
	 * Updates the events for the given calendar
	 * 
	 * @param ac
	 */
	private void fetchEvents(AgendaCalendar ac) {
		/* ================================================== */
		long start = System.currentTimeMillis();
		// find the related NamedCalendar
		NamedCalendar namedCal = null;
		for (NamedCalendar nc : calendarHash.keySet()) {
			/* ------------------------------------------------------- */
			if (calendarHash.get(nc).equals(ac)) {
				namedCal = nc;
				break;
			}
			/* ------------------------------------------------------- */
		}
		if (namedCal == null)
			return;
		/* ------------------------------------------------------- */
		// remove old events
		List<Event> events = eventHash.get(namedCal);
		/* ------------------------------------------------------- */
		if (events != null) {
			// disable notification of observables
			// the notification will be done in addAll later
			eventDataList.setEnableNotify(false);
			/* ------------------------------------------------------- */
			for (Event e : events)
				eventDataList.remove(e);
			/* ------------------------------------------------------- */
			events.clear();
			// load new
			
			List<Event> evts = fetchEventsForCalendar(namedCal);
			
			events.addAll(evts);

			eventDataList.setEnableNotify(true);
			
			// if calendar ist not active or selected don't show his events
			if ((namedCal.isActive() || namedCal.isSelected())) {
				eventDataList.addAll(events);
			} 
		}
		/* ------------------------------------------------------- */
//		 eventDataList.trigger();
		/* ================================================== */
		logger.info("Fetching Events For Calendar: "+namedCal.getName()+" [" + getFetchInterval() + "] took " + (System.currentTimeMillis()-start));
	}

	/**
	 * Fetches the events for the given calendar
	 * 
	 * @param calendar
	 * @return
	 */
	private List<Event> fetchEventsForCalendar(NamedCalendar calendar) {
		/* ================================================== */
		List<Event> events = new ArrayList<Event>();

		Interval interval = getFetchInterval();

//		System.out.println("fetchEventsForCalendar: " + calendar.getId() + " " + calendar  + "  "+ dayFormatter.format(interval.getStart()) + " - " + dayFormatter.format(interval.getEnd()));
		
		events.addAll(calendar.getEvents((Date) interval.getStart(),(Date) interval.getEnd()));

		return events;
		/* ================================================== */
	}

	/**
	 * returns 1 month interval for current date
	 * 
	 * @return
	 */
	private Interval getFetchInterval() {
		/* ================================================== */
		// compute the date range.
		// we will fetch the events for 1 month, the current is in the middle
		// ===================================================
		// the start date
		Calendar selectedDate = new GregorianCalendar();
		selectedDate.setTime(calendarPanel.getDate());
		
		// store the current month
		Calendar cStart = new GregorianCalendar();
		cStart.setTime(selectedDate.getTime());
		cStart.set(Calendar.DAY_OF_MONTH, 1);
		cStart.add(Calendar.DAY_OF_YEAR, -7);
		
		/* ------------------------------------------------------- */
		// the end date
		Calendar cEnd = new GregorianCalendar();
		cEnd.setTime(selectedDate.getTime());
		cEnd.set(Calendar.DAY_OF_MONTH, 31);
		cEnd.add(Calendar.DAY_OF_YEAR, 7);
		
		Interval in = new Interval(cStart.getTime(), cEnd.getTime());

		return in;
		/* ================================================== */
	}

	@SuppressWarnings("unchecked")
	private synchronized void updateEventsForActiveCalendars(boolean forceUpdate) {
		
		logger.log(LOGLEVEL, "updateEventsForActiveCalendars Forceupdate: " + forceUpdate);
		/* ================================================== */
		// add all events from active calendars
		List<Event> allActiveEvents = new ArrayList<Event>();

		boolean update = false;

		if (forceUpdate) {
			update = true;
		} else {
			for (NamedCalendar nc : calendarPanel.getCalendars()) {
				if (!displayingCalendars.contains(nc)
						&& (nc.isActive() || nc.isSelected())) {
					update = true;
					break;
				} else if (displayingCalendars.contains(nc)
						&& (!nc.isActive() && !nc.isSelected())) {
					update = true;
					break;
				}
			}
		}

		if (!update) {
			logger.log(LOGLEVEL, "updateEventsForActiveCalendars: No Update Needed");
			return;
		}

		displayingCalendars.clear();
		// find already displaying events
		for (NamedCalendar nc : calendarPanel.getCalendars()) {
			if ((nc.isActive() || nc.isSelected()) && eventHash.get(nc) != null) {
				allActiveEvents.addAll(eventHash.get(nc));
				displayingCalendars.add(nc);
			}
		}

		Collections.sort(allActiveEvents);
		eventDataList.setEnableNotify(false);
		eventDataList.clear();
		eventDataList.addAll(allActiveEvents);

		eventDataList.setEnableNotify(true);
		eventDataList.addAll(fetchNationalHolidays());
		/* ================================================== */
	}

	/**
	 * Fetches the stored national holidays
	 * 
	 * @return
	 */
	private List<Event> fetchNationalHolidays() {

		if (nationalHolidays == null) {
			try {
				logger.log(LOGLEVEL, "fetchNationalHolidays ");
				/* ================================================== */
				
				NationalHoliday[] holidays = (NationalHoliday[]) GECAMedLists
						.getArray(NationalHoliday.class);
				
				Event ev;
				nationalHolidays = new ArrayList<Event>();
				
				for (int i = 0; i < holidays.length; i++) {
					ev = new Event();
					
					Date start = DateUtil.move2Morning(holidays[i].getDate());
					ev.setStart(start);
					ev.setEnd(DateUtil.move2Midnight(start));
					ev.setSummary(holidays[i].getName());
					ev.setDescription(holidays[i].getName());
					ev.setBackground(true);
					ev.setEditable(false);
					ev.setIcon(NATIONAL_HOLIDAY_ICON);
					nationalHolidays.add(ev);
				}
			} catch (Exception e) {
				logger.warn("Error fetching national Holidays", e);
			}
		}

		return nationalHolidays;
		/* ================================================== */
	}

	/**
	 * @param oldEvent
	 *            event to remove
	 * @param newEventList
	 *            event to add
	 */
	@SuppressWarnings("unchecked")
	public void updateEvent(Event oldEvent, List<Event> newEventList) {
		logger.log(LOGLEVEL, "updateEvent "+ oldEvent);
		/* ================================================== */
		// if the oldEvent has been stored
		if (oldEvent != null && oldEvent.getId() != null) {
			/* ------------------------------------------------------- */
			AgendaCalendar ac = getCalendarForId(((Appointment) oldEvent
					.getId()).getCalendarId());
			// find named calendar for agendacalendar
			/* ------------------------------------------------------- */
			ArrayList<Event> oldEvents = (ArrayList<Event>) eventHash
					.get(findNamedCalendarForAgendaCalendar(ac));
			if (oldEvents != null) {
				/* ------------------------------------------------------- */
				// find recurring events
				List<Event> recOldEv = new ArrayList<Event>();
				for (Event oe : oldEvents) {
					/* ------------------------------------------------------- */
					if (oe.getId() != null
							&& oe.getId().equals(oldEvent.getId()))
						recOldEv.add(oe);
					/* ------------------------------------------------------- */
				}
				oldEvents.removeAll(recOldEv);
				// remove old event from old calendar's events
				// oldEvents.remove(oldEvent);
				// recOldEv.add(oldEvent);
				eventDataList.remove(oldEvent);
				/* ------------------------------------------------------- */
				eventDataList.removeAll(recOldEv);
			}
			/* ------------------------------------------------------- */
		}
		// add new event to new calendar hash
		if (newEventList != null && newEventList.size() > 0) {
			/* ------------------------------------------------------- */
			AgendaCalendar acNew = getCalendarForId(((Appointment) newEventList
					.get(0).getId()).getCalendarId());
			/* ------------------------------------------------------- */
			ArrayList<Event> hashedEvents = (ArrayList<Event>) eventHash
					.get(findNamedCalendarForAgendaCalendar(acNew));
			/* ------------------------------------------------------- */
			if (hashedEvents != null) {
				hashedEvents.addAll(newEventList);
				/* ------------------------------------------------------- */
				eventDataList.addAll(newEventList);
				/* ------------------------------------------------------- */
			}
		}
		Collections.sort(eventDataList);
		// eventDataList.trigger();
		/* ================================================== */
	}

	private void updateEventCalendarData(NamedCalendar cal) {
		logger.log(LOGLEVEL, "updateEventCalendarData "+ cal);
		/* ================================================== */
		List<Event> events = eventHash.get(cal);
		// List<Event> changedEvents = new ArrayList<Event>();

		for (Event e : events) {
			e.setColor(cal.getColor());
			e.set(NamedCalendar.CALENDAR_NAME, cal.getName());
			// set the calendar id of the event
			e.set(Event.CALENDAR_ID, cal.getId());
			// set Calendar isBackground to Event
			e.set(Event.CALENDAR_IS_BACKGROUND, cal.isBackground());
		}
		eventDataList.setEnableNotify(true);
		eventDataList.trigger();
		/* ================================================== */
	}

	// ######################################################################################
	// ######################################################################################
	// Calendar interaction part. Popup, delete, modify create etc....
	//
	// **************************************************************************************

	/**
	 * Updates the appropriat calendar
	 * 
	 * @param type
	 * @param calendarId
	 */
	private void updateCalendar(Integer type, Integer calendarId, Date changedDate) {
		logger.log(LOGLEVEL, "updateCalendar "+ calendarId);
		/* ================================================== */
		if (calendarId == null || type == null)
			return;
		/* ------------------------------------------------------- */
		if (AppointmentManager.MSG_UPDATE_CALENDAR_EVENTS.equals(type)) {
			/* ------------------------------------------------------- */
			AgendaCalendar ac = getCalendarForId(calendarId, false);
			
			// agenda is not loaded -> skip update
			if (ac == null)
				return;
			
			// changed date is not in displayed timeframe -> skip update
			if (changedDate != null) {
				Interval interval = getFetchInterval();
				if (changedDate.before((Date) interval.getStart()) || changedDate.after((Date) interval.getEnd())) {
					
					return;
				}
			}

			/* ------------------------------------------------------- */
			fetchEvents(ac); 
			/* ------------------------------------------------------- */
		}
		if (AppointmentManager.MSG_UPDATE_CALENDAR.equals(type)) {
			/* ------------------------------------------------------- */
			// remove the "old" object
			AgendaCalendar ac = getCalendarForId(calendarId, false);
			removeCalendarStructure(ac);
			// get the calendar object
			try {
				/* --------------------------------------------- */
				AppointmentManager apManager = (AppointmentManager) ManagerFactory
						.getRemote(AppointmentManagerBean.class);
				/* ------------------------------------------------------- */
				ac = apManager.getCalendar(calendarId);
				if (ac == null)
					return;
				/* ------------------------------------------------------- */
				updateCalendarStructure(ac, true);
				selectCalendar(findNamedCalendarForAgendaCalendar(ac).getId());
				/* --------------------------------------------- */
			} catch (Exception e) {
				/* --------------------------------------------- */
				e.printStackTrace();
				/* --------------------------------------------- */
			}
			/* ------------------------------------------------------- */
		}
		if (AppointmentManager.MSG_ADDED_CALENDAR.equals(type)) {
			/* ------------------------------------------------------- */
			// check if the calendar is present in this instance
			AgendaCalendar ac = getCalendarForId(calendarId, false);
			if (ac != null)
				return;
			/* ------------------------------------------------------- */
			// get the calendar object
			AppointmentManager apManager = (AppointmentManager) ManagerFactory
					.getRemote(AppointmentManagerBean.class);
			/* ------------------------------------------------------- */
			ac = apManager.getCalendar(calendarId);
			if (ac == null)
				return;
			/* ------------------------------------------------------- */
			updateCalendarStructure(ac);
			/* ------------------------------------------------------- */
		}
		if (AppointmentManager.MSG_REMOVED_CALENDAR.equals(type)) {
			/* ------------------------------------------------------- */
			// check if the calendar is present in this instance
			AgendaCalendar ac = getCalendarForId(calendarId, false);
			if (ac == null)
				return;
			/* ------------------------------------------------------- */
			removeCalendarStructure(ac);
			/* ------------------------------------------------------- */
		}
		/* ================================================== */
	}

	/**
	 * Creates a JMS message with the param calender and msgType to send to all clients and updates the local
	 * structur.
	 * 
	 * @param calendar the calendar which is added or updated
	 * @param msgType the type of the message
	 */
	private void informCalendarChanges(AgendaCalendar calendar, Integer msgType) {
		logger.log(LOGLEVEL, "informCalendarChanges "+ calendar);
		try {
			/* ------------------------------------------------------- */
			AppointmentManager apManager = (AppointmentManager) ManagerFactory
					.getRemote(AppointmentManagerBean.class);
			/* ------------------------------------------------------- */
			apManager.sendCalendarUpdateMessage(MainFrame.getClientId(), msgType, calendar.getId(), null);
		} catch (JMSException e) {
			e.printStackTrace();
		}
		updateCalendarStructure(calendar);
	}

	/**
	 * Adds the new AgendaCalendar to the internal data set creates a new
	 * DefaultNamedCalendar, puts the calendar to the navibar and loads the
	 * events
	 * 
	 * @param agSaved
	 */
	private void updateCalendarStructure(AgendaCalendar agSaved) {
		logger.log(LOGLEVEL, "updateCalendarStructure "+ agSaved);
		/* ================================================== */
		updateCalendarStructure(agSaved, false);
		/* ================================================== */
	}

	/**
	 * Deprecated: use the updateCalendarStructure (AgendaCalendar)
	 * Adds the new AgendaCalendar to the internal data set creates a new
	 * DefaultNamedCalendar, puts the calendar to the navibar and loads the
	 * events
	 * 
	 * @param agSaved The calendar to update
	 * @param override removes and recreates the calendar
	 */
	@Deprecated
	private void updateCalendarStructure(AgendaCalendar agSaved,
			boolean override) {
		/* ================================================== */
		logger.log(LOGLEVEL, "updateCalendarStructure "+ agSaved + " overwrite " + override);
		if (override)
			calendarHash.values().remove(agSaved);

		if (!calendarHash.values().contains(agSaved)) {
			// add
			DefaultNamedCalendar dnc = new DefaultNamedCalendar(agSaved
					.getTitle(), agSaved, (Locale) agendaAdminSettingsPlugin
					.getValue(AgendaAdminSettingsPlugin.CALENDAR_LOCALE));
			if (agSaved.getColor() != null)
				dnc.setColor(new Color(agSaved.getColor()));
			calendarPanel.addNamedCalendar(dnc);
			/* ------------------------------------------------------- */
			calendarHash.put(dnc, agSaved);
			/* ------------------------------------------------------- */
			List<AgendaCalendar> calList = GECAMedLists.getListReference(AgendaCalendar.class);
			calList.remove(agSaved);
			calList.add(agSaved);
			GECAMedLists.notifyListeners(AgendaCalendar.class);
		}
		fetchEventsForAllCalendars();
		// refresh button panel
		calendarPanel.triggerUpdate();
		/* ================================================== */
	}

	/**
	 * @param ac
	 */
	private void removeCalendarStructure(AgendaCalendar ac) {
		logger.log(LOGLEVEL, "removeCalendarStructure "+ ac);
		/* ================================================== */
		// find namedCalendar
		NamedCalendar nc = findNamedCalendarForAgendaCalendar(ac);

		removeCalendarStructure(nc);
		/* ================================================== */
	}

	/**
	 * Removes the given calendar from the internal structure. If there is no
	 * calendar after removing, a default will be created
	 * 
	 * @param calendar
	 */
	private void removeCalendarStructure(NamedCalendar calendar) {
		logger.log(LOGLEVEL, "removeCalendarStructure "+ calendar);
		/* ================================================== */
		if (calendar == null)
			return;
		// remove from panel
		calendarPanel.removeNamedCalendar(calendar);
		/* ------------------------------------------------------- */
		// remove Events
		List<Event> removeList = new ArrayList<Event>(0);
		// find the events matching the calendar
		for (Event e : eventDataList) {
			if (e.getId() != null
					&& ((Appointment) e.getId()).getCalendarId().equals(calendar.getId()))
				removeList.add(e);
		}
		/* ------------------------------------------------------- */
		// remove
		/* ------------------------------------------------------- */
		eventDataList.removeAll(removeList);
		AgendaCalendar aCalendar	= calendarHash.remove(calendar);
		if (aCalendar != null && GECAMedLists.getListReference(AgendaCalendar.class).remove(aCalendar))
			GECAMedLists.notifyListeners(AgendaCalendar.class);
		/* ------------------------------------------------------- */
		// create at least one calendar
		/* ------------------------------------------------------- */
		if (calendarHash.keySet().size() < 1)
			createDefaultCalendar();
		/* ================================================== */
	}

	/**
	 * @param ac
	 * @return
	 */
	private NamedCalendar findNamedCalendarForAgendaCalendar(AgendaCalendar ac) {
		logger.log(LOGLEVEL, "findNamedCalendarForAgendaCalendar "+ ac);
		/* ================================================== */
		NamedCalendar oldCalendar = null;
		for (NamedCalendar nc : calendarHash.keySet()) {
			if (calendarHash.get(nc).equals(ac)) {
				oldCalendar = nc;
				break;
			}
		}
		return oldCalendar;
		/* ================================================== */
	}

	/**
	 * Sets the current selected calendar
	 * 
	 * @param id
	 *            of NamedCalendar
	 */
	public void selectCalendar(Integer id) {
		/* ================================================== */
		logger.log(LOGLEVEL, "selectCalendar "+ id);
		// try to find the calendar by its id
		if (calendarPanel.getCalendars() == null)
			return;
		
		// deselect all calendars, except the current selected calendar of the event
		calendarPanel.setSelectedCalendar(id);
		/* ================================================== */
	}

	// ============================================================
	// CalendarListener methods.
	// ============================================================
	public void activeCalendarsChanged(Collection<NamedCalendar> calendars) {
		logger.log(LOGLEVEL, "activeCalendarsChanged " + calendars);
		/* ====================================================== */
		// if no calendar is active, remove all events
		/* ================================================== */
		if (calendars == null || calendars.size() < 1) {
			eventDataList.clear();
			return;
		}
		/* ------------------------------------------------------- */
		
		// TODO enable saving active Calendars (Moved to shutdown Hook)
//		storeCheckedCalendars(calendars);
		
		
		/* ================================================== */
		// fetch the appointments of the active calendars
		/* ================================================== */
		updateEventsForActiveCalendars(false);
		/* ====================================================== */
	}

	public void selectedCalendarChanged(NamedCalendar selectedCalendar) {
		/* ====================================================== */
		logger.log(LOGLEVEL, "selectedCalendarChanged " + selectedCalendar);
		updateEventsForActiveCalendars(false);
		/* ====================================================== */
	}

	// ============================================================
	// DateListener method.
	// is called whenever the date has been changed by clicking in
	// the date chooser.
	// ============================================================
	public void dateChanged(Date date) {
		/* ====================================================== */
		// TODO fetch only if the date is near the end of a date range
		// check if the new date equals the current month.
		
		logger.info("Date Changed to: " + dayFormatter.format(date));
		dateLabel.setText(GECAMedGuiUtils.getDateFormat(false).format(date));
		
		Calendar cal = new GregorianCalendar();
		cal.setTime(date);
		if (cal.get(Calendar.MONTH) == this.currentMonth)
			return;
		
		fetchEventsForAllCalendars();
		this.currentMonth = cal.get(Calendar.MONTH);
		/* ====================================================== */
	}


	/**
	 * @param calendars
	 */
	private void storeCheckedCalendars(Collection<NamedCalendar> calendars) {
		/* ====================================================== */
		try {
			/* ------------------------------------------------------- */
			AppointmentManager apManager = (AppointmentManager) ManagerFactory
					.getRemote(AppointmentManagerBean.class);
			/* ------------------------------------------------------- */
			for (NamedCalendar cal : calendars) {
				if (cal.isActive()) {
					apManager.addUserCalendarSelection(calendarHash.get(cal));
				} else {
					apManager.deleteUserCalendarSelection(calendarHash.get(cal));
				}
			}
			/* ------------------------------------------------------- */
		} catch (Exception e) {
			logger.error("Error while storing checked calendars for user", e);
		}
		/* ====================================================== */
	}

	/**
	 * @return
	 */
	public Collection<AgendaCalendar> getCheckedCalendars() {
		/* ====================================================== */
//		System.out.println("CALLED: AgendaModule.getCheckedCalendars()");
		try {
			/* ------------------------------------------------------- */
			AppointmentManager apManager = (AppointmentManager) ManagerFactory
					.getRemote(AppointmentManagerBean.class);
			Collection<AgendaCalendar> allCalendars;
			/* ------------------------------------------------------- */
			Collection<AgendaCalendar> calendars = apManager.getCalendarSelectionsByUser(GECAMedModule
					.getCurrentUser().getId());
			
			if (calendarHash == null)
				allCalendars = GECAMedLists.getListReference(AgendaCalendar.class);
			else
				allCalendars = calendarHash.values();
			
			for (AgendaCalendar calendar : allCalendars)
			{
				if (calendar.isBackground())
					calendars.add(calendar);
			}
			
			return calendars;
			/* ------------------------------------------------------- */
		} catch (Exception e) {
			logger.error("Error while loading checked calendars for user", e);
		}
		return null;
		/* ====================================================== */
	}
	
	
	/**
	 * @return The currently selected (not necessarily checked) AgendaCalendar 
	 * or <code>null</code> if none is selected. 
	 */
	public AgendaCalendar getSelectedCalendar ()
	{
		NamedCalendar nCal = calendarPanel.getSelectedCalendar();
		
		if (nCal == null || nCal.getId() == null)
			return null;
		
		return getCalendarForId(nCal.getId());
	}

	/**
	 * 
	 * CalendarListener for all the interactions that are made on the panel
	 * 
	 * @author martin.heinemann@tudor.lu 23.05.2007 10:06:22
	 * 
	 * 
	 * @version <br>
	 *          $Log: AgendaModule.java,v $
	 *          Revision 1.154  2014-02-21 08:45:10  ferring
	 *          Search also for selected, not only for checked calendars
	 *
	 *          Revision 1.153  2014-02-19 10:03:42  ferring
	 *          Time period for list view not taken at GECAMed Startup
	 *
	 *          Revision 1.152  2014-02-13 16:55:58  ferring
	 *          NewCalendar bug fixed (ticket #1294)
	 *
	 *          Revision 1.151  2013-12-27 18:09:25  donak
	 *          Cleanup of imports
	 *
	 *          Revision 1.150  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>
	 *
	 *          Revision 1.149  2013-07-15 06:18:36  ferring
	 *          logging changed
	 *
	 *          Revision 1.148  2013-07-10 16:41:09  troth
	 *          Fix ticket #1108.
	 *
	 *          Revision 1.147  2013-02-22 08:46:50  kutscheid
	 *          remove the tupel classes (please redeploy)
	 *
	 *          Revision 1.146  2013-02-19 12:07:34  ferring
	 *          GECAMedLists changed. Will now automatically load list of all beans
	 *
	 *          Revision 1.145  2013-02-06 15:25:02  troth
	 *          Fix ticket 1146.
	 *          Add the correct messages for add and update a calendar in function informCalendarChanges.
	 *
	 *          Revision 1.144  2013-01-22 14:21:29  ferring
	 *          iReport templates will now be compiled only once until the server is stopped
	 *
	 *          Revision 1.143  2012-08-09 14:18:49  troth
	 *          Ticket #1021 - Unpredictable NAF results and long search delai when no time slot left.
	 *
	 *          Revision 1.142  2012-07-27 15:41:33  troth
	 *          *** empty log message ***
	 *
	 *          Revision 1.140  2012-07-23 15:41:24  troth
	 *          Ticket #873 Point 6 and 7 fixed.
	 *
	 *          Revision 1.139  2012-07-19 15:10:07  troth
	 *          Ticket #873 Point 5, 8, 9 and 10 fixed.
	 *
	 *          Revision 1.138  2012-07-17 14:36:01  troth
	 *          Ticket #873 - Constraints are now static and the dialog is redesigned, add a today and 6 week button.
	 *
	 *          Revision 1.137  2012-07-16 13:24:06  troth
	 *          Init the FreeAppointmentFinderDialog every time before it will be shown to set the time constraints right, because may be they have changed (Physicians office time).
	 *
	 *          Revision 1.136  2012-07-13 15:54:26  troth
	 *          Label the time conditions with the start an end time. (Morning | 08:00 - 10:00)
	 *
	 *          Revision 1.135  2012-07-09 15:51:17  troth
	 *          To mark the moving appointment when they positioned with the NewAppointmentFinder we have moved the flag Event.EVENT_PROPOSAL_STATE in the Event class.
	 *
	 *          Revision 1.134  2012-06-14 16:37:24  troth
	 *          Fix Ticket #959 - Changing physician after copy-paste does strange things.
	 *
	 *          Revision 1.133  2012-06-12 15:43:51  troth
	 *          Fix Ticket #957 - Display inconsistencies when changing the agenda of an entry.
	 *
	 *          Revision 1.132  2012-06-12 14:12:02  troth
	 *          Add focus to password dialog which is when deleting a calendar with entries.
	 *
	 *          Revision 1.131  2012-06-11 16:12:10  troth
	 *          fix Ticket #991 - Visuelle �berbleibsel von Kalender-Eintr�gen nach L�schen eines Kalenders.
	 *
	 *          Revision 1.130  2012-05-15 14:09:59  troth
	 *          Implement Ticket #972.
	 *
	 *          Revision 1.129  2012-05-15 09:57:32  troth
	 *          1. Add new agenda log-messages (admin panel) for calendar modifications.
	 *
	 *          Revision 1.128  2012-04-24 13:58:13  troth
	 *          Better selection of the Calendar when click on a agenda entry | Fix Bug: Sometimes if a agenda entry has been selected the calendar of the entry was not selected. Now: The Calendar will be selected if a entry of the calendar is selected.
	 *
	 *          Revision 1.127  2012-04-24 08:55:02  troth
	 *          1. Fix Ticket #972 - Bordered select Calendar.
	 *          2. Better selection of the Calendar when click on a agenda entry (test version).
	 *
	 *          Revision 1.126  2012-01-24 13:18:41  troth
	 *          1. Translations of agenda buttonstitle and tooltips.
	 *
	 *          Revision 1.125  2012-01-23 16:05:00  troth
	 *          Add the old view layout of agenda, now the user can switch between the two layouts old (staircase display) and new (column display).
	 *          Bug fix in both layouts of the views. Separate the (1)holiday-, (2)office-, (3)background- and (4)normal events in different layers for the order of drawing ((1) - (4) the order of drawing).
	 *
	 *          Revision 1.124  2012-01-18 16:31:25  troth
	 *          Test: add the old view layout of agenda, now the user can switch between the two layouts old and new.
	 *
	 *          Revision 1.123  2011-11-30 08:21:01  ferring
	 *          NullpointerException caught
	 *
	 *          Revision 1.122  2011-11-16 16:01:27  troth
	 *          fix a warning
	 *
	 *          Revision 1.121  2011-10-24 14:16:17  troth
	 *          Code Cleanup
	 *
	 *          Revision 1.120  2011-10-20 15:04:28  troth
	 *          1. add new functions of ticket #879
	 *          2. fix ticket #904
	 *          3. new bizcal lib
	 *
	 *          Revision 1.119  2011-10-05 10:57:43  troth
	 *          Ticket #894
	 *          add: Log message string formatting
	 *
	 *          Revision 1.118  2011-10-04 12:13:32  troth
	 *          fix Ticket #892 - Patient matricule and treatment type automatically added to agenda entry description
	 *
	 *          Revision 1.117  2011-09-28 11:28:18  troth
	 *          Second Version of function 'logging Agenda modifications in the admin log' Ticket #894 Logging for Agenda modifications
	 * Revision 1.116 2011-09-22 15:28:52
	 *          troth Fist Version of function 'logging Agenda modifications in
	 *          the admin log' Ticket #894 Logging for Agenda modifications
	 * 
	 *          Revision 1.115 2011-09-22 13:29:50 hermen - changed
	 *          transparencies in appointmentlist renderer - fixed new column
	 *          problem im appointmentfinder
	 * 
	 *          Revision 1.114 2011-09-14 12:20:34 troth Add the new function
	 *          for printing a appointment overview for the physician.
	 * 
	 *          Revision 1.113 2011-08-03 14:02:37 troth code clearup
	 * 
	 *          Revision 1.112 2011-08-02 15:57:47 troth Fix ticket #871
	 * 
	 *          Revision 1.111 2011-07-20 13:49:51 troth fixed Ticket #614 ,
	 *          #635 and new Bizcal lib.
	 * 
	 *          Revision 1.110 2011-07-15 15:12:57 troth fixed Ticket #416 and
	 *          new Bizcal lib.
	 * 
	 *          Revision 1.109 2011-06-16 11:58:22 troth Remove some
	 *          'System.out.println'
	 * 
	 *          Revision 1.108 2011-05-31 10:41:56 troth fix Bug #850 and #861
	 * 
	 *          Revision 1.107 2011-05-18 13:06:24 troth Fix ticket #837:
	 *          Recurring calendar entry gets a date change after resizing
	 * 
	 *          Revision 1.106 2011-04-05 08:47:46 troth 1. Add new icon for the
	 *          button 'create new appointment' 2. Add some translations 3. Fix
	 *          some warnings
	 * 
	 *          Revision 1.105 2011-04-04 11:38:31 troth Redesign of the
	 *          appointment create dialog and the right navi bar.
	 * 
	 *          Revision 1.104 2011-02-18 14:25:56 troth - add some Javadoc -
	 *          bug fix - sometimes the DayView was not init when open the
	 *          agenda
	 * 
	 *          Revision 1.103 2011-02-16 10:47:41 troth check in new bizcal jar
	 *          and add the new bizcal view layout to the agenda
	 * 
	 *          Revision 1.102 2011-02-10 15:09:25 troth Add a new view to the
	 *          calendar of the agenda the 'Three Day View' which shows three
	 *          days per interval.
	 * 
	 *          Revision 1.101 2011-02-09 13:41:30 troth Some changes in GUI
	 *          (right navigation bar / head navigation bar).
	 * 
	 *          Revision 1.100 2010-10-08 05:57:43 ferring NullpointerException
	 *          at startup fixed
	 * 
	 *          Revision 1.99 2010-04-27 14:36:37 troth GECAMedOptionPane create
	 *          now only a simple JOptionPane. May be later we build our own
	 *          optionpane.
	 * 
	 *          Revision 1.98 2010-03-19 12:01:06 hermen improved and unified
	 *          iconfetching
	 * 
	 *          Revision 1.97 2010-03-17 16:24:17 hermen fixed bug 444 and
	 *          others concerning appointments not showing up in the views of
	 *          the agenda
	 * 
	 *          Revision 1.96 2009-12-15 11:06:24 hermen fixed NPE on add
	 *          Calendar
	 * 
	 *          Revision 1.95 2009-12-01 16:22:34 mack Changes required by the
	 *          introduction of locale parameter in DefaultNamedCalendar
	 * 
	 *          Revision 1.94 2009-07-02 13:09:14 hermen *** empty log message
	 *          ***
	 * 
	 *          Revision 1.93 2009-05-15 13:21:17 heinemann *** empty log
	 *          message ***
	 * 
	 *          Revision 1.92 2009-05-13 12:57:31 heinemann *** empty log
	 *          message ***
	 * 
	 *          Revision 1.91 2009-05-12 11:51:43 heinemann *** empty log
	 *          message ***
	 * 
	 *          Revision 1.90 2009-05-11 16:53:41 heinemann slider position of
	 *          the zoom in the agenda is stored in the user settings
	 * 
	 *          Revision 1.89 2009-04-03 13:22:05 heinemann fix for: Ticket #266
	 *          (new enhancement)
	 * 
	 *          If Color of a physician is changed, it will not change the color
	 *          of his Calendar
	 * 
	 *          Revision 1.88 2008-10-21 15:12:33 heinemann *** empty log
	 *          message ***
	 * 
	 *          Revision 1.87 2008-10-20 11:42:47 heinemann *** empty log
	 *          message ***
	 * 
	 *          Revision 1.86 2008-10-09 12:35:37 heinemann
	 *          http://santec.tudor.lu/trac/gecamed/ticket/193 show patient name
	 *          in the header of an appointment and the description in the body
	 * 
	 *          Revision 1.85 2008-09-30 14:53:48 heinemann *** empty log
	 *          message ***
	 * 
	 *          Revision 1.84 2008-09-25 09:42:27 heinemann fixed copyrights
	 * 
	 *          Revision 1.83 2008-09-10 15:22:28 heinemann changed hotkeys to
	 *          F1,F2 and F4
	 * 
	 *          Revision 1.82 2008-07-04 13:38:58 heinemann fixed generic
	 *          casting that the new eclipse does not want to accept.
	 * 
	 *          Revision 1.81 2008-05-29 12:43:39 heinemann fixed recurrence bug
	 *          for appointments that recurr per week. The days in the current
	 *          week are now also treated.
	 * 
	 *          Revision 1.80 2008-05-29 08:10:10 heinemann *** empty log
	 *          message ***
	 * 
	 *          Revision 1.79 2008-05-27 14:13:41 heinemann *** empty log
	 *          message ***
	 * 
	 *          Revision 1.78 2008-05-26 12:45:32 heinemann Removed debugging
	 * 
	 *          Revision 1.76 2008-04-14 13:11:36 heinemann *** empty log
	 *          message ***
	 * 
	 *          Revision 1.75 2008-04-09 09:39:43 heinemann *** empty log
	 *          message ***
	 * 
	 *          Revision 1.74 2008-04-08 09:52:33 heinemann moved creation of
	 *          new calendar from OfficeBean to AgendaModule
	 * 
	 *          Revision 1.73 2008-03-28 08:51:34 heinemann *** empty log
	 *          message ***
	 * 
	 *          Revision 1.72 2008-03-21 08:17:24 heinemann *** empty log
	 *          message ***
	 * 
	 *          Revision 1.71 2008-03-21 08:16:46 heinemann *** empty log
	 *          message ***
	 * 
	 *          Revision 1.70 2008-02-27 08:21:53 heinemann added initModule
	 *          call
	 * 
	 *          Revision 1.69 2008-01-22 12:53:46 heinemann fixed nullpointer if
	 *          a calendar has a null value in the color property
	 * 
	 *          Revision 1.68 2008-01-18 16:09:05 heinemann code cleanup and
	 *          java doc
	 * 
	 *          Revision 1.67 2007-11-20 08:58:54 hermen moved Managerfactory to
	 *          core.utils and refactured code to use ManagerFactory instead of
	 *          context.lookup
	 * 
	 *          Revision 1.66 2007-11-05 10:21:05 heinemann *** empty log
	 *          message ***
	 * 
	 *          ...........
	 * 
	 *          Revision 1.3 2007/05/25 13:50:25 heinemann pres-weekend checkin
	 * 
	 * 
	 */
	class AgendaCalendarListener implements CalendarListener {

		/**
		 * 
		 */
		public AgendaCalendarListener() {
			/* ================================================== */
			/* ================================================== */
		}

		/**
		 * @param event
		 */
		public void deleteEvent(Event event) throws Exception {
			/* ================================================== */
			deleteEvents(Collections.nCopies(1, event));
			/* ================================================== */
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see bizcal.swing.CalendarListener#deleteEvents(java.util.List)
		 */
		public void deleteEvents(List<Event> events) {
			long start = System.currentTimeMillis();
			/* ====================================================== */
			if (events == null)
				return;
			/* ------------------------------------------------------- */
			NamedCalendar nc = calendarPanel.getSelectedCalendar();
			if (nc == null)
				return;
			eventDataList.setEnableNotify(false);
			for (Event event : events) {
				/* ------------------------------------------------------- */
				nc.deleteEvent(MainFrame.getClientId(), event);
				// don't ask, it works =)
				updateEvent(event, null);
				// updateEvent(event, null);
				/* ------------------------------------------------------- */
			}
			// Log the user actions in agenda
			AgendaModule.logUserActionAgenda(((Appointment)events.get(0).getId()), AgendaModule.DELETE_APPOINTMENT, System.currentTimeMillis()-start);
			
			eventDataList.setEnableNotify(true);
			eventDataList.trigger();
			/* ====================================================== */
		}

		public void closeCalendar(Object calId) throws Exception {
		}

		public void copy(List<Event> list) throws Exception {
			/* ------------------------------------------------------- */
			// Collections.sort(list);
			clipBoard = new HashSet<Event>(list);
			/* ------------------------------------------------------- */
		}

		public void dateChanged(Date date) throws Exception {}

		public void dateSelected(Date date) throws Exception {
			/* ================================================== */
			if (calendarPanel.getCurrentView() instanceof MonthViewPanel) {
				/* ------------------------------------------------------- */
				// select the day view for the selected date
				// AgendaModule.this.dateChanged(date);
				calendarPanel.setDate(date);
				// dayViewPanel.dateChanged(date);
				calendarPanel.showView(DayViewPanel.VIEW_NAME_DAY);
				/* ------------------------------------------------------- */
			}
			/* ================================================== */
		}

		public void eventsSelected(List<Event> list) throws Exception {
			AgendaModule.this.selectedEvents = list;
		}

		public void newCalendar() throws Exception {
		}

		public void selectionReset() throws Exception {
		}

		public void showEvent(Object id, Event event) throws Exception {
		}

		public void eventSelected(Object id, Event event) throws Exception {
			/* ====================================================== */
			if (event.getId() == null)
				return;
			
			// select the calendar of this event
			Appointment ap = (Appointment) event.getId();
			selectCalendar(ap.getCalendarId());
			/* ====================================================== */
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see bizcal.swing.CalendarListener#moved(bizcal.common.Event,
		 * java.lang.Object, java.util.Date, java.lang.Object, java.util.Date)
		 */
		public void moved(Event event, Object orgCalId, Date orgDate,
				Object newCalId, Date newDate) throws Exception {
			/* ====================================================== */
			Event workingEvent = event;
			// if the event is part of a reccurrence we must
			// get the event that matches the date of the Appointment object
			// and compute the date shiffting and add it to the original
			// date in order to adjust all events that depends on this
			// recurrence.
			if (event.getId() instanceof Appointment) {
				/* ------------------------------------------------------- */
				Appointment app = (Appointment) event.getId();
				if (Appointment.NO_RECUR < app.getFrequency()) {
					/* ------------------------------------------------------- */
					// compute the shift
					long shift = DateUtil.getDiffDay(event.getStart(), newDate);

					if (app.getStartDate().equals(event.getStart())
							&& app.getEndDate().equals(event.getEnd())) {
						// this is the orginal event. Just move!
						event.move(newDate);
					} else {
						/*
						 * ------------------------------------------------------
						 * -
						 */
						// find the first event
						List<Event> events = eventHash.get(calendarPanel
								.getSelectedCalendar());
						if (events != null)
							for (Event e : events) {
								// if the event has the same Appointment object
								if (event.getId().equals(e.getId())) {
									// if the dates are equal
									if (app.getStartDate().equals(e.getStart())
											&& app.getEndDate().equals(
													e.getEnd())) {
										/*
										 * --------------------------------------
										 * -----------------
										 */
										// this is the first event, shift it
										e.move(new Date(e.getStart().getTime()
												+ shift));
										workingEvent = e;
										break;
										/*
										 * --------------------------------------
										 * -----------------
										 */
									}
								}
							}
						/*
						 * ------------------------------------------------------
						 * -
						 */
					}
					/* ------------------------------------------------------- */
					// shift the until field too
					if (app.getUntil() != null) {
						app
								.setUntil(new Date(app.getUntil().getTime()
										+ shift));
					}
					/* ------------------------------------------------------- */
				} else
					event.move(newDate);
				/* ------------------------------------------------------- */
			} else
				event.move(newDate);
			NamedCalendar nc = calendarPanel.getSelectedCalendar();
			/* ------------------------------------------------------- */
			if (nc == null)
				return;
			/* ------------------------------------------------------- */
			// if the event has the property for not saving it, we must respect
			// this =)
			if (workingEvent.get(Event.EVENT_PROPOSAL_STATE) != null
					&& (Boolean) workingEvent.get(Event.EVENT_PROPOSAL_STATE) == true) {
				// just update
				Appointment app = ((Appointment) workingEvent.getId()).copy();
				app.setStartDate(workingEvent.getStart());
				app.setEndDate(workingEvent.getEnd());

				workingEvent.setId(app);

				updateEvent(workingEvent, Collections.nCopies(1, workingEvent));
				// disable the automatic movement of the appointment if it overlays other appointments after dragging 
				freeAppointmentFindDialog
						.fadeToAppointment((Appointment) workingEvent.getId());
				freeAppointmentFindDialog.setAppointmentToView((Appointment) workingEvent.getId());
			} else {
				/* ------------------------------------------------------- */
				// normal behaviour
				List<Event> newEvent = nc.saveEvent(MainFrame.getClientId(),
						workingEvent, false);
				if (newEvent != null)
					updateEvent(workingEvent, newEvent);
				/* ------------------------------------------------------- */
			}
			/* ====================================================== */
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see bizcal.swing.CalendarListener#newEvent(java.lang.Object,
		 * java.util.Date) Is call when appointment is create by double click.
		 */
		public void newEvent(Object id, Date date) throws Exception {
			/* ====================================================== */
			// create a normal appointment lasting time fragmentation
			/* ------------------------------------------------------- */
			// int frag = (Integer)
			// agendaAdminSettingsPlugin.getValue(AgendaAdminSettingsPlugin.HOUR_FRAGMENTATION);
			/* ------------------------------------------------------- */
			NamedCalendar nc = calendarPanel.getSelectedCalendar();

			// set the duration of a appointment
			// -------------------------------------------------------
			AppointmentManager aManager = (AppointmentManager) ManagerFactory
					.getRemote(AppointmentManagerBean.class);

			Collection<AppointmentType> result = aManager
					.getAppointmentTypesByID(AppointmentType.GENERAL, nc
							.getId(), false);

			int duration = 0;
			if (result != null) {
				for (AppointmentType t : result) {
					if (t != null) {
						duration = t.getDuration();
						break;
					}
				}
			}

			// set the duration of a appointment to the calendar fragmentation
			// int offset = frag * 60000;
			// set the duration of a appointment to the calendar first
			// appointmenttype duration
			int offset = duration * 60000;
			DateInterval interval = new DateInterval(date, new Date(date
					.getTime()
					+ offset));
			// -------------------------------------------------------
			newEvent(id, interval);
			/* ====================================================== */
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see bizcal.swing.CalendarListener#newEvent(java.lang.Object,
		 * bizcal.util.DateInterval) Is call when appointment is create by
		 * (resize) drawing up a appointment.
		 */
		public void newEvent(Object id, DateInterval interval) throws Exception {
			/* ====================================================== */

			// create an Event object
			// Event newEvent = appointment2Event(ap);

			NamedCalendar nc = calendarPanel.getSelectedCalendar();
			/* ------------------------------------------------------- */
			if (nc == null)
				return;
			/* ------------------------------------------------------- */
			Event event = new Event();
			event.setStart(interval.getStartDate());
			event.setEnd(interval.getEndDate());

			List<Event> newEvent = nc.addEvent(MainFrame.getClientId(), event);
			if (newEvent != null)
				updateEvent(event, newEvent);
			/* ====================================================== */
		}

		public void paste(Object calId, Date date) throws Exception {
			/* ====================================================== */
			Integer calID = copyEvents();
			// reload events
			try {
				fetchEvents(getCalendarForId(calID));				
			} catch (Exception e) {
				logger.warn("Error reloading pasted Events", e);
				fetchEventsForAllCalendars();	
			}
			/* ====================================================== */
		}

		public void resized(Event event, Object orgCalId, Date orgEndDate,
				Date newEndDate) throws Exception {
			Event workingEvent = event;
			/* ====================================================== */
			NamedCalendar nc = calendarPanel.getSelectedCalendar();
			/* ------------------------------------------------------- */
			if (nc == null)
				return;
			/* ------------------------------------------------------- */

			// ///////////////////////////////////////////////////////////////////////////////////////////////////
			// if the event is part of a reccurrence we must
			// get the event that matches the date of the Appointment object
			// and compute the date shiffting and add it to the original
			// date in order to adjust all events that depends on this
			// recurrence.
			if (event.getId() instanceof Appointment) {
				/* ------------------------------------------------------- */
				Appointment app = (Appointment) event.getId();
				if (Appointment.NO_RECUR < app.getFrequency()) {
					/* ------------------------------------------------------- */
					// compute the shift
					// long shift = DateUtil.getDiffDay(event.getStart(),
					// newDate);

					if (app.getStartDate().equals(event.getStart())
							&& app.getEndDate().equals(event.getEnd())) {
						// this is the orginal event. Just move!
						// event.move(newDate);
						event.setEnd(newEndDate);
					} else {
						/*
						 * ------------------------------------------------------
						 * -
						 */
						// find the first event
						List<Event> events = eventHash.get(calendarPanel
								.getSelectedCalendar());
						if (events != null)
							for (Event e : events) {
								// if the event has the same Appointment object
								if (event.getId().equals(e.getId())) {
									// if the dates are equal
									if (app.getStartDate().equals(e.getStart())
											&& app.getEndDate().equals(
													e.getEnd())) {
										/*
										 * --------------------------------------
										 * -----------------
										 */

										// event.setEnd(newEndDate);
										// this is the first event, shift it
										e.setEnd(new Date(e.getStart()
												.getTime()
												+ DateUtil
														.getDiffDay(event
																.getStart(),
																newEndDate)));

										// setStart(newStartDate);
										// e.setEnd(newEndDate);
										// e.move(new
										// Date(e.getStart().getTime()+shift));
										workingEvent = e;

										break;
										/*
										 * --------------------------------------
										 * -----------------
										 */
									}
								}
							}
						/*
						 * ------------------------------------------------------
						 * -
						 */
					}
					/* ------------------------------------------------------- */
					// shift the until field too
					// if (app.getUntil() != null) {
					// app.setUntil(new Date(app.getUntil().getTime() + shift));
					// }
					/* ------------------------------------------------------- */
				} else
					event.setEnd(newEndDate);
				// event.move(newDate);
				/* ------------------------------------------------------- */
			} else
				event.setEnd(newEndDate);
			// event.move(newDate);
			// ///////////////////////////////////////////////////////////////////////////////////////////////////
			// event.setEnd(newEndDate);
			if (workingEvent.get(Event.EVENT_PROPOSAL_STATE) != null
					&& (Boolean) workingEvent.get(Event.EVENT_PROPOSAL_STATE) == true) {
				/* ------------------------------------------------------- */
				Appointment app = (Appointment) workingEvent.getId();
				app.setStartDate(workingEvent.getStart());
				app.setEndDate(workingEvent.getEnd());

				updateEvent(workingEvent, Collections.nCopies(1, workingEvent));
				// disable the automatic movement of the appointment if it overlays other appointments after resizeing
//				freeAppointmentFindDialog
//						.fadeToAppointment((Appointment) workingEvent.getId());
				freeAppointmentFindDialog.setAppointmentToView((Appointment) workingEvent.getId());
				/* ------------------------------------------------------- */
			} else {
				// normal behaviour!
				/* ------------------------------------------------------- */
				List<Event> newEvent = nc.saveEvent(MainFrame.getClientId(),
						workingEvent, false);
				if (newEvent != null)
					updateEvent(workingEvent, newEvent);
				/* ------------------------------------------------------- */
			}
			/* ====================================================== */
		}

		public void eventDoubleClick(Object id, Event event,
				MouseEvent mouseEvent) {
			/* ====================================================== */
			if (event == null)
				return;
			/* ------------------------------------------------------- */
			if (SwingUtilities.isLeftMouseButton(mouseEvent)) {
				/* ------------------------------------------------------- */
				modifyEvent(event);
				/* ------------------------------------------------------- */
			}
			/* ====================================================== */
		}

		public void eventClicked(Object id, Event _event, FrameArea area,
				MouseEvent e) {
			/* ====================================================== */
			// if (e.isPopupTrigger()) {
			// // show popup
			lastClickedEvent = _event;
			// /* ------------------------------------------------------- */
			// if (this.clipBoard == null || this.clipBoard.size() < 1)
			// this.pasteEventAction.setEnabled(false);
			// else
			// this.pasteEventAction.setEnabled(true);
			// /* ------------------------------------------------------- */
			// this.eventPopup.show(area, e.getX(), e.getY());
			// }
			/* ====================================================== */
		}
	}

	/**
	 * Converts an Appointment to an Event. If Appointment is null, the return
	 * is null.
	 * 
	 * @param app
	 * @return
	 */
	public static Event appointment2Event(Appointment app) {
		/* ================================================== */
		if (app == null)
			return null;
		/* ------------------------------------------------------- */
		Event event = new Event();
		// =================================================================
		// this is a workaround for SUN Java SDK 1.50_6 Bug No 5103041
		// ClassCastException in compareTo of java.util.Date and Timestamp
		// -----------------------------------------------------------------
		// thats how it should work. Problem has been fixed in Java 1.5.0_7
		// e.setStart(app.getStartDate());
		// e.setEnd(app.getEndDate());
		// The JBoss returns Timestamp objects in the util.Date fields as
		// inherited
		// class. The workaround idea is to create implicit java.util.Date
		// objects
		// from the Timestamp objects.
		/* --------------------------------------------------------------- */
		// workaround
		try {
			event.setStart(new Date(app.getStartDate().getTime()));
		} catch (Exception ex) {
		}
		/* ------------------------------------------------------- */
		try {
			event.setEnd(new Date(app.getEndDate().getTime()));
		} catch (Exception ex) {
		}
		// ==================================================================
		if (app.getPatientId() != null)
			event.setUpperRightIcon(IconFetcher.getMiniIcon(
					PatientManagerIconNames.class,
					PatientManagerIconNames.PATIENT));

		try {
			/* ------------------------------------------------------- */
//			if (GECAMedLists.getArray(AppointmentType.class) == null) {
//				loadApointmentTypes();
//			}
			List<AppointmentType> ap = GECAMedLists.getListReference(AppointmentType.class);
			for (AppointmentType t : ap) {
				if (t.getId().equals(app.getTypeId())) {
					event.setIcon(AgendaModule.getMiniIcon(t.getIcon()));

					break;
				}
			}
			// }
			/* ------------------------------------------------------- */
		} catch (Exception e1) {
		}

		// =================================================
		// if appointment is set to private and the owner is not the current
		// user
		// print only the date and make it not editable
		// =================================================
		if (app.isPrivate()
				&& !app.getCreatedBy().equals(MainFrame.getCurrentUserId())) {
			/* ------------------------------------------------------- */
			event.setEditable(false);
			event.setIcon(AgendaModule.getMiniIcon(AgendaModule.TYPE_PRIVATE));
			event.setSelectable(false);
			event.setSummary(Translatrix
					.getTranslationString("calendar.newEvent.private"));
			/* ------------------------------------------------------- */
		} else {
			/* ------------------------------------------------------- */
			event.setSummary(app.getSummary());
			event.setDescription(app.getDescription());
			event.setEditable(true);
			/* ------------------------------------------------------- */
		}
		event.setBackground(app.getIsBackground());
		event.setId(app);
		// set the calendar id of the event
		event.set(Event.CALENDAR_ID, app.getCalendarId());
		// set Calendar isBackground to Event
		event.set(Event.CALENDAR_IS_BACKGROUND, AgendaModule.getCalendarForId(app.getCalendarId()).isBackground());
		event.setShowTime(false);
		event.setRoundedCorner(false);
		// event.setShowHeader(false);
		try {
			event.setColor(new Color(getCalendarForId(app.getCalendarId())
					.getColor()));
		} catch (Exception e) {

		}
		/* ------------------------------------------------------- */
		try {
			if (AppointmentType.BLOCK_PERIOD.equals(AgendaModule.getTypeForId(
					app.getTypeId()).getAppointmentTypeClass()))
				event.set(Event.LINE_DISTANCE, 10);
		} catch (Exception ex) {
			ex.printStackTrace();
		}

		return event;
		/* ================================================== */
	}

//	/**
//	 * Loads the calendars into GECAMedLists
//	 */
//	public static void loadCalendars() {
//		/* ================================================== */
//		try {
//			/* ------------------------------------------------------- */
//			AppointmentManager apManager = (AppointmentManager) ManagerFactory
//					.getRemote(AppointmentManagerBean.class);
//			/* ------------------------------------------------------- */
//			Collection<AgendaCalendar> cals = apManager.getCalendars();
//			if (cals == null)
//				return;
//			/* ------------------------------------------------------- */
//			// save AgendaCalendars in GECAMedLists
//			GECAMedLists.storeList(AgendaCalendar.class, cals
//					.toArray(new AgendaCalendar[0]));
//			/* ------------------------------------------------------- */
//		} catch (Exception e) {
//			e.printStackTrace();
//		}
//		/* ================================================== */
//	}

	/**
	 * Loads the calendars into GECAMedLists
	 */
//	public static void loadApointmentTypes() {
//		/* ================================================== */
//		try {
//			/* ------------------------------------------------------- */
//			AppointmentManager apManager = (AppointmentManager) ManagerFactory
//					.getRemote(AppointmentManagerBean.class);
//			/* ------------------------------------------------------- */
//			Collection<AppointmentType> types = apManager.getAppointmentTypes(
//					null, false);
//			if (types == null)
//				return;
//			/* ------------------------------------------------------- */
//			// save AgendaCalendars in GECAMedLists
//			GECAMedLists.storeList(AppointmentType.class, types
//					.toArray(new AppointmentType[0]));
//			/* ------------------------------------------------------- */
//		} catch (Exception e) {
//			e.printStackTrace();
//		}
//		/* ================================================== */
//	}

	/**
	 * @param id
	 * @return
	 */
	public static AppointmentType getTypeForId(Integer id) {
		/* ================================================== */
		if (id == null)
			return null;
		/* ------------------------------------------------------- */
		// get appointment types from GECAMedLists
		List<AppointmentType> types = GECAMedLists.getListReference(AppointmentType.class);
		/* ------------------------------------------------------- */
		try {
			for (AppointmentType to : types)
				if (id.equals(to.getId()))
					return to;
			return types.get(0);
		} catch (Exception e) {
			return null;
		}
		/* ================================================== */
	}

	/**
	 * @param id
	 * @return
	 */
	public static AppointmentType getTypeForClassId(Integer id) {
		/* ================================================== */
		if (id == null)
			return null;
		/* ------------------------------------------------------- */
		// get appointment types from GECAMedLists
		List<AppointmentType> types = Arrays.asList(GECAMedLists.getArray(AppointmentType.class));
		/* ------------------------------------------------------- */
		try {
			for (AppointmentType to : types)
				if (id.equals(to.getAppointmentTypeClass()))
					return to;
			return types.get(0);
		} catch (Exception e) {
			return null;
		}
		/* ================================================== */
	}

	/**
	 * @param id
	 * @return returns a calendar for the id. If nothing is found, the first
	 *         calendar in the list is returned
	 */
	public static AgendaCalendar getCalendarForId(Integer id) {
		/* ================================================== */
		return getCalendarForId(id, true);
		/* ================================================== */
	}

	/**
	 * @param id
	 * @param nullSafe
	 *            if true, the first calendar is returned if nothing has been
	 *            found
	 * @return
	 */
	public static AgendaCalendar getCalendarForId(Integer id, boolean nullSafe) {
		/* ================================================== */
		if (id == null)
			return null;
		/* ------------------------------------------------------- */
		// get calendars from GECAMedLists
		// ArrayList<AgendaCalendar> cals = new ArrayList<AgendaCalendar>(
		// (Collection<? extends AgendaCalendar>)
		// Arrays.asList(GECAMedLists.getList(AgendaCalendar.class)));
		List<AgendaCalendar> cals = GECAMedLists.getListReference(AgendaCalendar.class);
		/* ------------------------------------------------------- */
		for (AgendaCalendar o : cals)
			if (id.equals(o.getId()))
				return o;
		try {
			if (nullSafe)
				return cals.get(0);
			// else
			// return null;
		} catch (Exception e) {
		}
		return null;
		/* ================================================== */
	}

	// ---------------------------------------------------------------------------
	/**
	 * returns the ImageIcon Resource specified by p_IconName.
	 * 
	 * @param p_IconName
	 *            specifies the name of the icon to get from application
	 *            resources.
	 * @return the ImageIcon specified by p_IconName, or <CODE>null</CODE> if
	 *         specified does not exist.
	 */
	// ---------------------------------------------------------------------------
	public static ImageIcon getIcon(String p_IconName) {
		return IconFetcher.getIcon(AgendaModule.class, p_IconName);
	}

	// ---------------------------------------------------------------------------

	public static ImageIcon getMediumIcon(String p_IconName) {
		return IconFetcher.getMediumIcon(AgendaModule.class, p_IconName);
	}

	// ---------------------------------------------------------------------------

	public static ImageIcon getScaledIcon(String p_IconName, int size) {
		return IconFetcher.getScaledIcon(AgendaModule.class, p_IconName, size);
	}

	// ---------------------------------------------------------------------------

	public static ImageIcon getMiniIcon(String p_IconName) {
		return IconFetcher.getMiniIcon(AgendaModule.class, p_IconName);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * lu.tudor.santec.settings.SettingListener#settingChanged(lu.tudor.santec
	 * .settings.SettingEvent)
	 */
	public void settingChanged(SettingEvent se) {
		/* ================================================== */
		if (this.agendaSettingsPlugin.equals(se.getSource())) {
			if (se.getSetting().equals(AgendaSettingsPlugin.LIST_VIEW_PERIOD)) {
				listViewPanel.setShowDays((Integer) agendaSettingsPlugin
						.getValue(AgendaSettingsPlugin.LIST_VIEW_PERIOD));
			}
			boolean calChanged = false;
			if (se.getSetting().equals(AgendaSettingsPlugin.START_HOUR)) {
				dConfig.setDefaultDayStartHour(DateUtil
						.getHourOfDay((Date) agendaSettingsPlugin
								.getValue(AgendaSettingsPlugin.START_HOUR)));
				calChanged = true;
			}
			/* ------------------------------------------------------- */
			if (se.getSetting().equals(AgendaSettingsPlugin.STOP_HOUR)) {
				dConfig.setDefaultDayEndHour(DateUtil
						.getHourOfDay((Date) agendaSettingsPlugin
								.getValue(AgendaSettingsPlugin.STOP_HOUR)));
				calChanged = true;
			}
			/* ------------------------------------------------------- */
			if (se.getSetting().equals(AgendaSettingsPlugin.WEEK_DAY_START)) {
				dConfig.setWeekStart((Integer) agendaSettingsPlugin
						.getValue(AgendaSettingsPlugin.WEEK_DAY_START));
				calChanged = true;
			}
			/* ------------------------------------------------------- */
			if (se.getSetting().equals(AgendaSettingsPlugin.WEEK_DAY_STOP)) {
				dConfig.setWeekStop((Integer) agendaSettingsPlugin
						.getValue(AgendaSettingsPlugin.WEEK_DAY_STOP));
				calChanged = true;
			}
			/* ------------------------------------------------------- */
			if (se.getSetting().equals(AgendaSettingsPlugin.DAY_BREAK)) {
				dConfig.setDayBreak((Integer) agendaSettingsPlugin
						.getValue(AgendaSettingsPlugin.DAY_BREAK));
				calChanged = true;
			}
			/* ------------------------------------------------------- */
			if (se.getSetting().equals(AgendaSettingsPlugin.GRID_ALPHA)) {
				dConfig.setGridAlpha((Integer) agendaSettingsPlugin
						.getValue(AgendaSettingsPlugin.GRID_ALPHA));
				calChanged = true;
			}
			/* ------------------------------------------------------- */
			if (calChanged) {
				/* ------------------------------------------------------- */
				refreshBizcal();
				/* ------------------------------------------------------- */
				// // reset the rules
				// try {
				// AppointmentManager aManager = (AppointmentManager)
				// ManagerFactory.getRemote(AppointmentManagerBean.class);
				//					
				// aManager.resetRules();
				// /* ------------------------------------------------------- */
				// } catch (Exception e) {
				// MainFrame.reportServerError(e);
				// }
				/* ------------------------------------------------------- */
			}
		}
		/* ------------------------------------------------------- */
		// Admin Settings
		/* ------------------------------------------------------- */
		if (agendaAdminSettingsPlugin.equals(se.getSource())) {
			/* ------------------------------------------------------- */
			if (AgendaAdminSettingsPlugin.HOUR_FRAGMENTATION.equals(se.getSetting()))
			{
				setHourFragmentation();
			}
					
			if (AgendaAdminSettingsPlugin.AUTO_DESCRIPTION_MATR.equals(se.getSetting()))
			{
				// TODO if something should triggered if the setting is change put it here
			}
			
			if (AgendaAdminSettingsPlugin.AUTO_DESCRIPTION_TYPE.equals(se.getSetting()))
			{
				// TODO if something should triggered if the setting is change put it here
			}
			if (AgendaAdminSettingsPlugin.AUTO_DESCRIPTION_ID.equals(se.getSetting()))
			{
				// TODO if something should triggered if the setting is change put it here
			}
			refreshBizcal();
			/* ------------------------------------------------------- */
		}
		/* ================================================== */
	}

	/**
	 * Refreshes the calendar.
	 */
	private void refreshBizcal() {
		/* ================================================== */
		weekModel.triggerUpdate();
		// update the calendar view
		this.dayViewPanel.refresh();
		this.dayThreeViewPanel.refresh();
		this.weekViewPanel.refresh();

		/* ================================================== */
	}

	// ---------------------------------------------------------------------------

	// ===============================================================================
	// Methods from PopupMenuCallBack interface
	//
	// manages all popup menus for the views.
	// ===============================================================================

	public JPopupMenu getCalendarPopupMenu(Object calId) throws Exception {
		/* ====================================================== */
		return null;
		/* ====================================================== */
	}

	public JPopupMenu getEmptyPopupMenu(Object calId, Date date)
			throws Exception {
		/* ====================================================== */
		/* ------------------------------------------------------- */
		if (this.clipBoard == null || this.clipBoard.size() < 1)
			this.pasteEventAction.setEnabled(false);
		else
			this.pasteEventAction.setEnabled(true);
		/* ------------------------------------------------------- */
		this.copyEventAction.setEnabled(false);
		this.deleteEventAction.setEnabled(false);
		this.modifyEventAction.setEnabled(false);
		return this.eventPopup;
		/* ====================================================== */
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see bizcal.swing.PopupMenuCallback#getEventPopupMenu(java.lang.Object,
	 * bizcal.common.Event)
	 */
	public JPopupMenu getEventPopupMenu(Object calId, Event event)
			throws Exception {
		/* ====================================================== */
		this.copyEventAction.setEnabled(true);
		this.deleteEventAction.setEnabled(true);
		this.modifyEventAction.setEnabled(true);
		/* ------------------------------------------------------- */
		if (this.clipBoard == null || this.clipBoard.size() < 1)
			this.pasteEventAction.setEnabled(false);
		else
			this.pasteEventAction.setEnabled(true);
		/* ------------------------------------------------------- */
		return this.eventPopup;
		/* ====================================================== */
	}

	public JPopupMenu getProjectPopupMenu(Object calId) throws Exception {
		/* ====================================================== */
		return null;
		/* ====================================================== */
	}

	public static AgendaModule getInstance() {
		/* ====================================================== */
		return agendaModule;
		/* ====================================================== */
	}

	public AgendaAdminSettingsPlugin getAgendaAdminSettingsPlugin() {
		/* ====================================================== */
		return agendaAdminSettingsPlugin;
		/* ====================================================== */
	}

	/**
	 * @return
	 */
	public AgendaSettingsPlugin getAgendaSettingsPlugin() {
		/* ====================================================== */
		return this.agendaSettingsPlugin;
		/* ====================================================== */
	}

	public void setDate(Date date) {
		this.calendarPanel.setDate(date);

	}

	/**
	 * Returns the next following appointment of a patient. The result is
	 * cachend and is updated each time an appointment for the patient has been
	 * made.
	 * 
	 * @param patientId
	 * @return
	 */
	public Appointment getNextAppointmentOfPatient(Integer patientId) {
		/* ================================================== */
		// make a self cleanup. Each time there are more than 10 entries
		// clear the hash
		if (this.patientNextAppointmentHash.keySet().size() > 10)
			this.patientNextAppointmentHash.clear();
		/* ------------------------------------------------------- */

		// try to get the appointment out of the hash
		Appointment nextApp = patientNextAppointmentHash.get(patientId);
		if (nextApp != null)
			return nextApp;
		/* ------------------------------------------------------- */
		// if there is no, try to get the appointment from the database
		try {
			/* ------------------------------------------------------- */
			AppointmentManager aManager = (AppointmentManager) ManagerFactory
					.getRemote(AppointmentManagerBean.class);
			nextApp = aManager.getNextAppointmentOfPatient(patientId);

			if (nextApp != null)
				this.patientNextAppointmentHash.put(patientId, nextApp);

			return nextApp;
			/* ------------------------------------------------------- */
		} catch (Exception e) {
			return null;
		}
		/* ================================================== */
	}

	/**
	 * Removes the next appointment from the hash to keep memory small
	 * 
	 * @param patientId
	 */
	public void removePatient(Integer patientId) {
		/* ================================================== */
		this.patientNextAppointmentHash.remove(patientId);
		/* ================================================== */
	}

	/**
	 * Reads the settings and pipe them to the dayViewConfig
	 */
	private void setHourFragmentation() {
		/* ================================================== */
		Integer frag = (Integer) agendaAdminSettingsPlugin
				.getValue(AgendaAdminSettingsPlugin.HOUR_FRAGMENTATION);
		int timeslots = 0;
		switch (frag) {
		case AgendaAdminSettingsPlugin.FRAG_HOUR:
			timeslots = 1;
			break;
		case AgendaAdminSettingsPlugin.FRAG_HALF:
			timeslots = 2;
			break;
		case AgendaAdminSettingsPlugin.FRAG_THIRD:
			timeslots = 3;
			break;
		case AgendaAdminSettingsPlugin.FRAG_QUARTER:
			timeslots = 4;
			break;
		case AgendaAdminSettingsPlugin.FRAG_SIXTHT:
			timeslots = 6;
			break;
		case AgendaAdminSettingsPlugin.FRAG_TWELFTH:
			timeslots = 12;
			break;

		default:
			timeslots = 4;
			break;
		}

		dConfig.setNumberOfTimeSlots(timeslots);
		// dConfig.setNumberOfTimeSlots(60);
		/* ================================================== */
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * lu.tudor.santec.gecamed.core.gui.GECAMedMessageListener#handleGECAMedMessage
	 * (lu.tudor.santec.gecamed.core.gui.GECAMedMessage)
	 */
	public void handleGECAMedMessage(GECAMedMessage message) {
		/* ====================================================== */
		if (message.getModul() instanceof AdminModule) {
			/* ------------------------------------------------------- */
			if (MessageListenerRegister.MESSAGE_CREATE_NEW_CALENDAR
					.equals(message.getMessage())) {
				/* ------------------------------------------------------- */
				// a new physician needs a new calendar
				/* ------------------------------------------------------- */
				try {
					/* --------------------------------------------- */
					AppointmentManager apManager = (AppointmentManager) ManagerFactory
							.getRemote(AppointmentManagerBean.class);
					apManager.createNewCalendar((Physician) message
							.getNewValue());
					/* --------------------------------------------- */
				} catch (Exception e) {
					/* --------------------------------------------- */
					e.printStackTrace();
					/* --------------------------------------------- */
				}
				/* ------------------------------------------------------- */
			}
			/* ------------------------------------------------------- */
		}
		/* ====================================================== */
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * lu.tudor.santec.gecamed.core.gui.PhysicianListener#physicianChanged(lu
	 * .tudor.santec.gecamed.office.ejb.entity.beans.Physician)
	 */
	public void physicianChanged(Physician physician) {
		/* ====================================================== */
		if (physician == null || calendarHash == null)
			return;
		/* ------------------------------------------------------- */
		// try to switch to the calendar of the physician
		/* ------------------------------------------------------- */
		for (NamedCalendar nc : this.calendarHash.keySet()) {
			/* ------------------------------------------------------- */
			AgendaCalendar ac = calendarHash.get(nc);
			if (physician.getId().equals(ac.getPhysicianId())) {
				/* ------------------------------------------------------- */
				selectCalendar(nc.getId());
				return;
				/* ------------------------------------------------------- */
			}
			/* ------------------------------------------------------- */
		}
		/* ====================================================== */
	}

	/**
	 * Logs the modifications of appointment done by the user action in the agenda  
	 * @param appointment the appointmet
	 * @param status are CREATE_APPOINTMENT, CHANGE_APPOINTMENT_BY_DIALOG, CHANGE_APPOINTMENT, DELETE_APPOINTMENT
	 */
	public static void logUserActionAgenda(Appointment appointment,String status, long took)
	{
		// check if the appointment is a new one
		if (appointment.getId() == null) {
			status = CREATE_APPOINTMENT;
		} else {
			// check if the appointment has change in the edit dialog
			if (status.equals(CHANGE_APPOINTMENT_BY_DIALOG))
			{
				AppointmentManager aManager = (AppointmentManager) ManagerFactory
						.getRemote(AppointmentManagerBean.class);

				Appointment dummyApp = aManager.getAppointment(appointment
						.getId());
				// check if the appointment is modify
				if (!appointment.isEqual(dummyApp))
				{
					status = CHANGE_APPOINTMENT;

				} else
					status = "nothing";
			}
		}
		
		// if status of the appointment have change log the modification
		if (!status.equals("nothing"))
		{
			// create the log message
			// Operation: {CREATE, CHANGE, DELETE} Appointment
			// Message: Physician: <physician name>; Patient: <patient name>; Appointment: <begin> - <end> [<recurrence rule>] 
			AgendaCalendar calendar = appointmentManager.getCalendar(appointment.getCalendarId());
			Physician physician = null;
			Patient patient = null;
			
			String physicianName = "Physician: not set";			
			if(calendar.getPhysicianId() != null)
			{
				try {
					// get the physician
					physician = officeManager.getPhysician(calendar.getPhysicianId());
				} catch (Exception e) {
					logger.log(Level.WARN, "Couldn't set physician for log appointment modification.", e);
				}
				if(physician != null)
					physicianName = "Physician: " + physician.getFirstName() + " " + physician.getName();
			}

			String appointmentSummary = null;
			if(appointment.getPatientId() != null)
			{
				try {
					// get the patient
					patient = patientManager.getPatient(appointment.getPatientId());
				} catch (Exception e) {
					logger.log(Level.WARN, "Couldn't set patient for log appointment modification.");
					patient = null;
				}
				appointmentSummary = "; Patient: " + patient.getFirstName() + " " + patient.getSurName();
			}else{
				appointmentSummary = "; Title: " + appointment.getSummary();
			}
			String recurrence = null; 
			Integer frequency = appointment.getFrequency();
			String recuringRule = appointment.getRRule();
			Date until = appointment.getUntil();
			
			SimpleDateFormat dateFormater = new SimpleDateFormat();
			dateFormater.applyPattern("dd/MM/yy HH:mm");
			
			if(frequency != null)
				if(frequency != 0)
				{
					if(Appointment.DAILY == frequency) recurrence =  Appointment.STR_DAILY + "; ";
					if(Appointment.WEEKLY == frequency) recurrence = Appointment.STR_WEEKLY + "; ";
					if(Appointment.MONTHLY == frequency) recurrence = Appointment.STR_MONTHLY + "; ";
					if(Appointment.YEARLY == frequency) recurrence = Appointment.STR_YEARLY + "; ";
				}
			if(recuringRule != null)
				recurrence = recurrence + recuringRule + " ";
			if(until != null)
				recurrence = recurrence + dateFormater.format(until);
			
			if(recurrence != null) recurrence = "[" + recurrence + "]";
			
			String infoText = physicianName
			+ appointmentSummary
			+ "; Appointment: " + dateFormater.format(appointment.getStartDate()) + " - " + dateFormater.format(appointment.getEndDate());
			if(recurrence != null) infoText = infoText + " " + recurrence;
			
			GECAMedLog.user(AgendaModule.MODULE_NAME, status, infoText, took);
		}
	}
	
	public static void logUserActionAgenda(String operation, AgendaCalendar calendar, AgendaCalendar calendarBevor)
	{
		StringBuffer message = new StringBuffer();
		String userName = "User: not set";
		String userNameBevor = "User: not set";
		String physicianName = "Physician: not set";
		String physicianNameBevor = "Physician: not set"; 
		
		if(calendar != null)
		{
			Physician physician = null;
			GecamedUser user = null;
						
			if(calendar.getPhysicianId() != null)
			{
				try {
					// get the physician
					physician = officeManager.getPhysician(calendar.getPhysicianId());
				} catch (Exception e) {
					logger.log(Level.WARN, "Couldn't set physician for log calendar modification.", e);
				}
				if(physician != null)
					physicianName = "Physician: " + physician.getFirstName() + " " + physician.getName();
			}
			
			if(calendar.getUserId() != null)
			{
				try {
					// get the user
					user = userManager.getUser(calendar.getUserId());
				} catch (Exception e) {
					logger.log(Level.WARN, "Couldn't set user for log calendar modification.", e);
				}
				if(physician != null)
					userName = "User: " + user.getName();
			}
		}
		
		if(calendarBevor != null)
		{
			Physician physician = null;
			GecamedUser user = null;
						
			if(calendarBevor.getPhysicianId() != null)
			{
				try {
					// get the physician
					physician = officeManager.getPhysician(calendarBevor.getPhysicianId());
				} catch (Exception e) {
					logger.log(Level.WARN, "Couldn't set physician for log appointment modification.", e);
				}
				if(physician != null)
					physicianNameBevor = "Physician: " + physician.getFirstName() + " " + physician.getName();
			}
			
			if(calendarBevor.getUserId() != null)
			{
				try {
					// get the user
					user = userManager.getUser(calendarBevor.getUserId());
				} catch (Exception e) {
					logger.log(Level.WARN, "Couldn't set user for log calendar modification.", e);
				}
				if(physician != null)
					userNameBevor = "User: " + user.getName();
			}
		}
		
		if(operation.equals(DELETE_CALENDAR))
		{
			message.append("Calendar: ");
			message.append(calendar);
			message.append(" - ");
			message.append(userName);
			message.append(" - ");
			message.append(physicianName);
		}
		
		if(operation.equals(CHANGE_CALENDAR))
		{
			message.append("Calendar: ");
			message.append(calendarBevor.getTitle());
			message.append(" - ");
			message.append(userNameBevor);
			message.append(" - ");
			message.append(physicianNameBevor);
			message.append(" >>> ");
			message.append("Calendar: ");
			message.append(calendar.getTitle());
			message.append(" - ");
			message.append(userName);
			message.append(" - ");
			message.append(physicianName);
		}
		
		if(operation.equals(CREATE_CALENDAR))
		{
			message.append("Calendar: ");
			message.append(calendar.getTitle());
			message.append(" - ");
			message.append(userNameBevor);
			message.append(" - ");
			message.append(physicianNameBevor);
		}
		
		GECAMedLog.user(AgendaModule.MODULE_NAME, operation, message.toString(), null);
	}
	
	/**
	 * Get the id of the Office Calendar.
	 * @return the id
	 */
	public static Integer getOfficeCalendarId()
	{
		for (AgendaCalendar calendar : GECAMedLists.getListReference(AgendaCalendar.class))
		{	
			if(calendar.getTitle().equals("OFFICE"))
			{
				return calendar.getId();
			}
		}	
		return null;
	}
	
	public Event getEventByAppointmentID(Integer appId) {
		for (Event ev : eventDataList) {
			if (ev.getId() != null && ev.getId() instanceof Appointment) {
				if (appId.equals(((Appointment)ev.getId()).getId())) {
					return ev;
				}
			}
		}
		return null;
	}
	
	public static void editAppointment(Integer appId) {
		try {
			AgendaModule m = getInstance();
			
			if (m == null) return;
			
			AppointmentManager apManager = (AppointmentManager) ManagerFactory
					.getRemote(AppointmentManagerBean.class);
			
			Appointment app = apManager.getAppointment(appId);

			if (app != null) {
				MainFrame.getInstance().selectModule(MODULE_NAME);
				m.setDate(app.getStartDate());
				m.selectCalendar(app.getCalendarId());
				m.fetchEventsForAllCalendars();

				Event ev = m.getEventByAppointmentID(appId);
				
				if (ev != null) {
					m.modifyEvent(ev);					
				}
				
			}
			
		} catch (Exception e) {
			logger.warn("Error editing Appointment with ID: " + appId, e);
		}
	}
	
}
