package lu.tudor.santec.gecamed.patient.gui.history.table;

/*******************************************************************************
 * 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
 *******************************************************************************/

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Collection;

import javax.swing.Action;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.JToggleButton;
import javax.swing.border.Border;
import javax.swing.text.BadLocationException;

import lu.tudor.santec.gecamed.core.gui.GECAMedColors;
import lu.tudor.santec.gecamed.core.gui.GECAMedIconNames;
import lu.tudor.santec.gecamed.core.gui.GECAMedModule;
import lu.tudor.santec.gecamed.core.gui.IconFetcher;
import lu.tudor.santec.gecamed.core.gui.MainFrame;
import lu.tudor.santec.gecamed.core.gui.listener.EntryTypeRegister;
import lu.tudor.santec.gecamed.core.gui.listener.IEntryTypeHandler;
import lu.tudor.santec.gecamed.core.gui.utils.ComponentTitledPanel;
import lu.tudor.santec.gecamed.core.gui.utils.IChangeListener;
import lu.tudor.santec.gecamed.core.gui.widgets.ErrorDialog;
import lu.tudor.santec.gecamed.core.gui.widgets.GECAMedBaseDialogImpl;
import lu.tudor.santec.gecamed.patient.ejb.entity.beans.Incident;
import lu.tudor.santec.gecamed.patient.ejb.entity.beans.IncidentEntry;
import lu.tudor.santec.gecamed.patient.gui.PatientManagerModule;
import lu.tudor.santec.gecamed.patient.gui.PatientPanel;
import lu.tudor.santec.i18n.Translatrix;

import org.apache.log4j.Logger;

import com.l2fprod.gui.border.LineBorder;

/**
 * Cointains the JTable that displays all HistoryElements of the current patient.
 * HE can be any thing that is stored in an IncidentEntry object as well as measurements and
 * prescriptions.
 * We can open a consultation in the incident form by this table and in the future available plugins for
 * stored files are called to handle the selected file, e.g. showing or modifying.
 * 
 * 
 * @author martin.heinemann@tudor.lu
 * 21.01.2008
 * 15:42:06
 *
 *
 * @version
 * <br>$Log: HistoryTablePanel.java,v $
 * <br>Revision 1.39  2014-02-17 14:04:31  ferring
 * <br>Editing file entries by clicking removed, context menu option to edit description and file name added instead
 * <br>
 * <br>Revision 1.38  2013-09-30 10:42:43  ferring
 * <br>error logging added and dialog will be created only once
 * <br>
 * <br>Revision 1.37  2013-09-04 15:33:26  troth
 * <br>The new consultation view with more entries and the sickleave version 2 history view work now.
 * <br>
 * <br>Revision 1.36  2013-02-28 13:19:42  ferring
 * <br>If a module for a history entry is not loaded, a message is shown telling the user and providing the option to delete this entry
 * <br>
 * <br>Revision 1.35  2013-02-05 13:15:18  ferring
 * <br>letter status added
 * <br>
 * <br>Revision 1.34  2012-03-13 12:11:22  ferring
 * <br>Form types are now separated by the code column in of the table incident_entry
 * <br>
 * <br>Revision 1.33  2010-08-24 12:49:40  troth
 * <br>fix small bug - to open consultation over the accident entry in the patient history
 * <br>
 * <br>Revision 1.32  2010-08-16 14:32:04  troth
 * <br>Incomplete - # 599: Keep prescription history stable when consultation tabs are clicked
 * <br>http://santec.tudor.lu/trac/gecamed/ticket/599
 * <br>
 * <br>Revision 1.31  2010-07-22 09:47:12  troth
 * <br>removed system.out.println
 * <br>
 * <br>Revision 1.30  2010-07-20 14:18:49  troth
 * <br>add function for colored the line of the open prescription entry in the history table
 * <br>
 * <br>Revision 1.29  2010-06-16 08:11:53  troth
 * <br>Bug Fix - # 515: Erzeugen eines �berfl�ssigen Konsultations-Tab
 * <br>http://santec.tudor.lu/trac/gecamed/ticket/515
 * <br>
 * <br>Revision 1.28  2010-04-26 16:40:00  troth
 * <br>Redesign of the prescription view
 * <br>
 * <br>Revision 1.27  2008-10-21 09:53:34  hermen
 * <br>fixed patient slot bug
 * <br>enhanced logging
 * <br>code cleanup
 * <br>
 * <br>Revision 1.26  2008-09-25 09:43:08  heinemann
 * <br>fixed copyrights
 * <br>
 * <br>Revision 1.25  2008-07-03 11:59:57  heinemann
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.24  2008-04-15 16:01:03  heinemann
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.23  2008-04-11 14:47:41  heinemann
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.22  2008-04-10 14:19:30  heinemann
 * <br>added original filename o the IncidentEntry table.
 * <br>differs to filename which is the generated name of the timestamp+originalfilename
 * <br>
 * <br>Revision 1.21  2008-04-10 12:25:42  heinemann
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.20  2008-04-09 12:53:59  heinemann
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.19  2008-04-09 09:39:43  heinemann
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.18  2008-03-20 16:08:14  heinemann
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.17  2008-03-12 12:33:26  heinemann
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.16  2008-03-12 10:14:07  heinemann
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.15  2008-03-06 15:34:26  heinemann
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.14  2008-01-22 13:51:52  heinemann
 * <br>code cleanup and java doc
 * <br>
 *    
 */
public class GenericTablePanel extends JPanel implements ActionListener, IChangeListener {

	/** the logger Object for this class */
	private static Logger logger = Logger.getLogger(HistoryTablePanel.class.getName());
	
	private static final long serialVersionUID = 1L;
	
	public static final int	EOF_DEFAULT				= -1;
	public static final int EOF_MODULE_NOT_LOADED	= 1;
	public static final int	EOF_ENTRY_NOT_FOUND		= 2;
	public static final int	EOF_FILE_NOT_FOUND		= 3;
	public static final int	EOF_COULDNT_WRITE_FILE	= 4;

//	private static DateFormat incidentFormater = DateFormat
//			.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM,
//					Translatrix.getLocale());

	private JTable table;

	private HistoryTableModel model;
	
//	private PatientPanel patientPanel;

	private JMenuItem openItem;

	private JToggleButton linkButton;

	private ComponentTitledPanel compTitlePanel;
	
	private HistoryTableRenderer renderer;
	
	private JScrollPane scrollPane;
	
	private NoHandlerForEntryDialog	noHandlerDialog;

	
	/**
	 * ------------@param patientPanel
	 */
	public GenericTablePanel(PatientPanel patientPanel) 
	{
		this(patientPanel, true);
	}
	
	
	/**
	 * @param patientPanel
	 * @param useCompountBorder
	 */
	public GenericTablePanel(PatientPanel patientPanel, boolean useCompountBorder) 
	{
		this (patientPanel, useCompountBorder, new HistoryTableModel(patientPanel.getHistoryDataAgent()));
	}
	
	
	public GenericTablePanel(PatientPanel patientPanel, boolean useCompountBorder, HistoryTableModel historyTableModel)
	{
		this.setOpaque(false);
		this.setLayout(new BorderLayout());
//		this.patientPanel = patientPanel;
		this.table = new JTable();
		this.scrollPane = new JScrollPane(this.table);

		JPanel panel = new JPanel(new BorderLayout(5,0));
		panel.setOpaque(false);

		JLabel l = new JLabel(Translatrix.getTranslationString("patient.history") + " ");
		l.setOpaque(true);
		l.setBackground(GECAMedColors.c_GECAMedBackground);
		l.setPreferredSize(new Dimension((int)l.getPreferredSize().getWidth(),20));

		panel.add(l);
		/* ------------------------------------------------------- */
		scrollPane.getViewport().setBackground(GECAMedColors.c_ScrollPaneBackground);
		scrollPane.setAutoscrolls(true);
		//jsp.getHorizontalScrollBar()
		
		/* ------------------------------------------------------- */
		if (useCompountBorder) {
			/* ------------------------------------------------------- */
			// buttons to filter the history table

			// show only linked consultations
			this.linkButton = new JToggleButton(IconFetcher.getSmallIcon(PatientManagerModule.class, PatientManagerModule.LINK));

			linkButton.setToolTipText(Translatrix.getTranslationString("patient.history.filterLinked"));
			linkButton.addActionListener(this);
			linkButton.setMargin(new java.awt.Insets(0,0,0,0));

			panel.add(linkButton, BorderLayout.EAST);


			this.compTitlePanel = new ComponentTitledPanel(new LineBorder(GECAMedColors.c_GECAMedTitledBorder), panel, scrollPane);

			this.add(compTitlePanel);
			/* ------------------------------------------------------- */
		} else {
			/* ------------------------------------------------------- */
			table.setTableHeader(null);
			this.add(scrollPane);
			/* ------------------------------------------------------- */
		}

		
//		model = new HistoryTableModel(patientPanel.getHistoryDataAgent());
		this.model = historyTableModel;
		patientPanel.getHistoryDataAgent().addUpdateListener(this);
//		model = this.patientPanel.getHistoryTableModel();
		table.setModel(model);
		table.getColumnModel().getColumn(0).setMaxWidth(60);
		table.getColumnModel().getColumn(0).setMinWidth(60);
		table.getColumnModel().getColumn(1).setMaxWidth(30);
		table.getColumnModel().getColumn(1).setMinWidth(30);
		table.getColumnModel().getColumn(2).setMaxWidth(50);
		if (table.getColumnCount() >= 5)
		{
			table.getColumnModel().getColumn(4).setMinWidth(0);
			table.getColumnModel().getColumn(4).setMaxWidth(0);
		}

		renderer = new HistoryTableRenderer(model);

		table.getColumnModel().getColumn(0).setCellRenderer(renderer);
		table.getColumnModel().getColumn(1).setCellRenderer(renderer);
		table.getColumnModel().getColumn(2).setCellRenderer(renderer);
		table.getColumnModel().getColumn(3).setCellRenderer(renderer);

		table.setShowGrid(false);
		table.setShowVerticalLines(true);
		/* ------------------------------------------------------- */

		initTableMouseListener();
		
		
		table.setDragEnabled(true);
		/* ------------------------------------------------------- */
		
//		FileEntryCellEditor cellEditor = new FileEntryCellEditor();
//		
//		table.getColumnModel().getColumn(3).setCellEditor(cellEditor);
		/* ================================================== */
	}
	
	/* (non-Javadoc)
	 * @see javax.swing.JComponent#setBorder(javax.swing.border.Border)
	 */
	@Override
	public void setBorder(Border border) {
		/* ================================================== */
		if (compTitlePanel != null)
			compTitlePanel.setBorder(border);
		/* ================================================== */
	}
	
	/**
	 * @return the model
	 */
	public HistoryTableModel getModel() {
		return model;
	}


	/**
	 * returns the incident for the selected row
	 * 
	 * @return
	 */
	public Incident getSelectedIncident() {
		/* ================================================== */
		return this.model.getIncidentByRow(table.getSelectedRow());
		/* ================================================== */
	}
	
	
	
	/* (non-Javadoc)
	 * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
	 */
	public void actionPerformed(ActionEvent e) {
		if (e.getSource().equals(this.linkButton)) {
			/* ------------------------------------------------------- */
			if (!linkButton.isSelected())
				model.setFilterIncident(null);
			else {
				/* ------------------------------------------------------- */
				try {
					int row = table.getSelectedRow();
					if (row > -1)
						model.setFilterIncident(model.getIncidentByRow(row));
					else
						model.setFilterIncident(null);
				} catch (Exception e1) {
					logger.error("Error while filtering table", e1);
				}
				/* ------------------------------------------------------- */
			}
			/* ------------------------------------------------------- */
		}
	}


	/**
	 * 
	 */
	private void initTableMouseListener() {
		/* ============================================= */
		this.openItem = new JMenuItem(Translatrix
				.getTranslationString("patient.incident.open"), GECAMedModule
				.getSmallIcon(GECAMedIconNames.OPEN));
		/* ------------------------------------------------------ */
		openItem.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				/* ============================================= */
				openConsultation();
				/* ============================================= */
			}
		});
		
		MouseAdapter popupListener = new HistoryMouseListener();
		table.addMouseListener(popupListener);
		/* ============================================= */
	}
	
	
	/**
	 * @param row
	 */
	private boolean openEntry (int row) {
		/* ================================================== */
		IncidentEntry entry = (IncidentEntry) model.getValueAt(row, 2);
		/* ------------------------------------------------------- */
		// check if there is an entry type
		// no type, no file open
		/* ------------------------------------------------------- */
		if (entry == null || entry.getEntryType() == null)
			return false;
		
		IEntryTypeHandler handler = EntryTypeRegister.getHandler(entry.getEntryType().getName());
		if (handler == null)
			return HistoryTablePanel.showEntryNotOpenedDialog(HistoryTablePanel.EOF_MODULE_NOT_LOADED, null, entry);
		else
			return handler.openEntry(entry);
	}
	
	
	protected void openConsultation() {
		int row = table.getSelectedRow();
		IncidentEntry entry = model.getIncidentEntry(row);
		PatientManagerModule.getInstance().getPatientPanel().openConsultation(entry);
	}
	
	
	public void updateTable() {
		/* ================================================== */
		this.table.revalidate();
		/* ================================================== */
	}
	
	public JScrollPane getScrollPane() {
		return this.scrollPane;
	}
	
	
	
	/** 
	  * Gibt die Anzahl der (gewrappten) Zeilen zurück. 
	  * @param area 
	  * @return 
	  * @throws BadLocationException 
	  * 
	  * @creditz <a href="http://groups.google.de/group/de.comp.lang.java/browse_thread/thread/7b2a34a94ab77fb7/400946ff25b241a4?lnk=st&q=JTextArea+getRows+&rnum=10&hl=de#400946ff25b241a4">
	  * de.comp.lang.java</a>
	  */ 
	public static int getLineCount(JTextArea area) 
	        throws BadLocationException { 
	        String text = area.getText(); 
	        int len = text.length(); 
	        int line = area.getLineOfOffset(len); 
	        return line+1; 

	}
	
	
	public void fireEvent() {
		/* ====================================================== */
		model.fireTableDataChanged();
		/* ====================================================== */
	}
	
	
	public void highlightEntry(IncidentEntry incidentEntry) {
		if (incidentEntry != null && incidentEntry.isPersistent()){
			
			this.renderer.setOpenIncidentEntryId(incidentEntry.getId());
		}else{
			this.renderer.setOpenIncidentEntryId(-1);
			
		}
	}
	
	
	
	/* ======================================== */
	// 		CLASS: HistoryMouseListener
	/* ======================================== */
	
	class HistoryMouseListener extends MouseAdapter
	{
		/* ======================================== */
		// 		MEMBERS
		/* ======================================== */
		
		private JPopupMenu popup;
		
		
		
		/* ======================================== */
		// 		CONSTRUCTORS
		/* ======================================== */
		
		public HistoryMouseListener()
		{
			// init the popup
			this.popup = new JPopupMenu();
			this.popup.setBackground(GECAMedColors.c_GECAMedBackground);

			popup.add(openItem);
		}
		
		
		
		/* ======================================== */
		// 		LISTENER METHODS
		/* ======================================== */
		
		@Override
		public void mouseClicked(MouseEvent e)
		{
			if (e.getClickCount() == 1 && GenericTablePanel.this.linkButton != null && GenericTablePanel.this.linkButton.isSelected() && !model.isFiltered())
			{
				model.setFilterIncident(model.getIncidentByRow(table.rowAtPoint(e.getPoint())));
			}
			else if (e.getClickCount() == 2 && !e.isPopupTrigger())
			{
				if (!openEntry(table.rowAtPoint(e.getPoint())))
					HistoryTablePanel.showEntryNotOpenedDialog(HistoryTablePanel.EOF_DEFAULT, null, null);
				
				e.consume();
			}
		}
		
		
		@Override
		public void mousePressed(MouseEvent e)
		{
			clicked(e);
		}
		
		
		@Override
		public void mouseReleased(MouseEvent e)
		{
			clicked(e);
		}
		
		
		private void clicked(MouseEvent e)
		{
			IEntryTypeHandler	handler;
			JPopupMenu			popup;
			Collection<Action>	actions;
			IncidentEntry		entry;
			int					row;
			JMenuItem			item;
			
			
			if (e.isPopupTrigger())
			{
				row = table.rowAtPoint(e.getPoint());
				
				table.getSelectionModel().setSelectionInterval(row, row);
				
				entry = (IncidentEntry) model.getValueAt(row, 2);
				/* ------------------------------------------------------- */
				// check if there is an entry type
				// no type, no file open
				/* ------------------------------------------------------- */
				if (entry == null || entry.getEntryType() == null)
					return;
				
//				entry = ((IncidentManager)ManagerFactory.getRemote(IncidentManagerBean.class)).getIncidentEntry(entry.getId());
				
				try
				{
					handler = EntryTypeRegister.getHandler(entry.getEntryType().getName());
					
					if (handler == null)
					{
						if (noHandlerDialog == null)
							noHandlerDialog	= new NoHandlerForEntryDialog();
						noHandlerDialog.setEntry(entry);
						noHandlerDialog.setVisible(true);
						return;
					}
					
					popup	= handler.getPopup(entry);
					if (popup == null)
					{
						popup	= this.popup;
						popup.removeAll();
						
						actions = handler.getActions(entry);
						if (actions != null)
							for (Action a : actions)
							{
								item	= new JMenuItem(a);
								item.setOpaque(false);
								popup.add(item);
							}
						
					}
				}
				catch (Exception e2)
				{
					e2.printStackTrace();
					return;
				}
				popup.show(table, e.getX(), e.getY());
			}
		}
	}
	
	
	public static boolean showEntryNotOpenedDialog (int reason, Exception exeption, IncidentEntry entry)
	{
		String message;
		
		
		switch (reason)
		{
			case EOF_MODULE_NOT_LOADED:
				message	= Translatrix.getTranslationString("history.openEntry.moduleNotLoaded");
				break;
				
			case EOF_ENTRY_NOT_FOUND:
				message	= Translatrix.getTranslationString("history.openEntry.entryNotFound");
				break;
				
			case EOF_FILE_NOT_FOUND:
				message	= Translatrix.getTranslationString("history.openEntry.fileNotFound");
				break;
				
			case EOF_COULDNT_WRITE_FILE:
				message	= Translatrix.getTranslationString("history.openEntry.couldntWriteFile");
				break;
				
			case EOF_DEFAULT:
				message	= Translatrix.getTranslationString("history.openEntry.failed");
				break;
				
			default:
				return false;
		}
		
		if (exeption != null)
			ErrorDialog.showErrorDialog(
					MainFrame.getInstance(), 
					Translatrix.getTranslationString("history.openEntry.failedTitle"), 
					message, 
					exeption);
		else
			GECAMedBaseDialogImpl.showMessageDialog(
					MainFrame.getInstance(), 
					Translatrix.getTranslationString("history.openEntry.failedTitle"), 
					message, 
					GECAMedBaseDialogImpl.OK_BUTTON_MODE, 
					GECAMedModule.getScaledIcon(GECAMedIconNames.ERROR, 48));
		
		// return true, to not show one more error dialog
		return true;
	}
}
