package lu.tudor.santec.gecamed.billing.gui.hospitalisation;

import java.awt.Component;
import java.awt.Cursor;
import java.text.DateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Vector;

import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.ListCellRenderer;
import javax.swing.ListSelectionModel;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;

import lu.tudor.santec.gecamed.billing.ejb.entity.beans.Rate;
import lu.tudor.santec.gecamed.billing.ejb.entity.beans.RateIndex;
import lu.tudor.santec.gecamed.billing.ejb.session.beans.NomenclatureBean;
import lu.tudor.santec.gecamed.billing.ejb.session.interfaces.NomenclatureInterface;
import lu.tudor.santec.gecamed.billing.gui.BillingModule;
import lu.tudor.santec.gecamed.billing.gui.invoice.InvoiceEditorPanel;
import lu.tudor.santec.gecamed.core.ejb.entity.beans.NationalHoliday;
import lu.tudor.santec.gecamed.core.gui.GECAMedColors;
import lu.tudor.santec.gecamed.core.gui.LoginScreen;
import lu.tudor.santec.gecamed.core.gui.MainFrame;
import lu.tudor.santec.gecamed.core.gui.utils.GECAMedGuiUtils;
import lu.tudor.santec.gecamed.core.gui.widgets.GECAMedBaseDialogImpl;
import lu.tudor.santec.gecamed.core.utils.ManagerFactory;
import lu.tudor.santec.gecamed.office.ejb.entity.beans.Physician;
import lu.tudor.santec.i18n.Translatrix;

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

import bizcal.util.DateUtil;

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

public class HospitalisationPeriodDialog extends GECAMedBaseDialogImpl
{
	/* ======================================== */
	// 		CONSTANTS
	/* ======================================== */
	
	/** the logger Object for this class */
	private static Logger logger = Logger.getLogger(HospitalisationPeriodDialog.class.getName());
	private static final long serialVersionUID = 1L;

	// RELEVANT SECTIONS OF CHAPTER 4 OF THE CNS NOMENCLATURE
	static final String SECTION_1	= "G_4_1";
	static final String SECTION_2	= "G_4_2";
	static final String SECTION_3	= "G_4_3";
	static final String SECTION_4	= "G_4_4";
	static final String SECTION_5	= "G_4_5";
	static final String SECTION_6	= "G_4_6";
	static final String SECTION_61	= "G_4_6_1";
	static final String SECTION_62	= "G_4_6_2";
	static final String SECTION_63	= "G_4_6_3";
	static final String SECTION_64	= "G_4_6_4";
	static final String SECTION_7	= "G_4_7";
	static final String SECTION_71	= "G_4_7_1";
	static final String SECTION_72	= "G_4_7_2";
	static final String SECTION_8	= "G_4_8";
	static final String SECTION_9	= "G_4_9";
	static final String SECTION_10	= "G_4_10";
	
	static final String[] GENERAL_SECTIONS = {
		SECTION_1,
		SECTION_2,
		SECTION_3,
		SECTION_4,
		SECTION_8,
		SECTION_9,
		SECTION_10
	};
	
	static final String[] REANIMATION_SECTIONS = {
		SECTION_6,
		SECTION_7,
	};
	
	// HOSPITALISATION CODES FOR GENERAL MEDECIN:
	private static final String CODE_F11 = "F11";
	private static final String CODE_F12 = "F12";
	private static final String CODE_F13 = "F13";
	private static final String CODE_F14 = "F14";

	// HOSPITALISATION CODES FOR INTERN MEDECIN:
	private static final String CODE_F20 = "F20"; // 1st day of hospitalisation, if transfered to a specialist
	private static final String CODE_F21 = "F21"; // 1st day of hospitalisation, if not transfered
	private static final String CODE_F22 = "F22"; //  2nd - 14th day of hospitalisation
	private static final String CODE_F23 = "F23"; // 15th - 42th day of hospitalisation
	private static final String CODE_F24 = "F24"; // 43th - last day of hospitalisation
	private static final String CODE_F25 = "F25"; // 1st day of hospitalisation, if transfered to a specialist in internal medicine
	private static final String CODE_F26 = "F26"; // 1st day of hospitalisation by a specialist in internal medicine (not transferred)
	private static final String CODE_F27 = "F27"; // 1st day of hospitalisation of a child younger than 14, transferred to a specialist in pediatrics 
	private static final String CODE_F28 = "F28"; // 1st day of hospitalisation of a child younger than 14 by a specialist in pediatric (not transferred)
	private static final String[] SEC2_TRANSFER_CODES = {CODE_F20, 	// defines which transfer options are available and their order
														CODE_F21, 
														CODE_F25, 
														CODE_F26, 
														CODE_F27, 
														CODE_F28};
	
	// HOSPITALISATION CODES FOR POST-OPERATION:
	private static final String CODE_F31 = "F31";
	private static final String CODE_F32 = "F32";
	private static final String CODE_F33 = "F33";
	private static final String CODE_F34 = "F34";
	
	// HOSPITALISATION CODES FOR LONG TERM STAY:
	private static final String CODE_F40 = "F40";
	private static final String CODE_F42 = "F42";
	private static final String CODE_F43 = "F43";
	private static final String CODE_F48 = "F48";
	private static final String CODE_F49 = "F49";
	private static final String[] SEC4_TRANSFER_CODES = {	// defines which transfer options are available and their order
		CODE_F40,
		CODE_F42,
		CODE_F43,
		CODE_F48,
		CODE_F49
	};
	
	// HOSPITALISATION CODES FOR INTENSIVE CARE
	private static final String CODE_F51 = "F51"; // 1st & 2nd day of intensive care
	private static final String CODE_F52 = "F52"; // 3rd - 6th day of intensive care
	
	// HOSPITALISATION CODES FOR INTENSIVE CARE FOR ANESTHESISTS
	private static final String CODE_F61 = "F61"; // 1st & 2nd day of intensive care
	private static final String CODE_F62 = "F62"; // from 3rd day of intensive care
	private static final String CODE_F65 = "F65"; // 1st & 2nd day of post operative intensive care 
	private static final String CODE_F66 = "F66"; // from 3rd day of post operative intensive care
	private static final String CODE_F68 = "F68"; // continious anesthesie per day
	private static final String CODE_F69 = "F69"; // post operative per day
	private static final String[] SEC6_TRANSFER_CODES = {	// defines which transfer options are available and their order
		SECTION_61,
		SECTION_62,
		SECTION_63,
		SECTION_64
	};
	
	// HOSPITALISATION CODES FOR REANIMATION AND ANESTHESISTS
	private static final String CODE_F71 = "F71"; // 1st & 2nd day of care
	private static final String CODE_F72 = "F72"; // 3st & 4nd day of care
	private static final String CODE_F73 = "F73"; // from 5rd day of care
	// HOSPITALISATION CODES FOR REANIMATION AND ANESTHESISTS
	private static final String CODE_F75 = "F75"; // 1st & 2nd day of care
	private static final String CODE_F76 = "F76"; // 3st & 4nd day of care
	private static final String CODE_F77 = "F77"; // from 5rd day of care
	private static final String[] SEC7_TRANSFER_CODES = {	// defines which transfer options are available and their order
		SECTION_71,
		SECTION_72
	};
	
	private static final String CODE_F80 = "F80"; 
	
	private static final String CODE_F85 = "F85"; 
	
	private static final String CODE_F90 = "F90"; 
	private static final String CODE_F91 = "F91"; 
	private static final String[] SEC10_TRANSFER_CODES = {	// defines which transfer options are available and their order
		CODE_F90,
		CODE_F91
	};

	static final HashMap<String, String[]>  TRANSFER_CODES = new HashMap<String, String[]>();
	static {
		TRANSFER_CODES.put(SECTION_2, 	SEC2_TRANSFER_CODES);
		TRANSFER_CODES.put(SECTION_4, 	SEC4_TRANSFER_CODES);
		TRANSFER_CODES.put(SECTION_6, 	SEC6_TRANSFER_CODES);
		TRANSFER_CODES.put(SECTION_7, 	SEC7_TRANSFER_CODES);
		TRANSFER_CODES.put(SECTION_10, 	SEC10_TRANSFER_CODES);
	}
			
	private static final String LAYOUT_MAIN_COL = " 5px, fill:400dlu:grow, 5px"; 
	private static final String LAYOUT_MAIN_ROW = " 5px, f:p," +
												  " 5px, f:p," + 	    // TabbedPane
												  "10px, f:p," + 	    // act list headline
												  " 5px, f:150px:g," + 	// act list
												  "10px";

	private static final String ERROR_MSG_PREFIX 	= "<html><b><font color=\"#FF0000\" size=\"4\">"; 
	private static final String WARNING_MSG_PREFIX 	= "<html><b><font color=\"#FF8C00\" size=\"3\">"; 
	
	private static final int[] 	 	COLUMN_WIDTHS 	= new int[] {100, 60, 250};
	private static final boolean[] 	COLUMN_RESIZE 	= new boolean[] {true, true, false};
	
	private static final String		TAB_SETTING		= "billing.hospitalisationPeriod.tab";

	
	/* ======================================== */
	// 		MEMBERS
	/* ======================================== */
	
	private static DateFormat dateFormatter = GECAMedGuiUtils.getDateFormat(false);
	
	private static NomenclatureInterface nomenclatureHandler;
	
	private static HashMap<String, Rate> RATEHASH = new HashMap<String, Rate>();
	private static HashMap<String, RateIndex> CHAPTERHASH = new HashMap<String, RateIndex>();
	
	
	private boolean	initialised		= false;

	
//	private int		selectedSection = SECTION_1;
	
	// components
	private DefaultTableModel 	rates;
	private Vector<String> 		columnIdentifiers;
	private JTable 				rateTable;
	private TableCellRenderer 	cellRenderer;

	private JLabel 				errorLabel;

	private HospitalisationPeriodGeneralTab generalPanel;
	private HospitalisationPeriodReanimationTab reanPanel;
	private JTabbedPane tabs;
	private Physician physician;
	private boolean calculating;
	
	private Timer calculationTimer = new Timer();
	private TimerTask calculationTask;
	private Integer hundredDaysDialogState;
	
//	private HashMap<String, JRadioButton> transferOptions = new HashMap<String, JRadioButton>();
	
	/* ======================================== */
	// 		CONSTRUCTOR
	/* ======================================== */

	public HospitalisationPeriodDialog ()
	{
		super(MainFrame.getInstance(), 
				Translatrix.getTranslationString("HospitalisationPeriodDialog.title"), 
				OK_CANCEL_BUTTON_MODE);
		setResizingOptions(RESIZING_ALL);
		
		columnIdentifiers = new Vector<String>();
		columnIdentifiers.add(Translatrix.getTranslationString("ActListModel.DateHeader"));
		columnIdentifiers.add(Translatrix.getTranslationString("ActListModel.CodeHeader"));
		columnIdentifiers.add(Translatrix.getTranslationString("ActListModel.LabelHeader"));
		

		
		
		/* **************************************** */
		// 		DEFINE THE COMPONENTS
		/* **************************************** */
		
		// ERROR LABEL
		errorLabel = new JLabel();

		// RATE TABLE
		JLabel actListLabel = new JLabel(
				Translatrix.getTranslationString("HospitalisationPeriodDialog.hospitalisationActs"));
		rates 		= new DefaultTableModel();
		
		rates.setDataVector(new Vector<Vector<String>>(), columnIdentifiers);
		rateTable 	= new JTable(rates);
		rateTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		rateTable.getTableHeader().setReorderingAllowed(false);
		rateTable.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
		
		JScrollPane tableScroller = new JScrollPane(rateTable);
		tableScroller.setOpaque(false);
		tableScroller.getViewport().setOpaque(false);
		
		cellRenderer = new RateTableCellRenderer();
		
		/* **************************************** */
		// 		ADD THE COMPONENTS
		/* **************************************** */
		
		CellConstraints cc = new CellConstraints();
		mainPanel.setLayout(new FormLayout(LAYOUT_MAIN_COL, LAYOUT_MAIN_ROW));
		
		int row = 0;
		mainPanel.add(errorLabel, 						cc.xy(2, row+=2));

		tabs = new JTabbedPane();

		// General Panel ------------------------------------------------------------------------------------
		
		generalPanel = new HospitalisationPeriodGeneralTab(this);
		tabs.addTab(Translatrix.getTranslationString("HospitalisationPeriodDialog.generalPanel"), generalPanel);

		// Reanimation Panel ------------------------------------------------------------------------------------
		
		reanPanel = new HospitalisationPeriodReanimationTab(this);
		tabs.addTab(Translatrix.getTranslationString("HospitalisationPeriodDialog.reanimationPanel"), reanPanel);
		
		tabs.setSelectedIndex(0);
		
		mainPanel.add(tabs, 							cc.xy(2, row+=2));
		mainPanel.add(actListLabel, 					cc.xy(2, row+=2));
		mainPanel.add(tableScroller, 					cc.xy(2, row+=2));
		
		Component[] components = mainPanel.getComponents();
		for (Component component : components)
		{
			((JComponent)component).setOpaque(false);
		}

		calcRates(true);
		calculating = false;
		hundredDaysDialogState = null;
		
//		this.pack();
		this.setSize(920, 600);
		this.setLocationRelativeTo(MainFrame.getInstance());
	}
	
	
	/* ======================================== */
	// 		METHODS
	/* ======================================== */
	
//	public void setInvoice (Invoice invoice)
//	{
//		this.invoice = invoice;
//	}
	
	
	public Vector<Vector<Object>> showDialog(Date date)
	{
//		ButtonModel selectedSection;
		
		initialised = false;

		generalPanel.init(date);
		reanPanel.init(null);
		rates.setDataVector(new Vector<Vector<String>>(), columnIdentifiers);

		loadTabSelection();
		
		initialised = true;
		
//		calcRates(true);
		rateTable.validate();
		calculating = false;
		hundredDaysDialogState = null;
		
		// show the dialog
		setVisible(true);
		
		calculating = true;
		
		if (getButtonOption() == OK_OPTION)
		{
			saveTabSelection();
			return getTableData();
		}
		else
		{
//			selectedSection.setSelected(true);
			return null;
		}
	}
	
	
	@SuppressWarnings("unchecked")
	public Vector<Vector<Object>> getTableData ()
	{
		return rates.getDataVector();
	}
	
	/* ======================================== */
	// 		HELP METHODS
	/* ======================================== */
	
	/**
	 * deletes and recalculates the list
	 */
	void calculateRates (final boolean datesChanged)
	{
		if (calculationTask != null) {
			calculationTask.cancel();
		}
		
		calculationTask = new TimerTask() {
			@Override
			public void run() {
				if (calculating) return;
				setWaitCursor(true);
				calcRates(datesChanged);
				calculating = false;
				setWaitCursor(false);
			}
		};
		calculationTimer.schedule(calculationTask, 600);
	}
	
	
	private boolean isSundayHoliday(Calendar day) {
		

		int weekday = day.get(Calendar.DAY_OF_WEEK);
		if (weekday == Calendar.SUNDAY) {
			return true;
		}

		Date d = day.getTime();
		for (NationalHoliday nh : BillingModule.getInstance().getNationalHolidays()) {
			if (DateUtil.isSameDay(nh.getDate(), d)) {
				return true;
			}
		}
		
		return false;
	}
	
	
	
	private void saveTabSelection ()
	{
		String tab = tabs.getSelectedIndex()+"";
		LoginScreen.setMachineSetting(TAB_SETTING, tab);
		
		generalPanel.saveSectionSelection();
		reanPanel.saveSectionSelection();
	}
	
	private void loadTabSelection()
	{
		try {
			String tabSetting = LoginScreen.getMachineSetting(TAB_SETTING);
			tabs.setSelectedIndex(Integer.parseInt(tabSetting));
		} catch (Exception e) {
			
		}
		
		generalPanel.loadSectionSelection();
		reanPanel.loadSectionSelection();
	}
	
	private void setColumnWidth()
	{
		TableColumnModel 	columnModel = rateTable.getColumnModel();
		int 				columnCount = rateTable.getColumnCount();
		TableColumn 		column;
		
		
		for (int i = 0; i < columnCount; i++)
		{
			int w = COLUMN_WIDTHS[i];
			column = columnModel.getColumn(i);
			column.setWidth(w);
			column.setPreferredWidth(w);
			column.setMinWidth(w);
			if (COLUMN_RESIZE[i])
				column.setMaxWidth(w);
		}
	}
	
	
	private String getCode (String section, int day, boolean intensiveCare, int daysInIntensiveCare, int hours)
	{
		String code = null;
		String transferCode = null;
		
		CBItem transferRate = getTransferOption();
		if (transferRate != null) {
			transferCode = transferRate.getCode();
		}
		
	    if (intensiveCare) {
				if (daysInIntensiveCare <= 2)
					return CODE_F51;
				else if (daysInIntensiveCare <= 6)
					return CODE_F52;
				else
					showWarning(Translatrix.getTranslationString("HospitalisationPeriodDialog.intensiveCareLonger6Days"));
	    } else if (section.equals(SECTION_1)) {
				if (day == 1)
					code = CODE_F11;
				else if (day <= 14)
					code = CODE_F12;
				else if (day <= 42)
					code = CODE_F13;
				else
					code = CODE_F14;
		} else if (section.equals(SECTION_2)) {
				if (day == 1)
					code = transferCode;
				else if (day <= 14)
					code = CODE_F22;
				else if (day <= 42)
					code = CODE_F23;
				else
					code = CODE_F24;
		} else if (section.equals(SECTION_3)) {			
				if (day <= 7)
					code = CODE_F31;
				else if (day <= 14)
					code = CODE_F32;
				else if (day <= 42)
					code = CODE_F33;
				else
					code = CODE_F34;
		} else if (section.equals(SECTION_4)) {			
				code = transferCode;
		} else if (section.equals(SECTION_6) && transferCode != null) {		
			if (day == 2 && hours < 24) 
				code = null;
			else if (transferCode.equals(SECTION_61)) {
				if (day <= 2)
					return CODE_F61;
				else 
					return CODE_F62;
			} else if (transferCode.equals(SECTION_62)) {
				if (day <= 2)
					return CODE_F65;
				else
					return CODE_F66;
			} else if (transferCode.equals(SECTION_63)) {
				return CODE_F68;
			} else if (transferCode.equals(SECTION_64)) {
				return CODE_F69;
			} 
		} else if (section.equals(SECTION_7) && transferCode != null) {
			if (day == 2 && hours < 24) 
				code = null;
			else if (transferCode.equals(SECTION_71)) {
				if (day <= 2)
					code = CODE_F71;
				else if (day <= 4)
					code = CODE_F72;
				else
					code = CODE_F73;				
			} else if (transferCode.equals(SECTION_72)) {			
				if (day <= 2)
					code = CODE_F75;
				else if (day <= 4)
					code = CODE_F76;
				else
					code = CODE_F77;
			} 
		} else if (section.equals(SECTION_8)) {			
				code = CODE_F80;
		} else if (section.equals(SECTION_9)) {			
				code = CODE_F85;
		} else if (section.equals(SECTION_10)) {			
				code = transferCode;
		}
		
		return code;
	}
	
	Rate getRate (String code) {
		return getRate(code, null);
	}
	
	private Rate getRate (String code, Date date) {
		if (nomenclatureHandler == null)
			nomenclatureHandler  = (NomenclatureInterface) ManagerFactory.getRemote(NomenclatureBean.class);

		Rate rate = null;
		
		if (date == null) {
			rate = RATEHASH.get(code);
			if (rate == null)
			{
				try {
					rate = nomenclatureHandler.getRateByCode(code, null);
				} catch (Exception e) {
					logger.log(Level.ERROR, e.getMessage(), e);
					return null;
				}
				RATEHASH.put(code, rate);
			}			
		} else {
			try {
				rate = nomenclatureHandler.getRateByCode(code, date);
			} catch (Exception e) {
				logger.log(Level.ERROR, e.getMessage(), e);
				return null;
			}
		}
		return rate;
	}
	
	
	RateIndex getChapter (String code) {
		RateIndex chapter = CHAPTERHASH.get(code);
		if (chapter == null)
		{
			if (nomenclatureHandler == null)
				nomenclatureHandler  = (NomenclatureInterface) ManagerFactory.getRemote(NomenclatureBean.class);
			
			try {
				chapter = nomenclatureHandler.getRateIndexByLabel(code);
			} catch (Exception e) {
				logger.log(Level.ERROR, e.getMessage(), e);
				return null;
			}
			CHAPTERHASH.put(code, chapter);
		}
		return chapter;
	}
	
	private void showError (String errorMessage)
	{
		if (errorMessage == null)
		{
			errorLabel.setVisible(false);
			okButton.setEnabled(true);
		}
		else
		{
			errorLabel.setText(ERROR_MSG_PREFIX + errorMessage);
			errorLabel.setVisible(true);
			okButton.setEnabled(false);
		}
	}
	
	private synchronized void calcRates(boolean datesChanged) {
		if (calculating) return;
		
		calculating = true;
 		
		
		if (!initialised) {
			calculating = false;
			return;
		}
			
		Vector<Vector<Object>> 	data = new Vector<Vector<Object>>();
		Vector<Object> 			dataRow;
		TableColumnModel 		columnModel;
		TableColumn 			column;
		
		// reset Error Label
		showError(null);
		// reset Results
		rates.setDataVector(data, columnIdentifiers);
		
		
		String section = getSection();
		
		if (section == null) {
			calculating = false;
			return;
		}
		
		Calendar hospitalisationStart 	= new GregorianCalendar();
		Calendar hospitalisationEnd 	= new GregorianCalendar();
		Calendar intensiveCareStart 	= new GregorianCalendar();
		Calendar intensiveCareEnd 		= new GregorianCalendar();
		boolean	 intensiveCareSelected  = false;
		Calendar currentDay 			= new GregorianCalendar();
		String 	 error 					= null;
		int		 intensiveDays 			= 0;
		boolean	 intensiveCare;
		Long startTime = null;
		Long endTime = null;
		int hours = 0;
		
		String	 code;
		Rate 	 rate;

		if (datesChanged) hundredDaysDialogState = null;
		
		if (tabs.getSelectedComponent().equals(this.generalPanel)) {
			if (generalPanel.hospitalisationStartDateChooser.getDate() == null || generalPanel.hospitalisationEndDateChooser.getDate() == null) {
				calculating = false;
				return;
			}
			
			intensiveDays = generalPanel.intensiveCareDaysSpentField.getInt();
			
			hospitalisationStart.setTime(generalPanel.hospitalisationStartDateChooser.getDate());
			clearTimeOfCalendar(hospitalisationStart);
			hospitalisationEnd.setTime(generalPanel.hospitalisationEndDateChooser.getDate());
			clearTimeOfCalendar(hospitalisationEnd);
			hospitalisationEnd.add(Calendar.MINUTE, 1);
			intensiveCareSelected = generalPanel.intensiveCarePeriodBox.isSelected();
			
			int days = DateUtil.getDateDiff(generalPanel.hospitalisationEndDateChooser.getDate(), generalPanel.hospitalisationStartDateChooser.getDate());
			
			
			
			if (days < 0)
				// start date of hospitalisation is before the end date
				error = Translatrix.getTranslationString("HospitalisationPeriodDialog.hospitalisationEndBeforeStart");
			else if (days > 100) {
				
					if (hundredDaysDialogState == null) {
						int n = JOptionPane.showConfirmDialog(
								this,
								"You are trying to generate entries for more than 100 days ("+days+") ! Continue?",
								"to many days!",
								JOptionPane.OK_CANCEL_OPTION,
								JOptionPane.WARNING_MESSAGE
								);
						hundredDaysDialogState = n;
					}
					
					if (JOptionPane.CANCEL_OPTION == hundredDaysDialogState) {
						calculating = false;
						return;					
					} 				

					
			} else if (intensiveCareSelected)
			{
				intensiveCareStart.setTime	(generalPanel.intensiveCareStartDateChooser.getDate());
				clearTimeOfCalendar(intensiveCareStart);
				intensiveCareEnd.setTime	(generalPanel.intensiveCareEndDateChooser.getDate());
				clearTimeOfCalendar(intensiveCareEnd);
				
				if (intensiveCareStart.after(intensiveCareEnd))
					// end date of intensive care is before the start date
					error = Translatrix.getTranslationString("HospitalisationPeriodDialog.intensiveCareEndBeforeStart");
				else if (intensiveCareStart.before(hospitalisationStart))
					// start date of intensive care is before the hospitalisation start date
					error = Translatrix.getTranslationString("HospitalisationPeriodDialog.intensiveCareStartBeforeHospitalisationStart");
				else if (intensiveCareEnd.after(hospitalisationEnd))
					// end date of intensive care is after the hospitalisation end date
					error = Translatrix.getTranslationString("HospitalisationPeriodDialog.intensiveCareEndBeforeHospitalisationEnd");
			}
			hours = 24;
		} else if (tabs.getSelectedComponent().equals(this.reanPanel)) {
			if (reanPanel.hospitalisationStartDateChooser.getDate() == null || reanPanel.hospitalisationEndDateChooser.getDate() == null) {
				calculating = false;
				return;
			}
			
			intensiveCareSelected = false;
			hospitalisationStart.setTime(reanPanel.hospitalisationStartDateChooser.getDate());
			hospitalisationStart = reanPanel.hospitalisationStartTimeChooser.getCalendarWithTime(hospitalisationStart);
			startTime = hospitalisationStart.getTimeInMillis();
			clearTimeOfCalendar(hospitalisationStart);

			hospitalisationEnd.setTime(reanPanel.hospitalisationEndDateChooser.getDate());
			hospitalisationEnd = reanPanel.hospitalisationEndTimeChooser.getCalendarWithTime(hospitalisationEnd);
			endTime = hospitalisationEnd.getTimeInMillis();
			clearTimeOfCalendar(hospitalisationEnd);
			
			
			intensiveCareStart.setTime(hospitalisationEnd.getTime());
			intensiveCareEnd.setTime(hospitalisationEnd.getTime());
			
			hours = (int) ((endTime-startTime)/(1000*60*60));
			
			int days = DateUtil.getDateDiff(reanPanel.hospitalisationEndDateChooser.getDate(), reanPanel.hospitalisationStartDateChooser.getDate());
			
			if (days < 0)
				// start date of hospitalisation is before the end date
				error = Translatrix.getTranslationString("HospitalisationPeriodDialog.hospitalisationEndBeforeStart");
			else if (days > 100) {
				if (hundredDaysDialogState == null) {
					int n = JOptionPane.showConfirmDialog(
						    this,
						    "You are trying to generate entries for more than 100 days ("+days+") ! Continue?",
							"to many days!",
						    JOptionPane.OK_CANCEL_OPTION,
						    JOptionPane.WARNING_MESSAGE
						    );
					hundredDaysDialogState = n;
				}
				
				if (JOptionPane.CANCEL_OPTION == hundredDaysDialogState) {
					calculating = false;
					return;					
				} 
			}
			
		} else {
			// maybe other panels
		}
		
		showError(error);
		if (error != null) {
			calculating = false;			
			return;
		}
		
		
		currentDay.setTime(hospitalisationStart.getTime());
		for (int day = 1; currentDay.compareTo(hospitalisationEnd) <= 0; day++)
		{
			if (intensiveCareSelected && currentDay.compareTo(intensiveCareStart) >= 0 && currentDay.compareTo(intensiveCareEnd) <= 0) {
				intensiveDays++;
				intensiveCare = true;
			} else {
				intensiveCare = false;
			}
			
			code = getCode(section, day, intensiveCare, intensiveDays, hours);
			
			if (code == null) {
				currentDay.add(Calendar.DAY_OF_YEAR, 1);
				continue;
			}
			
			rate = null;
			
			// check Sunday / holiday
			if (isSundayHoliday(currentDay)) {
				String weekendCode = code + "1";
				// we need the date here to confirm the code was existing that date
				rate = getRate(weekendCode, currentDay.getTime());
			}
			
			if (rate == null) {
//				rate = getRate(code, currentDay.getTime());
				// no need for the date here
				rate = getRate(code);				
			}
			
			try
			{
				dataRow = new Vector<Object>();
				dataRow.add(InvoiceEditorPanel.getPerformedDateWithDefaultTime(currentDay.getTime()));
				dataRow.add(rate);
				dataRow.add(rate);
				
				if (physician != null) {
					rate.setNonAssignable("PHYSICIANID", physician.getId());
				}
				
				data.add(dataRow);
			}
			catch (Exception e)
			{
				logger.log(Level.ERROR, e.getMessage(), e);
			}
			
			currentDay.add(Calendar.DAY_OF_YEAR, 1);
			
		}
		
		if (startTime != null) {
			Calendar startDate = new GregorianCalendar();
			startDate.setTimeInMillis(startTime);
			if (startDate.get(Calendar.HOUR_OF_DAY) != 0 || startDate.get(Calendar.MINUTE) != 0 ) {
				((Rate)data.get(0).get(1)).setNonAssignable("TIME", startDate.getTime());	
			}
		}
		if (endTime != null ) {
			Calendar endDate = new GregorianCalendar();
			endDate.setTimeInMillis(endTime);
			if (endDate.get(Calendar.HOUR_OF_DAY) != 0 || endDate.get(Calendar.MINUTE) != 0 ) {
				((Rate)data.get(data.size()-1).get(1)).setNonAssignable("TIME", endDate.getTime());							
			}
		}
		
		rates.setDataVector(data, columnIdentifiers);

		columnModel = rateTable.getColumnModel();
		for (int i = 0; i < columnModel.getColumnCount(); i++)
		{
			column = columnModel.getColumn(i);
			column.setCellRenderer(cellRenderer);
		}

		setColumnWidth();
		
		calculating = false;
//		this.pack();
	}
	
	private void showWarning (String warningMessage)
	{
		if (warningMessage == null
				|| errorLabel.isVisible())
			return;
		
		errorLabel.setText(WARNING_MSG_PREFIX + warningMessage);
		errorLabel.setVisible(true);
	}
	
	
	private void clearTimeOfCalendar (Calendar c)
	{
		c.set(Calendar.HOUR_OF_DAY, 12);
		c.set(Calendar.MINUTE, 		0);
		c.set(Calendar.SECOND, 		0);
		c.set(Calendar.MILLISECOND, 0);
	}
	
	
	private String getSection() {
		if (tabs.getSelectedComponent().equals(this.generalPanel)) {
			return generalPanel.sectionList.getSelectedValue();
		} else if (tabs.getSelectedComponent().equals(this.reanPanel)) {
			return reanPanel.sectionList.getSelectedValue();
		} else {
			return null;
		}
	}
	
	private CBItem getTransferOption() {
		if (tabs.getSelectedComponent().equals(this.generalPanel)) {
			return (CBItem) generalPanel.transferOptionBox.getSelectedValue();
		} else if (tabs.getSelectedComponent().equals(this.reanPanel)) {
			return (CBItem) reanPanel.transferOptionBox.getSelectedValue();
		} else {
			return null;
		}
	}
	
	public static String trimDesc(String desc) {
		int length = 115;
		if (desc != null && desc.length() > length) {
			desc = desc.substring(0, length-4) + "...";
		}
		return desc;
	}
	
	class RateTableCellRenderer implements TableCellRenderer, ListCellRenderer<Rate>
	{
		public Component getTableCellRendererComponent(JTable table, Object value,
				boolean isSelected, boolean hasFocus, int row, int column)
		{
			String text;
			
			if (value == null)
				text = "";
			else 
			{
				switch (column)
				{
				case 0:
					text = dateFormatter.format(((Date)value));
					break;

				case 1:
					text = ((Rate)value).getCode();
					break;
					
				case 2:
					text = ((Rate)value).getLabel();
					break;
					
				default:
					logger.log(Level.WARN, "Column must be less than 3, but is " + column);
					return null;
				}
			}
			JLabel cell = new JLabel(text);
			cell.setOpaque(true);
			
			if (isSelected) 		cell.setBackground(GECAMedColors.c_TabSelection);
			else if (row % 2 == 0)  cell.setBackground(GECAMedColors.c_EvenLineBackground);
			else 					cell.setBackground(GECAMedColors.c_OddLineBackground);
			
			return cell;
		}

		public Component getListCellRendererComponent(JList<? extends Rate> list, Rate value, int index, boolean isSelected, boolean cellHasFocus) {

			Rate rate = ((Rate)value);
			
			String text = rate.getCode() + " " + rate.getLabel();
			
			JLabel cell = new JLabel(text);
			cell.setOpaque(true);
			
			if (isSelected) 		cell.setBackground(GECAMedColors.c_TabSelection);
			else if (index % 2 == 0)  cell.setBackground(GECAMedColors.c_EvenLineBackground);
			else 					cell.setBackground(GECAMedColors.c_OddLineBackground);
			
			return null;
		}
	}

	public void setPhysician(Physician phy) {
		this.physician = phy;
	};
	
	
	/**
	 * sets the Mousecursor of the MainFrame to a WaitCursor and Back
	 *
	 * @param on true=waitcursor false=normalcursor
	 */
	public void setWaitCursor(boolean on) {
		if (on) {
			this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
		} else {
			this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
		}
	}
		
}
