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

import java.text.DateFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import org.jdom2.Element;

import com.etixpert.evolution.value.DistributorValue;

public class BonusData {
	//static DateFormat dateformat = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM, Locale.GERMAN);		
	static DateFormat dateformat = DateFormat.getDateInstance(DateFormat.SHORT, Locale.GERMAN);		
	
	static class SpecialBonusEntry {
		public String name;
		public double val;
		
		public SpecialBonusEntry(String aName, double aVal) {
			name = aName;
			val = aVal;
		}
	}
	
	static class CommentEntry {
		public String name;
		public String ref;
		public String txt;
		public double pVal;
		public double bVal;
		public double percent;
		public double val;
		
		public CommentEntry(String aName, String aRef, String aTxt, double aPVal, double aBVal, double aPercent, double aVal) {
			name = aName;
			ref  = aRef;
			txt  = aTxt;
			pVal = aPVal;
			bVal = aBVal;
			percent = aPercent;
			val  = aVal;
		}
	}
	
	private DistributorValue distributor;
	private Object           levelId;
	private Date             fromDate;
	private Date             toDate;
	private BonusData        prev;
	private BonusData        sponsorData;
	private List             children;

	// metrics
	private double pPV;
	private double pEV;
	private double pPEV;
	private double pTV;
	private double pOV;
	private double pQV;
	
	private double bPV;
	private double bEV;
	private double bPEV;
	private double bTV;
	private double bOV;
	private double bQV;

	private double xPV;
	private double xEV;
	private double xPEV;
	private double xTV;
	private double xOV;
	private double xQV;

	private double tOV;
	private double bCV;
	
 	private double  personalBonus;
	private double  differentialBonus;
	private double  tradeMarginBonus;
	private double  managerBonus;
	private boolean managerBonusCompressed = false;
	private double  specialBonus;
	private Map     specialBonusList;
	private List    comments;
	
	public BonusData(DistributorValue aDistributor, Date date) {
		distributor = aDistributor;
		prev = distributor.getActBonus();		
		fromDate = date;
		toDate = null;
		levelId = distributor.getLevelId();
     
        if (prev != null) {
			bPV  = prev.bPV;
			bEV  = prev.bEV;
			bPEV = prev.bPEV;
			bTV  = prev.bTV;
			bOV  = prev.bOV;

			pPV  = prev.pPV;
			pEV  = prev.pEV;
			pPEV = prev.pPEV;
			pTV  = prev.pTV;
			pOV  = prev.pOV;
			
			xEV  = prev.xPV;
			xEV  = prev.xEV;
			xPEV = prev.xPEV;
			xTV  = prev.xTV;
			xOV  = prev.xOV;
			
			tOV  = prev.tOV;
			bCV  = prev.bCV;
        }
		
        specialBonusList     = new Hashtable();
        comments = new ArrayList();
		
        sponsorData = BonusData.get(distributor.getSponsor(), date);
        if (sponsorData != null) { 
        	sponsorData.children.add(this);
        }
        children = new LinkedList();
        
        distributor.setActBonus(this);
        System.err.println("BonusData created for " + distributor.getId() + "," + levelId);
	}
	
	public DistributorValue getSponsor() {
		return distributor.getSponsor();
	}
	
	public BonusData getSponsorData() {
		return sponsorData;
	}
	
	public BonusData getPrev() {
		return prev;
	}
	
	public DistributorValue getDistributor() {
		return distributor;
	}
	
	public Object getLevelId() {
		return levelId;
	}
	
	public void setLevelId(Object aLevelId) {
		levelId = aLevelId;
	}
	
	public Date getFromDate() {
		return fromDate;
	}
	
	public Date getToDate() {
		return toDate;
	}
	
	public void setToDate(Date date) {
		toDate = date;
	}

	public double getPersonalBonus() {
		return personalBonus > 0 ? personalBonus : 0;
	}
	
	public void addToPersonalBonus(double abonus) {
		personalBonus += abonus;
	}
	
	public void setPersonalBonus(double abonus) {
		personalBonus = abonus;
	}
	
	public double getDifferentialBonus() {
		return differentialBonus > 0 ? differentialBonus : 0;
	}
	
	public void addToDifferentialBonus(double abonus) {
		differentialBonus += abonus;
	}

	public void setDifferentialBonus(double abonus) {
		differentialBonus = abonus;
	}

	public double getManagerBonus() {
		return managerBonus > 0 ? managerBonus : 0;
	}
	
	public void addToManagerBonus(double abonus) {
		managerBonus += abonus;
	}
	
	public void setManagerBonus(double abonus) {
		managerBonus = abonus;
	}

	public boolean isManagerBonusCompressed() {
		return managerBonusCompressed;
	}
	
	public void setManagerBonusCompressed(boolean abonusCompressed) {
		managerBonusCompressed = abonusCompressed;
	}
	public double getTradeMarginBonus() {
		return tradeMarginBonus > 0 ? tradeMarginBonus : 0;
	}
	
	public void addToTradeMarginBonus(double abonus) {
		tradeMarginBonus += abonus;
	}
	
	public void setTradeMarginBonus(double abonus) {
		tradeMarginBonus = abonus;
	}
	
	public double getSpecialBonusValue(Object key) {
		SpecialBonusEntry sb = (SpecialBonusEntry) specialBonusList.get(key);
		return sb != null ? sb.val : 0;
	}

	public String getSpecialBonusName(Object key) {
		SpecialBonusEntry sb = (SpecialBonusEntry) specialBonusList.get(key);
		return sb != null ? sb.name : null;
	}

	public void addToSpecialBonus(Object key, String name , double aBonus) {
		SpecialBonusEntry sb = (SpecialBonusEntry) specialBonusList.get(key);
		if (sb == null) {
			sb = new SpecialBonusEntry(name, aBonus);
			specialBonusList.put(key, sb);
		} else {
			sb.val += aBonus;
		}
		if (!name.startsWith("!")) specialBonus += aBonus;
	}
	
	public void setSpecialBonus(Object key, String name , double aBonus) {
		SpecialBonusEntry sb = (SpecialBonusEntry) specialBonusList.get(key);
		if (sb == null) {
			sb = new SpecialBonusEntry(name, aBonus);
			specialBonusList.put(key, sb);
			if (!name.startsWith("!")) specialBonus += aBonus;
		} else {
			if (!name.startsWith("!"))    specialBonus += aBonus;
			if (!sb.name.startsWith("!")) specialBonus -= sb.val;
			sb.name = name;
			sb.val = aBonus;
		}
	}

	public void addComment(String name, String ref, String txt, double pVal, double bVal, double percent, double aBonus) {
		CommentEntry ce = new CommentEntry(name, ref, txt, pVal, bVal, percent, aBonus);
		comments.add(ce);
	}
	
	public double getFinalBonus() {
		double ret = 0;
		for (BonusData bd = this; bd != null; bd = bd.prev) {
			ret += (bd.personalBonus > 0 ? bd.personalBonus : 0) + 
				   (bd.differentialBonus > 0 ? bd.differentialBonus : 0) +
				   (bd.managerBonus > 0 ? bd.managerBonus : 0) +
				   (bd.tradeMarginBonus > 0 ? bd.tradeMarginBonus : 0) +
				   bd.specialBonus;
		}
		return ret > 0 ? ret : 0;
	}

	public double getpPV() {
		return pPV;
	}
	
	public double getbPV() {
		return bPV;
	}

	public double getxPV() {
		return xPV;
	}

	public void addToPV(double aPoint, double aBonus, double aPrice) {
		pPV += aPoint;
		bPV += aBonus;
		xPV += aPrice;
	}

	public double getpEV() {
		return pEV;
	}
	
	public double getbEV() {
		return bEV;
	}

	public double getxEV() {
		return xEV;
	}

	public void addToEV(double aPoint, double aBonus, double aPrice) {
		pEV += aPoint;
		bEV += aBonus;
		xEV += aPrice;
	}
	
	public double getpPEV() {
		return pPEV;
	}
	
	public double getbPEV() {
		return bPEV;
	}

	public double getxPEV() {
		return xPEV;
	}
	
	public void addToPEV(double aPoint, double aBonus, double aPrice) {
		pPEV += aPoint;
		bPEV += aBonus;
		xPEV += aPrice;
	}

	public double getpTV() {
		return pTV;
	}
	
	public double getbTV() {
		return bTV;
	}

	public double getxTV() {
		return xTV;
	}

	public void addToTV(double aPoint, double aBonus, double aPrice) {
		pTV += aPoint;
		bTV += aBonus;
		xTV += aPrice;
	}

	public double getpOV() {
		return pOV;
	}

	public double getbOV() {
		return bOV;
	}

	public double getxOV() {
		return xOV;
	}

	public double getbCV() {
		return bCV;
	}

	public void  addTobCV(double aBonus) {
		bCV += aBonus;
	}
	
	public void addToOV(double aPoint, double aBonus, double aPrice) {
		pOV += aPoint;
		bOV += aBonus;
		xOV += aPrice;
	}

	public void addTotOV(double aPrice) {
		tOV += aPrice;
	}

		
	private void toXML(Element target) {
		NumberFormat nf = NumberFormat.getIntegerInstance(Locale.ENGLISH);
		nf.setMaximumFractionDigits(3);
		nf.setGroupingUsed(false);
		for (Iterator it = children.iterator(); it.hasNext(); ) {
			BonusData bd = (BonusData) it.next();
			
			Element e = new Element("item");
			
			e.setAttribute("Id",      "" + bd.distributor.getId());
			e.setAttribute("LevelId", "" + bd.levelId);
			e.setAttribute("From",    dateformat.format(bd.fromDate));
			e.setAttribute("To",      bd.toDate != null ? dateformat.format(bd.toDate) : "");
			
			e.setAttribute("pPV",  nf.format(bd.pPV  - (bd.prev != null ? bd.prev.pPV  : 0)));
			e.setAttribute("pEV",  nf.format(bd.pEV  - (bd.prev != null ? bd.prev.pEV  : 0)));
			e.setAttribute("pPEV", nf.format(bd.pPEV - (bd.prev != null ? bd.prev.pPEV : 0)));
			e.setAttribute("pTV",  nf.format(bd.pTV  - (bd.prev != null ? bd.prev.pTV  : 0)));
			e.setAttribute("pOV",  nf.format(bd.pOV  - (bd.prev != null ? bd.prev.pOV  : 0)));

			e.setAttribute("bPV",  nf.format(bd.bPV  - (bd.prev != null ? bd.prev.bPV  : 0)));
			e.setAttribute("bEV",  nf.format(bd.bEV  - (bd.prev != null ? bd.prev.bEV  : 0)));
			e.setAttribute("bPEV", nf.format(bd.bPEV - (bd.prev != null ? bd.prev.bPEV : 0)));
			e.setAttribute("bTV",  nf.format(bd.bTV  - (bd.prev != null ? bd.prev.bTV  : 0)));
			e.setAttribute("bOV",  nf.format(bd.bOV  - (bd.prev != null ? bd.prev.bOV  : 0)));

			e.setAttribute("tOV",  nf.format(bd.tOV  - (bd.prev != null ? bd.prev.tOV  : 0)));
			
			e.setAttribute("PB", nf.format(bd.personalBonus));
			e.setAttribute("DB", nf.format(bd.differentialBonus));
			e.setAttribute("MB", nf.format(bd.managerBonus));
			e.setAttribute("TB", nf.format(bd.tradeMarginBonus));
			e.setAttribute("SB", nf.format(bd.specialBonus));
			
			for (Iterator it2 =  bd.specialBonusList.values().iterator(); it2.hasNext(); ) {
				SpecialBonusEntry entry = (SpecialBonusEntry) it2.next(); 
				Element spe = new Element("B");
				spe.setAttribute("Name", entry.name != null ? entry.name : "noname");
				spe.setAttribute("Val", nf.format(entry.val));
				e.addContent(spe);
			}

			for (Iterator it2 =  bd.comments.iterator(); it2.hasNext(); ) {
				CommentEntry entry = (CommentEntry) it2.next(); 
				Element spe = new Element(entry.name);
				if (entry.ref != null) spe.setAttribute("Ref", entry.ref);
				if (entry.txt != null) spe.setAttribute("Txt", entry.txt);
				spe.setAttribute("PVal", nf.format(entry.pVal));
				spe.setAttribute("BVal", nf.format(entry.bVal));
				spe.setAttribute("Percent", "" + (int) entry.percent);
				spe.setAttribute("Val", nf.format(entry.val));
				e.addContent(spe);
			}

			target.addContent(e);
			bd.toXML(e);
		}
	}

	public static Element toXML(Map environment) {
		Element ret = new Element("bonus");
		DistributorValue bv = ((DistributorValue) environment.get(""));
		if (bv.getActBonus() != null) bv.getActBonus().toXML(ret);
		return ret;
	}
	
	public void close(Date date) {
		System.err.println("close " + distributor.getId());
		toDate = date;
		List children = distributor.getChildren();
		for (Iterator it = children.iterator(); it.hasNext(); ) {
			DistributorValue act = (DistributorValue) it.next(); 
			BonusData aval = act.getActBonus();
			if (aval != null) aval.close(date);
		}
	}

	public static BonusData get(DistributorValue src, Date date) {
		if (src == null) return null;
		BonusData ret = src.getActBonus();

		if (ret == null) { 
			return new BonusData(src, date);
		}
		// is that closed?
		if (ret.toDate != null) {
			// we can reuse the old one			
			//if (ret.levelId != src.getLevelId() ||
			//		src.getSponsor() != null && !src.getSponsor().getActBonus().children.contains(ret)) {	
				return new BonusData(src, date);
			//}
		}
		return ret;
	}
}
