package lu.tudor.santec.gecamed.billing.utils;

import java.util.HashSet;
import java.util.Set;

import lu.tudor.santec.gecamed.billing.ejb.entity.beans.Act;
import lu.tudor.santec.gecamed.billing.ejb.entity.beans.Invoice;
import lu.tudor.santec.gecamed.patient.ejb.entity.beans.HospitalisationClass;

/**
 * @author jens.ferring(at)tudor.lu
 * 
 * This class is to check, whether anything has changed in the invoice,
 * since the last time the status was saved or the rules have been 
 * applied.
 * 
 * @version
 * <br>$Log: InvoiceModifiedStatus.java,v $
 * <br>Revision 1.2  2013-09-17 14:32:35  ferring
 * <br>No exception anymore, when insuranceId of a patient is NULL
 * <br>
 * <br>Revision 1.1  2013-02-15 14:00:19  ferring
 * <br>Options added to warn if rules have not been applied and to avoid saving, if private and CNS rates are on the same invoice
 * <br>
 */

public class InvoiceModifiedStatus
{
	/* ======================================== */
	// 		MEMBERS
	/* ======================================== */
	
	private Set<Integer>	acts;
	
	private boolean			unchangable;
	
	private String			hospitalisationClass;
	
	private String			insurance;
	
	private Boolean			firstClassRequired;
	
	private int				actCount;
	
	
	
	/* ======================================== */
	// 		CONSTRUCTORS
	/* ======================================== */
	
	public InvoiceModifiedStatus()
	{
		acts	= new HashSet<Integer>();
	}
	
	
	
	/* ======================================== */
	// 		CLASS BODY
	/* ======================================== */
	
	public void saveStatus (Invoice invoice)
	{
		unchangable				= invoice.getState() > InvoiceWorkflow.c_OpenState;
		
		if (unchangable)
			return;
		
		// TODO: 
		if (invoice.getHospitalisationClass() != null)
			hospitalisationClass	= invoice.getHospitalisationClass().getAcronym();
		else
			hospitalisationClass	= HospitalisationClass.c_Ambulant;
		
		if (invoice.getHealthInsurance() != null)
			insurance				= invoice.getHealthInsurance().getAcronym();
		else
			insurance				= "-";
		
		firstClassRequired		= invoice.getFirstClassRequired();
		
		acts.clear();
		if (invoice.getActs() == null)
		{
			actCount = 0;
		}
		else
		{
			actCount = invoice.getActs().size();
			
			for (Act act : invoice.getActs())
			{
				if (act == null)
					continue;
				
				acts.add(hashAct(act));
			}
		}
	}
	
	
	public boolean modified (Invoice invoice)
	{
		if (unchangable && invoice.getState() > InvoiceWorkflow.c_OpenState)
			// the invoice could not be modified
			return false;
		
		if (	   invoice.getHospitalisationClass() == null
				|| changed(hospitalisationClass,	invoice.getHospitalisationClass().getAcronym())
				|| invoice.getHealthInsurance() == null
				|| changed(insurance,				invoice.getHealthInsurance().getAcronym())
				|| changed(firstClassRequired,		invoice.getFirstClassRequired())
				|| actCount != invoice.getActs().size())
			return true;
		
		for (Act act : invoice.getActs())
		{
			if (!acts.contains(hashAct(act)))
				// if the hash of the act has changed, the act has changed 
				return true;
		}
		
		return false;
	}
	
	
	
	/* ======================================== */
	// 		HELP METHODS
	/* ======================================== */
	
	private static boolean changed (Object o1, Object o2)
	{
		if (o1 == null)
			return o2 != null;
		
		return !o1.equals(o2);
	}
	
	
	private static int hashAct (Act act)
	{
		return new StringBuilder(act.getCode())
				.append("|")
				.append(act.getPerformedDate())
				.append("|")
				.append(act.getHospitalisationClass())
				.append("|")
				.append(act.getQuantity())
				.append("|")
				.append(act.getSuffixes())
				.append("|")
				.append(act.getFixAmount())
				.toString()
				.hashCode();
	}
}
