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

import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;

import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.event.TreeExpansionEvent;
import javax.swing.event.TreeExpansionListener;
import javax.swing.tree.TreePath;

import lu.tudor.santec.gecamed.core.gui.GECAMedColors;
import lu.tudor.santec.gecamed.core.gui.GECAMedMessage;
import lu.tudor.santec.gecamed.core.gui.MainFrame;
import lu.tudor.santec.gecamed.core.gui.PhysicianListener;
import lu.tudor.santec.gecamed.core.gui.listener.PhysicianListenerRegister;
import lu.tudor.santec.gecamed.core.utils.Logger;
import lu.tudor.santec.gecamed.core.utils.ManagerFactory;
import lu.tudor.santec.gecamed.labo.ejb.entity.beans.ResultStub;
import lu.tudor.santec.gecamed.labo.ejb.session.beans.ResultBean;
import lu.tudor.santec.gecamed.labo.ejb.session.interfaces.ResultInterface;
import lu.tudor.santec.gecamed.labo.gui.LaboModule;
import lu.tudor.santec.gecamed.office.ejb.entity.beans.Physician;

import org.apache.log4j.Level;
import org.jdesktop.swingx.JXTreeTable;
import org.jdesktop.swingx.decorator.HighlighterFactory;

import bizcal.util.DateUtil;

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

public class HistoryPanel extends JPanel implements TreeExpansionListener
	{
	/**
	 * 
	 */
	private HistoryTreeTableModel	m_History;
	private JXTreeTable				m_HistoryTable;
	private JScrollPane				m_HistoryScroller;
	private HistoryRenderer			m_HistoryRenderer;
//	private HistoryNode				m_RootNode;
	private Date					m_Today;
	
	private ResultInterface			m_ResultInterface;

	private static Logger			m_Logger	     = new Logger (HistoryPanel.class);
		
//---------------------------------------------------------------------------
//***************************************************************************
//* Constants	                                                            *
//***************************************************************************
//---------------------------------------------------------------------------

	public static final String	c_OpenLaboResultMessage = "OpenLaboResult";
	
	private static final long serialVersionUID 		= 1L;
	
	private static final int	c_MaxDaySpan 		= 6;
	
	private final static String c_Columns			= 	"3dlu,fill:pref:grow,3dlu";
	
	private final static String c_Rows				=    "3dlu,fill:pref:grow,3dlu";

//---------------------------------------------------------------------------
//***************************************************************************
//* Constructor	                                                            *
//***************************************************************************
//---------------------------------------------------------------------------

public HistoryPanel ()
	{
	MouseAdapter l_DoubleClick;	
		
	this.buildHistoryPanel ();	
	
	m_Today = HistoryNode.stripTime (new Date ());
	m_History.setRoot(this.buildTree());
	m_HistoryTable.setTreeTableModel (m_History);
	
	l_DoubleClick = new MouseAdapter()
		{
    	public void mouseClicked(MouseEvent p_Event)
    		{
    		if (p_Event.getClickCount() == 2)
    			{
    			openSelectedResult (); 
    			}
    		}
    	};

	m_HistoryTable.addMouseListener (l_DoubleClick);
	
	// call update(), when ever the physician is changed
	PhysicianListenerRegister.addPhysicianListener(new PhysicianListener() {
		
		public void physicianChanged(Physician physician) 
		{
			update();
		}
	});
	
	}
	
//---------------------------------------------------------------------------
//***************************************************************************
//* Primitives	                                                            *
//***************************************************************************
//---------------------------------------------------------------------------
/**
 * The private getKeyChainInterface returns an instance of the KeyChainBean
 * session bean. On the first call, the KeyChainBean will actualy be looked up
 * via JNDI. Once it has been found, the reference to the bean will be stored
 * in a private data member. Doing so avoids JNDI lookups on later calls.
 * @return an instance of the KeyChainBean session bean.
 */
//---------------------------------------------------------------------------

private ResultInterface getResultInterface ()
	{
	if (m_ResultInterface != null) return m_ResultInterface;

	try {
		m_ResultInterface = (ResultInterface) ManagerFactory.getRemote(ResultBean.class);
		} 
	catch (Exception p_Exception) 
		{
		m_Logger.log(Level.FATAL, "Failed to lookup ResultInterface!",p_Exception);
		}

	return m_ResultInterface;
	}

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

private Collection <ResultStub> getRecentResults ()
	{
	ResultInterface				l_ResultInterface;
	Date						l_OneWeekAgo;
	Date						l_Tonight;
	Collection <ResultStub>		l_ResultStubs = null;
	
	l_ResultInterface = this.getResultInterface();
	if (l_ResultInterface == null) return null;
	
	l_OneWeekAgo = DateUtil.getDiffDay (m_Today, -c_MaxDaySpan);
	l_Tonight	 = DateUtil.move2Midnight (m_Today);
	
	try	{
		l_ResultStubs = l_ResultInterface.getResultStubsForPhysician (MainFrame.getCurrentPhysician(), 
															  		  l_OneWeekAgo,
															  		  l_Tonight);
		}
	catch (Exception p_Exception)
		{
		m_Logger.log(Level.FATAL, "Failed to fetch Results for current physician!",p_Exception);	
		}
	
	return l_ResultStubs;
	}

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

private void buildHistoryPanel ()
	{
	CellConstraints		l_Constraints;
	FormLayout			l_Layout;	
	int					l_Column;
	
	l_Constraints  	= new CellConstraints();
	l_Layout		= new FormLayout(c_Columns, c_Rows);

	this.setLayout (l_Layout);

	m_History = new HistoryTreeTableModel ();	
	
	m_HistoryTable  = new JXTreeTable();
    m_HistoryTable.setRootVisible(false);
    m_HistoryScroller = new JScrollPane (m_HistoryTable);
	    
    m_HistoryTable.setTreeCellRenderer (new HistoryTreeCellRenderer ());
	
 	m_HistoryRenderer = new HistoryRenderer ();
	
	for (l_Column=0; l_Column < m_History.getColumnCount(); l_Column++)
		{
    	switch (l_Column)
    		{
			case HistoryTreeTableModel.c_PatientNameColumn:
			case HistoryTreeTableModel.c_PatientSSNColumn:
			case HistoryTreeTableModel.c_LaboratoryColumn:
			case HistoryTreeTableModel.c_ExaminationDateColumn:
			case HistoryTreeTableModel.c_ExaminationStatusColumn:
			case HistoryTreeTableModel.c_ResultStatusColumn:
								
				if (m_History.getColumnClass(l_Column) != null)	
					m_HistoryTable.setDefaultRenderer (m_History.getColumnClass(l_Column), m_HistoryRenderer);
    		}
		}

	m_HistoryTable.setHighlighters(HighlighterFactory.createAlternateStriping(
    							 GECAMedColors.c_EvenLineBackground, 
    							 GECAMedColors.c_OddLineBackground));
	
    this.add (m_HistoryScroller,    l_Constraints.xywh(2, 2, 1, 1));
	}

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

private HistoryNode buildTree ()
	{
	HistoryNode				  l_RootNode;
	HistoryNode				  l_NodeOfDay;
	HistoryNode				  l_ResultNode;
	Collection <ResultStub>	  l_Results;
	Iterator <ResultStub>	  l_ResultIterator;
	ResultStub				  l_Result;
	int						  l_Day;
	HistoryNode []			  l_HistoryNodes;
	
	l_RootNode = new HistoryNode ();
	
	l_HistoryNodes = new HistoryNode [c_MaxDaySpan];
	
	for (l_Day = 0; l_Day < c_MaxDaySpan; l_Day++)
		{
		l_HistoryNodes [l_Day] = new HistoryNode ();
		// TODO: '-' ???
		l_HistoryNodes [l_Day].setDay(DateUtil.getDiffDay(m_Today, -l_Day));
		}
	
	l_Results = this.getRecentResults();
	if (l_Results != null)
		{
		l_ResultIterator = l_Results.iterator();
		while (l_ResultIterator.hasNext())
			{
			l_Result = l_ResultIterator.next();
			
			l_ResultNode = new HistoryNode ();
			l_ResultNode.setResultStub(l_Result);
				
			l_Day    = DateUtil.getDateDiff(m_Today, HistoryNode.stripTime(l_Result.getDownloaded()));
			
			if (l_Day < c_MaxDaySpan) 
				{
				l_NodeOfDay = l_HistoryNodes [l_Day];
				l_NodeOfDay.add( l_ResultNode );
				}
			}
		}

	for (l_Day = 0; l_Day < c_MaxDaySpan; l_Day++)
		{
		l_NodeOfDay = l_HistoryNodes [l_Day];	
		if (l_NodeOfDay.getChildCount() > 0) l_RootNode.add(l_NodeOfDay); 
		}
	
	return 	l_RootNode;
	}

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

private HistoryNode getSelectedNode ()
	{
	HistoryNode			l_Node;
	TreePath			l_SelectionPath;
	int		 			l_SelectedRow;

	l_SelectedRow = m_HistoryTable.getSelectedRow();
	if (l_SelectedRow < 0) return null;
		
	l_SelectionPath = m_HistoryTable.getPathForRow (l_SelectedRow);
	l_Node = (HistoryNode) l_SelectionPath.getLastPathComponent();
		
	return l_Node;
	}
//---------------------------------------------------------------------------
//***************************************************************************
//* Class Body	                                                            *
//***************************************************************************
//---------------------------------------------------------------------------

public void openSelectedResult ()
	{
	HistoryNode		l_Node;
	ResultStub		l_ResultStub;
	GECAMedMessage	l_Message;
	
	l_Node = this.getSelectedNode();
	if (l_Node != null && l_Node.isLeaf())
		{
		l_ResultStub = l_Node.getResultStub();	
		
		l_Message = new GECAMedMessage (LaboModule.getInstance(), c_OpenLaboResultMessage, null, l_ResultStub);
		MainFrame.fireGECAMedMessage(l_Message);
		}
	}

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

public void update ()
	{
	m_Today = HistoryNode.stripTime (new Date ());
	
	m_History = new HistoryTreeTableModel ();
	m_History.setRoot(this.buildTree());
	m_HistoryTable.setTreeTableModel (m_History);
	m_HistoryTable.expandRow(m_History.getRowCount() - 1);
	m_HistoryTable.validate();
	}

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

public void treeCollapsed (TreeExpansionEvent p_ExpansionEvent)

	{
	// TODO Auto-generated method stub	
	}

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

public void treeExpanded (TreeExpansionEvent p_ExpansionEvent)
	{
	// TODO Auto-generated method stub	
	}

//---------------------------------------------------------------------------
//***************************************************************************
//* End of Class                                                            *
//***************************************************************************
//---------------------------------------------------------------------------
	}
