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

import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import javax.persistence.Transient;

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.core.ejb.entity.beans.GECAMedEntityBean;

/**
 * @author jens.ferring(at)tudor.lu
 * 
 * @version
 * <br>$Log: UnionAct.java,v $
 * <br>Revision 1.1  2013-03-22 10:27:03  ferring
 * <br>UnionActs added and billing bugs fixed (since last not released commit)
 * <br>
 */

public class UnionAct extends Act
{
	/* ======================================== */
	// 		CONSTANTS
	/* ======================================== */
	
	private static final long	serialVersionUID	= 1L;
	
	
	
	/* ======================================== */
	// 		MEMBERS
	/* ======================================== */
	
	/**
	 * Defines whether or not this is the highest act
	 */
	private boolean					mainAct;
	
	/**
	 * All acts of this group
	 */
	private Collection<UnionAct>	summedActs;
	
	/**
	 * The actual, this UnionAct represents
	 */
	private Act						originalAct;
	
	
	
	/* ======================================== */
	// 		CONSTRUCTORS
	/* ======================================== */
	
	public UnionAct (Act act, boolean isMainAct, Collection<UnionAct> summedActs)
	{
		this.mainAct	= isMainAct;
		this.summedActs	= summedActs;
		this.originalAct= act;
		
		act.updateFields(this, GECAMedEntityBean.getSuperClasses(Act.class));
		addValueListener(act.getValueListener());
	}
	
	
	
	/* ======================================== */
	// 		CLASS BODY
	/* ======================================== */

	@Override
	@Transient
	public void clearSuffix(char c)
	{
		if (mainAct)
		{
			for (UnionAct act : summedActs)
				act.doClearSuffix(c);
		}
	}
	
	
	@Transient
	public void doClearSuffix (char c)
	{
		super.clearSuffix(c);
	}
	
	
	@Override
	public void setQuantity (Integer i)
	{
		if (mainAct)
		{
			for (UnionAct act : summedActs)
				act.doSetQuantity(i);
		}
	}
	
	
	@Transient
	public void doSetQuantity (Integer i)
	{
		super.setQuantity(i);
	}
	
	
	@Override
	@Transient
	public double monetize ()
	{
		double amount	= 0.0;
		
		
		if (mainAct)
		{
			for (UnionAct act : summedActs)
				amount += act.doMonetize();
		}
		return amount;
	}
	
	
	@Transient
	public double doMonetize ()
	{
		return super.monetize();
	}
	

	@Override
	@Transient
	public void setSuffix(char c)
	{
		if (mainAct)
		{
			for (UnionAct act : summedActs)
				act.doSetSuffix(c);
		}
	}
	
	
	@Transient
	public void doSetSuffix (char c)
	{
		super.setSuffix(c);
	}
	
	
	@Transient
	public Collection<String> getCodes ()
	{
		Collection<String>	codes	= new HashSet<String>();
		
		
		for (Act act : summedActs)
		{
			codes.add(act.getCode());
		}
		
		return codes;
	}
	
	
//	public Double getAmount ()
//	{
//		return getValue();
//	}
	
	
	@Override
	@Transient
	public Double getValue()
	{
		double	amount	= 0.0;
		
		
		if (mainAct)
		{
			for (UnionAct act : summedActs)
				amount	+= act.doGetAmount();
		}
		
		return Double.valueOf(amount);
	}
	
	
	@Transient
	public double doGetAmount ()
	{
		return super.getAmount().doubleValue();
	}
	
	
//	@Override
//	public int hashCode()
//	{
//		return highestCode.hashCode();
//	}
	
	
	@Transient
	public static boolean insertUnionActs (RulesObjectsHolder roh)
	{
		Collection<UnionAct>	summedActs;
		Set<String>				allUnionCodes	= new HashSet<String>();
		UnionAct				unionAct;
		Collection<String>		unionCodes;
		boolean					isMainAct;
		boolean					hasChanges		= false;
		UnionAct				mainAct			= null;
		Invoice					invoice			= roh.getInvoice();
		

		for (List<Act> actsOfDay : roh.getSortedActs())
		{
			allUnionCodes.clear();
			
			for (Act act : actsOfDay)
			{
				// see, whether there are acts, that are to be used as one act
				unionCodes = Cumulations.unionCumulationActs.get(act.getCode());
				if (!allUnionCodes.contains(act.getCode())
						&& unionCodes != null)
				{
					isMainAct	= true;
					summedActs	= new HashSet<UnionAct>();
					
					for (Act uAct : actsOfDay)
					{
						if (unionCodes.contains(uAct.getCode()))
						{
							unionAct	= new UnionAct(uAct, isMainAct, summedActs);
							summedActs.add(unionAct);
							invoice.getActs().remove(uAct);
//							uAct.setCode("REPLACED");
//							uAct.setFixAmount(0.0);
							invoice.getActs().add(unionAct);
							allUnionCodes.add(uAct.getCode());
							if (isMainAct)
							{
								mainAct		= unionAct;
								isMainAct	= false;
								hasChanges	= true;
							}
							else
							{
								unionAct.monetize();
							}
						}
					}
					
					if (mainAct != null)
						mainAct.monetize();
				}
			}
		}
		
		if (hasChanges)
			invoice.setActs(invoice.getActs());
		
		return hasChanges;
	}
	
	
	public static void replaceUnionActs (Invoice invoice)
	{
		List<UnionAct>	unionActs	= new LinkedList<UnionAct>();
		Set<Act>		acts		= invoice.getActs();
		
		
		for (Act act : acts)
		{
			if (act instanceof UnionAct)
				unionActs.add((UnionAct) act);
		}
		
		if (!unionActs.isEmpty())
		{
			for (UnionAct unionAct : unionActs)
			{
				unionAct.updateFields(unionAct.originalAct, GECAMedEntityBean.getSuperClasses(Act.class));
				unionAct.originalAct.addValueListener(unionAct.getValueListener());
				unionAct.getValueListener().clear();
				
				acts.remove(unionAct);
				acts.add(unionAct.originalAct);
				unionAct.originalAct.monetize();
			}
			
			invoice.setActs(acts);
		}
	}
	
	@Transient
	public String printSummed () 
	{
		StringBuffer sb = new StringBuffer("[");
		if (summedActs != null) {
			for (Act act : summedActs)
			{
				sb.append(act).append(" ");
			}
		}
		sb.append("]");
		return sb.toString();
	}
	
}
