/*
 * Qualification.java
 * Created on May 11, 2005 
 * Author: 	L�szl� Felf�ldi, Etixpert GmbH
 * mail:	laszlo.felfoldi@etixpert.com		
 */
package com.etixpert.evolution.app.bonus.handler;

import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import org.jdom2.Element;

import com.etixpert.evolution.app.bonus.BonusData;
import com.etixpert.evolution.app.bonus.Engine;
import com.etixpert.evolution.app.bonus.Handler;
import com.etixpert.evolution.event.CalculateEvent;
import com.etixpert.evolution.event.Event;
import com.etixpert.evolution.event.PropagateEvent;
import com.etixpert.evolution.value.DistributorValue;
import com.etixpert.evolution.value.bonus.BonusDefinitionValue;

public class Qualification implements Handler {
	private Map values;
	
	private class Entry {
		public double limit;
		public Object nextLevel;
		public int    childLimitVal;
		public Set    childLimitLevels;
		
		public Entry(Object aNextLevel, double aLimit, int aChildLimitVal, Set aChildLimitLevels) {
			limit = aLimit;
			nextLevel = aNextLevel;
			childLimitVal = aChildLimitVal;
			childLimitLevels = aChildLimitLevels;
		}
	}
	
	public Qualification(BonusDefinitionValue src) {
		values = new Hashtable();

		// Format is from1,to1,limit1,childlimitexpression1;from2,to2,limit2,childlevel21=...
		// childlimitexpression can be omitted, or : level1+level2+...:limit
		String[] items = src.getData().split(";");
		for (int i = 0; i < items.length; i++) {
			String[] vals = items[i].split(",");
			try {
				Set childLimitLevels = null;
				int childLevelVal    = 0;
				if (vals.length > 3) {
					String[] sum_val = vals[3].split(":");
					String[] tags = sum_val[0].split("\\+");
					childLimitLevels = new HashSet();
					for (int j = 0; j < tags.length; j++) {
						childLimitLevels.add(BonusDefinitionValue.getLevel(tags[j]));
					}
					childLevelVal = Integer.parseInt(sum_val[1]);
				}
				Entry entry = new Entry(BonusDefinitionValue.getLevel(vals[1]), Double.parseDouble(vals[2]), childLevelVal, childLimitLevels);				
				values.put(BonusDefinitionValue.getLevel(vals[0]), entry);
			} catch (Exception e) {}
		}		
	}
	
	private boolean checkChildLimit(Entry item, BonusData dhv) {
		int val = 0;
		for (Iterator it = dhv.getDistributor().getChildren().iterator(); it.hasNext(); ) {
			DistributorValue child = (DistributorValue) it.next();
			Object childLevel = child.getLevelId();
			if (item.childLimitLevels.contains(childLevel)) { 
				if (++val >= item.childLimitVal) return true;
			}
		}
		return false;
	}
	
	/* (non-Javadoc)
	 * @see com.etixpert.evolution.app.bonus.Handler#handle(com.etixpert.evolution.common.Event, java.util.Map)
	 */
	public boolean handle(Event event, Map environment) {
		DistributorValue distributor = event.getEventTarget();    
		BonusData        dhv         = BonusData.get(distributor, event.getEventDate());
		PropagateEvent   order       = (PropagateEvent) event;
	
		// when partnerType == "1", distributor cannot jump level
		boolean allowedToJump = !new Integer(1).equals(distributor.getPartnerTypeId());

		Entry   item        = (Entry) values.get(distributor.getLevelId());
		double  addVal      = order.getPoint();
		double  actVal      = dhv.getpOV();
		try {
			System.err.println("Qualify: " + dhv.getDistributor().getId() + ", " + dhv.getDistributor().getLevelId() + ", " + item.limit + ", " + actVal + ", "  + addVal);
		} catch (Exception e) {} 
		
		
		if (item != null && item.limit <= actVal && allowedToJump) {
			if (item.childLimitLevels == null || checkChildLimit(item, dhv)) {
				distributor.getActBonus().close(event.getEventDate());
				distributor.setLevelId(item.nextLevel);
				item = (Entry) values.get(item.nextLevel);
			}
		}
		
		if (item != null && item.limit < actVal + addVal) {
			// check the child limits if exist
			if (item.childLimitLevels == null || checkChildLimit(item, dhv)) {
				addVal = item.limit > actVal ? item.limit - actVal : actVal;
			}	
		}	
		
		System.err.println("Qualify In: " + addVal);

		if (distributor.getSponsor() != null) {
			PropagateEvent newEvent1 = new PropagateEvent(distributor.getSponsor(), order, distributor, addVal);
			Engine.handleEvent(newEvent1, environment);
			addVal = newEvent1.getPoint();
		}

		CalculateEvent newEvent2 = new CalculateEvent(order, addVal);
		Engine.handleEvent(newEvent2, environment);

		order.setPoint(addVal);
			
		return true;
	}
	
	public void toXML(Element to) {
	}
}
