/*******************************************************************************
 * 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.Collection;
import java.util.LinkedHashSet;

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

import lu.tudor.santec.gecamed.billing.ejb.entity.beans.Invoice;
import lu.tudor.santec.gecamed.billing.ejb.entity.beans.Ledger;
import lu.tudor.santec.gecamed.billing.ejb.entity.beans.TrashedInvoice;
import lu.tudor.santec.gecamed.billing.ejb.entity.beans.TrashedInvoiceStub;
import lu.tudor.santec.gecamed.billing.ejb.entity.beans.UntrashedInvoice;
import lu.tudor.santec.gecamed.billing.ejb.session.interfaces.TrashedInvoiceStubInterface;
import lu.tudor.santec.gecamed.core.ejb.session.beans.GECAMedSessionBean;
import lu.tudor.santec.gecamed.core.utils.querybuilder.HibernateQueryFactory;
import lu.tudor.santec.gecamed.core.utils.querybuilder.WhereClause;

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

/**
 * The TrashedInvoiceStubBean manages invoices that have been deleted and
 * which are in the trash. The bean also provides a method to undelete, i.e.
 * to restore such an invoice.
 * @author nico.mack@tudor.lu
 */

@Stateless
@Remote (TrashedInvoiceStubInterface.class)
public class TrashedInvoiceStubBean extends GECAMedSessionBean implements TrashedInvoiceStubInterface
	{
	
	/** the logger Object for this class */
	private static org.apache.log4j.Logger m_Logger = org.apache.log4j.Logger.getLogger(TrashedInvoiceStubBean.class.getName());

//***************************************************************************
//* Constructor(s)                                                          *
//***************************************************************************

//---------------------------------------------------------------------------
//***************************************************************************
//* Class Body                                                              *
//***************************************************************************
//---------------------------------------------------------------------------
/**
 * Fetches all trashed invoices from database.
 * @return A collection holding all trashed invoices stored in the database.
 */
//---------------------------------------------------------------------------

@RolesAllowed("gecam")
@SuppressWarnings("unchecked")
public Collection <TrashedInvoiceStub> getAllTrashedInvoiceStubs () throws Exception
	{
	Collection <TrashedInvoiceStub>	l_InvoiceStubs;

	try	{
		l_InvoiceStubs = m_EntityManager.createNamedQuery(TrashedInvoiceStub.c_AllTrashedInvoiceStubs)
									    .getResultList();
		}
	catch (NoResultException p_Exception)
		{
		l_InvoiceStubs = new LinkedHashSet <TrashedInvoiceStub> ();
		}
	
	return l_InvoiceStubs;
	}

//---------------------------------------------------------------------------
/**
 * Returns the number of trashed invoices matching the specified where clause.
 * @param p_Clause specifies the where clause that trashed invoices have to
 * match in order to be taken into account.
 * @return the number of matching invoices (in trash)
 */
//---------------------------------------------------------------------------

@RolesAllowed("gecam")
@SuppressWarnings("unchecked")
public Long getInvoiceStubCountByWhereClause (WhereClause p_Clause) throws Exception
	{
	Query					l_Query;
	String					l_QueryString;

	Long					l_Count;
	
	if (p_Clause == null) return 0L;

	l_QueryString = "SELECT COUNT(o) FROM TrashedInvoice o $WHERECLAUSE";

	try	{
		l_Query = HibernateQueryFactory.buildQueryFromNestedWhereClause (m_EntityManager, l_QueryString, p_Clause);
		l_Count = (Long) l_Query.getSingleResult();
		}
	catch (NoResultException p_Exception)
		{
		l_Count = 0L;
		}
	
	return l_Count;
	}

//---------------------------------------------------------------------------
/**
 * Returns the trashed invoices matching the specified where clause.
 * @param p_Clause specifies the where clause that trashed invoices have to
 * match in order to be taken into account.
 * @return a collection holding the matching invoices (from trash)
 */
//---------------------------------------------------------------------------

@RolesAllowed("gecam")
@SuppressWarnings("unchecked")
public Collection <TrashedInvoiceStub> getInvoiceStubsByWhereClause (WhereClause p_Clause) throws Exception
	{
	Query							l_Query;
	String							l_QueryString;

	Collection <TrashedInvoiceStub>	l_InvoiceStubs;

	l_InvoiceStubs = new LinkedHashSet <TrashedInvoiceStub> ();
	
	if (p_Clause == null) return l_InvoiceStubs;

	l_QueryString = "SELECT OBJECT(s) FROM TrashedInvoiceStub s WHERE s.id IN " +
					"(SELECT o.id FROM TrashedInvoice o $WHERECLAUSE)";

	try	{
		l_Query = HibernateQueryFactory.buildQueryFromNestedWhereClause (m_EntityManager, l_QueryString, p_Clause);
		l_InvoiceStubs = l_Query.getResultList();
		}
	catch (NoResultException p_Exception)
		{
		// Simply Return empty Collection
		}
	
	return l_InvoiceStubs;
	}

//---------------------------------------------------------------------------
/**
 * Undeletes a particular invoice identified by the specified Id. 
 * @param p_InvoiceId specifies the Id of the invoice currently in trash to
 * be undeleted, i.e. to be restored.
 * @return the restored invoice if undelete operation was successful, <code>
 * null</code> otherwise.
 */
//---------------------------------------------------------------------------

@RolesAllowed("gecam")
public Invoice undeleteInvoice (Integer p_InvoiceId) throws Exception
	{
	TrashedInvoice		l_TrashedInvoice;
	UntrashedInvoice	l_UntrashedInvoice;
	Invoice				l_Invoice = null;
	
	try	{
		l_TrashedInvoice = m_EntityManager.find(TrashedInvoice.class, p_InvoiceId);
		}
	catch (NoResultException p_Exception)
		{
		l_TrashedInvoice = null;
		}
	
	if (l_TrashedInvoice != null)
		{
		l_UntrashedInvoice = new UntrashedInvoice (l_TrashedInvoice);
		
		try	{
			l_UntrashedInvoice = m_EntityManager.merge(l_UntrashedInvoice);
			l_Invoice = getInvoiceByID(p_InvoiceId);
			m_EntityManager.remove (l_TrashedInvoice);
			}
		catch (Exception p_Exception)
			{
			m_Logger.error("Failed to undelete Invoice!",p_Exception);
			}
		}
	
	return l_Invoice;
	}

	private  Invoice getInvoiceByID (Integer p_ID) throws Exception
	{
	Invoice l_Invoice;
	
	try	{
		l_Invoice = (Invoice) m_EntityManager.createNamedQuery(Invoice.c_InvoiceById)
								   			 .setParameter (Invoice.c_IdParameter,p_ID)
								   			 .getSingleResult();
		l_Invoice.updateFirstClassRequired();
		}
	catch (NoResultException p_Exception)
		{
		l_Invoice = null;
		}
	
	return l_Invoice;
	}
	
	
	public  void deleteTrashedInvoiceByID (Integer p_ID) throws Exception
	{
		m_EntityManager.remove(m_EntityManager.find(TrashedInvoice.class, p_ID));
		
		deleteLedgersByInvoiceID(p_ID);
		
	}
	
	
	@SuppressWarnings("unchecked")
	private void deleteLedgersByInvoiceID (Integer p_ID) throws Exception  {
		Collection<Ledger> 	l_Ledgers = null;

		try	{
			l_Ledgers = m_EntityManager.createNamedQuery (Ledger.c_LedgersByInvoiceID)
									   .setParameter("invoiceID", p_ID)
									   .getResultList();
			
			if (l_Ledgers != null) {
				for (Ledger ledger : l_Ledgers) {
					m_EntityManager.remove(ledger);
				}				
			}
		}
		catch (NoResultException p_Exception)
		{	
		}

	}
	

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