/*******************************************************************************
 * 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.hl7import.ejb.mdb.beans;

import java.util.Collection;
import java.util.Iterator;
import java.util.Properties;

import javax.annotation.PostConstruct;
import javax.ejb.ActivationConfigProperty;
import javax.ejb.EJB;
import javax.ejb.MessageDriven;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;

import lu.tudor.santec.gecamed.core.ejb.session.interfaces.ListManagerInterface;
import lu.tudor.santec.gecamed.core.utils.ManagerFactory;
import lu.tudor.santec.gecamed.hl7import.ejb.entity.beans.HL7Admission;
import lu.tudor.santec.gecamed.hl7import.ejb.entity.beans.HL7Observation;
import lu.tudor.santec.gecamed.hl7import.ejb.entity.beans.HL7Order;
import lu.tudor.santec.gecamed.hl7import.ejb.session.beans.AdmissionBean;
import lu.tudor.santec.gecamed.hl7import.ejb.session.beans.ObservationBean;
import lu.tudor.santec.gecamed.hl7import.ejb.session.beans.OrderBean;
import lu.tudor.santec.gecamed.hl7import.ejb.session.interfaces.AdmissionInterface;
import lu.tudor.santec.gecamed.hl7import.ejb.session.interfaces.ObservationInterface;
import lu.tudor.santec.gecamed.hl7import.ejb.session.interfaces.OrderInterface;

import org.apache.log4j.Category;
import org.apache.log4j.Level;

//***************************************************************************
//* Class Definition                                                        *
//***************************************************************************


@MessageDriven(activationConfig =
{
  @ActivationConfigProperty(propertyName = "destinationType", 	propertyValue="javax.jms.Queue"),
  @ActivationConfigProperty(propertyName = "destination",		propertyValue="queue/gecamed"),
  @ActivationConfigProperty(propertyName = "acknowledgeMode", 	propertyValue = "AUTO_ACKNOWLEDGE"),
// @ActivationConfigProperty(propertyName="maxPoolSize",         propertyValue="1"), 
  @ActivationConfigProperty(propertyName = "maxSession", 		propertyValue = "1")
 })

//@Depends ({"gecamed:service=AdmissionBean", 
//	       "gecamed:service=OrderBean", 
//	       "gecamed:service=ObservationBean"}) 
 
public class GECAMedMarshal implements MessageListener
	{
	
	@EJB
	private AdmissionInterface		m_AdmissionInterface;
	
	@EJB
	private OrderInterface			m_OrderInterface;
	
	@EJB
	private ObservationInterface	m_ObservationInterface;
	
	@EJB 
	private ListManagerInterface	m_ListManagerInterface;
	
	private Collection <HL7Admission>		m_Admissions   = null;
	private Collection <HL7Order>			m_Orders 	   = null;
	private Collection <HL7Observation>		m_Observations = null;

	
	
	
	
	private Properties				m_ServerProperties;
	
	private static final Category m_Logger = Category.getInstance(GECAMedMarshal.class.getName());
	
//---------------------------------------------------------------------------
//***************************************************************************
//* Constructor(s)                                                          *
//***************************************************************************
//---------------------------------------------------------------------------
	    
@PostConstruct
public void postConstruct ()
	{
	
	if (m_ListManagerInterface != null)
		{
		try {
			m_ServerProperties = m_ListManagerInterface.getServerInfos();
			} 
		catch (Exception p_Exception) 
			{
			this.log(Level.WARN, "Failed to retriever Server Infos!",p_Exception);
			}
		}	
	}

//--------------------------------------------------------------------------- 
//***************************************************************************
//* Primitives		                                       					*
//***************************************************************************

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

private void log (Level p_Level, String p_Message)
	{
	this.log(p_Level,p_Message,null);
	}

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

private void log (Level p_Level, String p_Message, Exception p_Exception)
	{
	if (p_Exception != null) m_Logger.log (p_Level,p_Message,p_Exception);
						else m_Logger.log (p_Level,p_Message);
	}

//---------------------------------------------------------------------------
 
private AdmissionInterface getAdmissionInterface ()
	{
	if (m_AdmissionInterface != null) return m_AdmissionInterface;

	try {
		m_AdmissionInterface = (AdmissionInterface) ManagerFactory.getLocal(AdmissionBean.class);

//		InitialContext l_Context = new InitialContext();
//		m_AdmissionInterface = (AdmissionInterface) l_Context.lookup("AdmissionBean/local");
//		l_Context.close();
		} 
	catch (Exception p_Exception) 
		{
		this.log (Level.FATAL,"Failed to get AdmissionInterface",p_Exception);
		}

	return m_AdmissionInterface;
	}

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

private OrderInterface getOrderInterface ()
	{
	if (m_OrderInterface != null) return m_OrderInterface;

	try {
		m_OrderInterface = (OrderInterface) ManagerFactory.getLocal(OrderBean.class);

//		InitialContext l_Context = new InitialContext();
//		m_OrderInterface = (OrderInterface) l_Context.lookup("OrderBean/local");
//		l_Context.close();
		} 
	catch (Exception p_Exception) 
		{
		this.log (Level.FATAL,"Failed to get OrderInterface",p_Exception);
		}

	return m_OrderInterface;
	}

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

private ObservationInterface getObservationInterface ()
	{
	if (m_ObservationInterface != null) return m_ObservationInterface;

	try {
		m_ObservationInterface = (ObservationInterface) ManagerFactory.getLocal(ObservationBean.class);
		
//		InitialContext l_Context = new InitialContext();
//		m_ObservationInterface = (ObservationInterface) l_Context.lookup("ObservationBean/local");
//		l_Context.close();
		} 
	catch (Exception p_Exception) 
		{
		this.log (Level.FATAL,"Failed to get ObservationInterface",p_Exception);
		}

	return m_ObservationInterface;
	}

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

private Collection <HL7Admission> fetchAdmissions ()
	{
	AdmissionInterface				l_AdmissionInterface;
	Collection <HL7Admission>		l_Admissions = null;
	
	m_Logger.info("Fetching Admissions (ADT Messages)....");
	
	l_AdmissionInterface = this.getAdmissionInterface();
	if (l_AdmissionInterface != null)
		{
		try	{		
			l_Admissions = l_AdmissionInterface.getAllAdmissions();
			}
		catch (Exception p_Exception)
			{
			this.log (Level.FATAL,"Failed to fetch Admissions!",p_Exception);
			}
		}
	
	return l_Admissions;
	}

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

private Collection <HL7Order> fetchOrders ()
	{
	OrderInterface					l_OrderInterface;
	Collection <HL7Order>			l_Orders = null;
	
	m_Logger.info("Fetching Orders (ORM Messages)....");
	
	l_OrderInterface = this.getOrderInterface();
	if (l_OrderInterface != null)
		{
		try	{		
			l_Orders = l_OrderInterface.getAllOrders();
			}
		catch (Exception p_Exception)
			{
			this.log (Level.FATAL,"Failed to fetch Orders!",p_Exception);
			}
		}
	
	return l_Orders;
	}

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

private Collection <HL7Observation> fetchObservations ()
	{
	ObservationInterface			l_ObservationInterface;
	Collection <HL7Observation>		l_Observations = null;
	
	m_Logger.info("Fetching Observations (ORU Messages)....");
	
	l_ObservationInterface = this.getObservationInterface();
	if (l_ObservationInterface != null)
		{
		try	{		
			l_Observations = l_ObservationInterface.getAllObservations();
			}
		catch (Exception p_Exception)
			{
			this.log (Level.FATAL,"Failed to fetch Observations!",p_Exception);
			}
		}
	
	return l_Observations;
	}

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

@TransactionAttribute (TransactionAttributeType.REQUIRES_NEW)
private void fetchHL7Data ()
	{	
	m_Observations = this.fetchObservations();
	m_Orders       = this.fetchOrders();
	m_Admissions   = this.fetchAdmissions();	
	}

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

private void disposeHL7Data ()
	{
	if (m_Observations != null) m_Observations.clear();
	if (m_Orders != null) m_Orders.clear();
	if (m_Admissions != null) m_Admissions.clear();		
	}

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

private void processAdmissions ()
	{
	AdmissionInterface				l_AdmissionInterface;
//	Collection <HL7Admission>		l_Admissions;
	Iterator	 <HL7Admission>		l_AdmissionIterator;	
	HL7Admission					l_CurrentAdmission	= null;
	
	m_Logger.info("Processing Admissions (ADT Messages)....");
	
	l_AdmissionInterface = this.getAdmissionInterface();
	if (l_AdmissionInterface != null)
		{
		try	{		
//			l_Admissions = l_AdmissionInterface.getAllAdmissions();
		
			if ((m_Admissions != null) && (m_Admissions.size() > 0))
				{
				m_Logger.info("Processing " + m_Admissions.size() + " Admissions");
				l_AdmissionIterator = m_Admissions.iterator();
				
				while (l_AdmissionIterator.hasNext())
					{
					l_CurrentAdmission = l_AdmissionIterator.next();
					try	{
						l_AdmissionInterface.processAdmission (l_CurrentAdmission);		
						}
					catch (Exception p_Exception)
						{
						this.log(Level.WARN,"Uncaught Exception from AdmissionBean for Message with Control ID " + l_CurrentAdmission.getControlId(), p_Exception);
						}
					}
				}
			}
		catch (Exception p_Exception)
			{
			this.log(Level.FATAL,"Failed to retrieve Admissions",p_Exception);
			}
		}
	}

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

private void processOrders ()
	{
	OrderInterface					l_OrderInterface;
//	Collection <HL7Order>			l_Orders;
	Iterator   <HL7Order>			l_OrderIterator;
	HL7Order						l_CurrentOrder 	= null;

	m_Logger.info("Processing Orders (ORM Messages)....");

	l_OrderInterface = this.getOrderInterface();
	if (l_OrderInterface != null)
		{
		try	{		
//			l_Orders = l_OrderInterface.getAllOrders();
		
			if ((m_Orders != null) && (m_Orders.size() > 0))
				{
				m_Logger.info("Processing " + m_Orders.size() + " Orders");
				l_OrderIterator = m_Orders.iterator();
				
				while (l_OrderIterator.hasNext())
					{
					l_CurrentOrder = l_OrderIterator.next();
					try	{
						l_OrderInterface.processOrder (l_CurrentOrder);		
						}
					catch (Exception p_Exception)
						{
						this.log(Level.WARN,"Uncaught Exception from OrderBean for Message with Control ID " + l_CurrentOrder.getControlId(), p_Exception);
						}
					}
				}
			}
		catch (Exception p_Exception)
			{
			this.log(Level.FATAL,"Failed to retrieve Orders",p_Exception);
			}
		}
	}

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

private void processObservations ()
	{
	ObservationInterface			l_ObservationInterface;
//	Collection <HL7Observation>		l_Observations;
	Iterator   <HL7Observation>		l_ObservationIterator;
	HL7Observation					l_CurrentObservation 	= null;

	m_Logger.info("Processing Observations (ORU Messages)....");

	l_ObservationInterface = this.getObservationInterface();
	if (l_ObservationInterface != null)
		{
		try	{		
//			l_Observations = l_ObservationInterface.getAllObservations();
		
			if ((m_Observations != null) && (m_Observations.size() > 0))
				{
				m_Logger.info("Processing " + m_Observations.size() + " Observations");
				l_ObservationIterator = m_Observations.iterator();
				
				while (l_ObservationIterator.hasNext())
					{
					l_CurrentObservation = l_ObservationIterator.next();
					try	{
						l_ObservationInterface.processObservation (l_CurrentObservation);		
						}
					catch (Exception p_Exception)
						{
						this.log(Level.WARN,"Uncaught Exception from ObservationBean for Message with Control ID " + l_CurrentObservation.getControlId(), p_Exception);
						}
					}
				}
			}
		catch (Exception p_Exception)
			{
			this.log(Level.FATAL,"Failed to retrieve Observations",p_Exception);
			}
		}
	}

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

private void doDailyTasks ()
	{
	OrderInterface		l_OrderInterface;
	
	l_OrderInterface = this.getOrderInterface();
	if (l_OrderInterface != null)
		{
		try	{		
			l_OrderInterface.dailyTask();	
			}
		catch (Exception p_Exception)
			{
			this.log(Level.WARN,"Failed to perform daily tasks", p_Exception);
			}	
		}
	}

//---------------------------------------------------------------------------
//***************************************************************************
//* Class Body		                                                    	*
//***************************************************************************
//---------------------------------------------------------------------------

@TransactionAttribute (TransactionAttributeType.NOT_SUPPORTED)	
public void onMessage (Message p_Message) 
	{
	TextMessage						l_TextMessage;
	String							l_BuildDate;
	long							l_Time;				
	
	try	{
		if (p_Message instanceof TextMessage) 
			{		
			l_TextMessage = (TextMessage) p_Message;
			
			if (l_TextMessage.getText() == null) return;
			
			m_Logger.info("Got TextMessage [" + l_TextMessage.getText() + "]");
		
			if (l_TextMessage.getText().equals("HL7import"))
				{
				l_Time = System.currentTimeMillis();
			
				if (m_ServerProperties != null)
					{
					l_BuildDate = m_ServerProperties.getProperty("SERVER_BUILD_DATE");
					if (l_BuildDate != null) this.log(Level.INFO,"Server Build Date : " + l_BuildDate);
					}
				
				this.fetchHL7Data();

				this.processAdmissions();
				this.processOrders ();
				this.processObservations();
			
				this.disposeHL7Data();
				
				l_Time = System.currentTimeMillis() - l_Time;
				this.log(Level.INFO, "Import of HL7 data took " + l_Time + " ms to complete!");
				}
		
			else if (l_TextMessage.getText().equals("DoDaily"))
				{
				l_Time = System.currentTimeMillis();

				this.doDailyTasks();
				l_Time = System.currentTimeMillis() - l_Time;
				this.log(Level.INFO, "Performing daily tasks took " + l_Time + " ms to complete!");
				}
			}
		}
	catch (Exception p_Exception)
		{
		this.log(Level.FATAL, "Failed to process received message",p_Exception);
		}
	}

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

}
