/*******************************************************************************
 * 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.billing.ejb.session.beans;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

import javax.annotation.security.RolesAllowed;
import javax.ejb.EJB;
import javax.ejb.Remote;
import javax.ejb.Stateless;
import javax.persistence.NoResultException;

import lu.tudor.santec.gecamed.billing.ejb.entity.beans.Invoice;
import lu.tudor.santec.gecamed.billing.ejb.entity.beans.Settlement;
import lu.tudor.santec.gecamed.billing.ejb.entity.beans.Statement;
import lu.tudor.santec.gecamed.billing.ejb.session.interfaces.StatementInterface;
import lu.tudor.santec.gecamed.billing.ejb.session.interfaces.StatementInvoiceStubInterface;
import lu.tudor.santec.gecamed.core.ejb.session.beans.GECAMedSessionBean;
import lu.tudor.santec.gecamed.usermanagement.ejb.session.interfaces.LoginInterface;

//***************************************************************************
//* Interface Definition and Members                                        *
//***************************************************************************

/**
 * The StatementBean manages access to third party statements.
 * @author nico.mack@tudor.lu
 */

@Stateless
@Remote (StatementInterface.class)
public class StatementBean extends GECAMedSessionBean implements StatementInterface
	{
	private static final long serialVersionUID = 1L;
	
	@EJB
	LoginInterface m_LoginBean;
	
	@EJB
	StatementInvoiceStubInterface m_StatementInvoiceStubBean;
	
//***************************************************************************
//* Class Constants                                                         *
//***************************************************************************
	
//***************************************************************************
//* Class Primitives                                                        *
//***************************************************************************
//---------------------------------------------------------------------------

private Collection <Integer> getInvoiceIDs (Collection <Invoice> p_Invoices)
	{
	Collection <Integer> l_InvoiceIDs;
	Iterator <Invoice>	 l_InvoiceIterator;
	Invoice				 l_Invoice;
	
	l_InvoiceIDs = new ArrayList <Integer> ();
	l_InvoiceIterator = p_Invoices.iterator();
	while (l_InvoiceIterator.hasNext())
		{
		l_Invoice = l_InvoiceIterator.next();
		l_InvoiceIDs.add(l_Invoice.getId());
		}

	return l_InvoiceIDs;
	}

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

//***************************************************************************
//* Class Body                                                              *
//***************************************************************************
//---------------------------------------------------------------------------
/**
 * Returns all third party statements stored in the database.
 * @return A collection holding all third party statements, <code>null</code>
 * if none are available.
 */
//---------------------------------------------------------------------------

@RolesAllowed("gecam")
@SuppressWarnings("unchecked")

public Collection <Statement> getAllStatements() throws Exception 
	{
	Collection 	l_Statements;

	try	{	
		l_Statements = m_EntityManager.createNamedQuery (Statement.c_AllStatements).getResultList();
		}
	catch (NoResultException p_Exception)
		{
		l_Statements = null;
		}
	
	return l_Statements;
	}

//---------------------------------------------------------------------------
/**
 * Fetches one particular third party statement identified by the specified
 * id.
 * @param p_ID specifies the id of the third party statement to fetch
 * @return The third party statement identified by the specified id, <code>
 * null</code> if none can be found.
 */
//---------------------------------------------------------------------------

@RolesAllowed("gecam")

public Statement getStatementByID (Integer p_ID) throws Exception 
	{
	Statement l_Statement;
	
	try	{	
		l_Statement = m_EntityManager.find(Statement.class, p_ID);
		}
	catch (NoResultException p_Exception)
		{
		l_Statement = null;
		}
	
	return l_Statement;
	}

//---------------------------------------------------------------------------
/**
 * Fetches the settlement method associated with the specified third party
 * statement.
 * @param p_Statement specifies the third party statement to get associated
 * settlement method for.
 * @return The settlement method defined for the specified statement, <code>
 * null</code> if none was defined.
 */
//---------------------------------------------------------------------------

@RolesAllowed("gecam")

public Settlement getSettlement (Statement p_Statement)	throws Exception
	{
	Settlement l_Settlement;
	
	if ((p_Statement == null) || (p_Statement.getAccount() == null)) return null;
	
	try	{	
		l_Settlement = (Settlement) m_EntityManager.createNamedQuery (Settlement.c_SettlementByAccount)
								  			   	   .setParameter("account", p_Statement.getAccount())
								  			   	   .setMaxResults(1)
								  			   	   .getSingleResult();
		}
	catch (NoResultException p_Exception)
		{
		l_Settlement = null;
		}
	
	return l_Settlement;
	}

//---------------------------------------------------------------------------
/**
 * Stores the specified third party statement into the database.
 * @param p_Statement specifies the statement to be saved.
 * @return the persisted, i.e. saved statement. The method returns <code>null
 * </code> if specified statement was <code>null</code>.
 */
//---------------------------------------------------------------------------

@RolesAllowed("gecam")

public Statement saveStatement (Statement p_Statement) throws Exception 
	{
	if (p_Statement == null) return p_Statement;
	
	return m_EntityManager.merge (p_Statement);
	}

//---------------------------------------------------------------------------
/**
 * Checks whether all invoices for a particular statement have already been
 * settled or not
 * @param p_Statement specifies the third party statement to get full
 * settlement state of
 * @return <code>True</code> if all invoices on specified have already been
 * settled, <code>False</code> otherwise.
 */
//---------------------------------------------------------------------------

@RolesAllowed("gecam")
public Boolean allInvoicesSettledForStatement	(Statement p_Statement) throws Exception
	{
	Long	l_InvoiceCount 		  = Long.valueOf(0);
	Long	l_SettledInvoiceCount = Long.valueOf(0);
	Boolean	l_AllInvoicesSettled  = Boolean.FALSE;
		
	if ((p_Statement != null) && (p_Statement.isPersistent()))
		{
		try	{
			l_InvoiceCount = (Long) m_EntityManager.createNamedQuery (Invoice.c_InvoiceCountByStatement)
									  			   .setParameter (Invoice.c_StatementParameter,p_Statement)
									  			   .getSingleResult();
			
			l_SettledInvoiceCount = (Long) m_EntityManager.createNamedQuery (Invoice.c_SettledInvoiceCountByStatement)
			   											  .setParameter (Invoice.c_StatementParameter,p_Statement)
			   											  .getSingleResult();
			
			l_AllInvoicesSettled = (l_InvoiceCount.longValue() > 0) && (l_InvoiceCount.equals(l_SettledInvoiceCount));
			}
		catch (Exception p_Exception)
			{
			throw (p_Exception);
			}
		}
	
	return l_AllInvoicesSettled;
	}

//---------------------------------------------------------------------------
/**
 * Removes the specified third party statement from the database. If third
 * party statement was already closed, i.e. there are already invoices which
 * reference it, then the statement will be opened first, thus references to
 * statement will be dropped.
 * @param p_Statement specifies the statement to delete.
 */
//---------------------------------------------------------------------------

@RolesAllowed("gecam")
@SuppressWarnings("unchecked")

public void deleteStatement (Statement p_Statement) throws Exception 
	{
	Collection <Invoice> l_Invoices;
	Collection <Integer> l_InvoiceIDs;
	
	if (p_Statement.isPersistent()) 
		{
		p_Statement = m_EntityManager.find (Statement.class, p_Statement.getId());
		
		//====================================================================
		//= In case invoices were already closed via the statement to delete
		//= we'll reopen those invoices before actually deleting the statement.
		//====================================================================
		
		try	{	
			l_Invoices = m_EntityManager.createNamedQuery(Invoice.c_InvoicesByStatement)
			 						    .setParameter ("statement",p_Statement)
			 							.getResultList();
			}
		catch (NoResultException p_Exception)
			{
			l_Invoices = null;
			}

		if ((l_Invoices != null) && (l_Invoices.size() > 0))
			{
			l_InvoiceIDs = this.getInvoiceIDs(l_Invoices);
			m_StatementInvoiceStubBean.openInvoicesForStatement (p_Statement, l_InvoiceIDs);
			}
		
		m_EntityManager.remove(p_Statement);
		}
	}

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

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