package com.hero.objects.powers;

import java.util.ArrayList;

import org.jdom.Element;

import com.hero.HeroDesigner;
import com.hero.objects.ElementalControl;
import com.hero.objects.GenericObject;
import com.hero.objects.Multipower;
import com.hero.objects.modifiers.Modifier;
import com.hero.ui.dialog.ENDReserveDialog;
import com.hero.ui.dialog.GenericDialog;
import com.hero.util.Rounder;

/**
 * Copyright (c) 2000 - 2005, CompNet Design, Inc. All rights reserved.
 * Redistribution and use in source and binary forms, with or without
 * modification, is prohibited unless the following conditions are met: 1.
 * Express written consent of CompNet Design, Inc. is obtained by the developer.
 * 2. Redistributions must retain this copyright notice. THIS SOFTWARE IS
 * PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
 * EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * @author CompNet Design, Inc.
 * @version $Revision$
 */

public class EnduranceReserve extends Power {

	private static String xmlID = "ENDURANCERESERVE";

	private EnduranceReserveRecovery rec;

	public EnduranceReserve(Element root) {
		super(root, EnduranceReserve.xmlID);
	}

	@Override
	public EnduranceReserve clone() {
		EnduranceReserve clone = (EnduranceReserve) super.clone();
		clone.setRecovery((EnduranceReserveRecovery) rec.clone());
		return clone;
	}

	@Override
	public double getActiveCost() {
		boolean theSame = recIsSamePower();
		double total = super.getTotalCost();
		if (theSame) {
			total += rec.getTotalCost();
		}
		double advantageTotal = 0d;
		boolean advantagesApplied = false;
		for (Modifier mod : assignedModifiers) {
			if (mod.getTotalValue() > 0) {
				advantageTotal += mod.getTotalValue();
				advantagesApplied = true;
			}
		}
		if (getParentList() != null) {
			ArrayList<Modifier> parentMods = getParentList()
					.getAssignedModifiers();
			LOOP: for (Modifier mod : parentMods) {
				if (mod.getXMLID().equals("CHARGES")
						&& (getParentList() instanceof Multipower)) {
					continue LOOP;
				}
				if ((mod.getTotalValue() > 0)
						&& ((GenericObject.findObjectByID(
								getAssignedModifiers(), mod.getXMLID()) == null)
								|| mod.getXMLID().equals("GENERIC_OBJECT") || mod
								.getXMLID().equals("CUSTOM_MODIFIER"))) {
					if ((getParentList() instanceof Multipower)
							|| (getParentList() instanceof ElementalControl)) {
						continue;
					} else {
						advantageTotal += mod.getTotalValue();
					}
					advantagesApplied = true;
				}
			}
		}
		double ret = total * (1 + advantageTotal);

		rec.setParent(getParentList());
		if (advantagesApplied) {
			ret = Rounder.roundHalfDown(ret);
		}
		if (!theSame) {
			ret += rec.getActiveCost();
		}
		return ret;
	}

	@Override
	public String getColumn2Output() {
		if (getLevels() == 0) {
			String ret = rec.getAlias() + " " + rec.getDamageDisplay();
			if (rec.getName().trim().length() > 0) {
				ret = "<i>" + rec.getName() + ":</i>  " + ret;
			}
			ret += " (" + rec.getLevels() + " REC)";
			if ((rec.getInput() != null)
					&& (rec.getInput().trim().length() > 0)) {
				ret += ":  " + rec.getInput();
			}

			String recAdders = rec.getAdderString();
			if (recAdders.trim().length() > 0) {
				ret += " (";
				ret += "REC: " + recAdders;
				ret += ")";
			}
			String recMods = rec.getModifierString();
			if (recMods.trim().startsWith(";")) {
				recMods = recMods.trim();
				recMods = recMods.substring(1, recMods.length());
			}
			if (recMods.trim().length() > 0) {
				ret += "; " + recMods;
			}
			return ret;
		}
		String ret = getAlias() + " " + getDamageDisplay();
		if (getName().trim().length() > 0) {
			ret = "<i>" + getName() + ":</i>  " + ret;
		}
		ret += " (" + getLevels() + " END, " + rec.getLevels() + " REC)";
		if ((getInput() != null) && (getInput().trim().length() > 0)) {
			ret += ":  " + getInput();
		}
		if (getSelectedOption() != null) {
			ret += " (";
			ret += getSelectedOption().getAlias();

			String adderString = getAdderString();
			String recAdders = rec.getAdderString();
			if ((adderString.trim().length() > 0)
					|| (recAdders.trim().length() > 0)) {
				ret += "; " + adderString;
				if (adderString.trim().length() > 0) {
					ret += ", ";
				}
				if (recAdders.trim().length() > 0) {
					ret += "REC: " + recAdders;
				}
			}
			ret += ")";
		} else {
			String adderString = getAdderString();
			String recAdders = rec.getAdderString();
			if ((adderString.trim().length() > 0)
					|| (recAdders.trim().length() > 0)) {
				ret += " (";
				ret += adderString;
				if (adderString.trim().length() > 0) {
					ret += ", ";
				}
				if (recAdders.trim().length() > 0) {
					ret += "REC: " + recAdders;
				}
				ret += ")";
			}
		}
		boolean theSame = recIsSamePower();
		String modifierString = getModifierString();
		if (!theSame && (modifierString.trim().length() > 0)) {
			ret += " Reserve: ";
			if (modifierString.trim().startsWith(";")) {
				modifierString = modifierString.trim();
				modifierString = modifierString.substring(1, modifierString
						.length());
			}
		}
		ret += modifierString;
		if (!theSame) {
			String recMods = rec.getModifierString();
			if (recMods.trim().startsWith(";")) {
				recMods = recMods.trim();
				recMods = recMods.substring(1, recMods.length());
			}
			if (recMods.trim().length() > 0) {
				ret += "; REC: " + recMods;
			}
		}
		return ret;
	}

	@Override
	public String getDamageDisplay() {
		return "";
	}

	@Override
	public GenericDialog getDialog(boolean isNew, boolean isPower) {
		return new ENDReserveDialog(this, isNew, isPower);
	}

	@Override
	public double getRealCostPreList() {
		boolean theSame = recIsSamePower();
		double active = 0;
		if (theSame) {
			active = getActiveCost();
		} else {
			active = super.getActiveCost();
		}
		double limitationTotal = 0d;
		boolean limitationsApplied = false;
		for (Modifier mod : assignedModifiers) {
			if (mod.getTotalValue() < 0) {
				limitationTotal += mod.getTotalValue();
				limitationsApplied = true;
			}
		}
		if (getParentList() != null) {
			ArrayList<Modifier> parentMods = getParentList()
					.getAssignedModifiers();
			LOOP: for (Modifier mod : parentMods) {
				if (mod.getTypes().contains("VPP")) {
					continue LOOP;
				}
				if (mod.getXMLID().equals("CHARGES")
						&& (getParentList() instanceof Multipower)) {
					continue LOOP;
				}
				if ((mod.getTotalValue() < 0)
						&& ((GenericObject.findObjectByID(assignedModifiers,
								mod.getXMLID()) == null)
								|| mod.getXMLID().equals("GENERIC_OBJECT") || mod
								.getXMLID().equals("CUSTOM_MODIFIER"))) {
					limitationTotal += mod.getTotalValue();
					limitationsApplied = true;
				}
			}
		}
		double ret = active / (1d + Math.abs(limitationTotal));
		if (limitationsApplied) {
			ret = Rounder.roundHalfDown(ret);
		}

		rec.setParent(getParentList());
		if (!theSame) {
			ret += rec.getRealCostPreList();
		}
		if ((ret == 0) && (active > 0)) {
			ret = 1;
		}

		if ((HeroDesigner.getActiveHero() != null)
				&& HeroDesigner.getActiveHero().getRules().multiplierAllowed()
				&& (getMultiplier() != 1)) {
			ret = ret * getMultiplier();
			ret = Rounder.roundHalfDown(ret);
		} else if ((HeroDesigner.getActiveHero() != null)
				&& HeroDesigner.getActiveHero().getRules().multiplierAllowed()
				&& (getParentList() != null)
				&& (getParentList().getMultiplier() != 1)) {
			ret = ret * getParentList().getMultiplier();
			ret = Rounder.roundHalfDown(ret);
		}
		if (getQuantity() > 1) {
			double q = getQuantity();
			int doublings = 0;
			while (q > 1d) {
				doublings += 1;
				q = q / 2d;
			}
			ret += doublings * 5;
		}

		return ret;
	}

	public EnduranceReserveRecovery getRecovery() {
		return rec;
	}

	@Override
	public Element getSaveXML() {
		Element root = super.getSaveXML();
		root.addContent(rec.getSaveXML());
		return root;
	}

	@Override
	protected void init(Element element) {
		super.init(element);
		rec = new EnduranceReserveRecovery(element);
	}

	/**
	 * Utility method to determine if the REC has the same Modifiers as the
	 * Reserve. If so, they are treated as a single Power (for rounding
	 * purposes).
	 * 
	 * @return
	 */
	public boolean recIsSamePower() {
		if (rec == null) {
			return true;
		}
		if (getAssignedModifiers().size() == rec.getAssignedModifiers().size()) {
			OUTER: for (Modifier mod1 : getAssignedModifiers()) {
				for (Modifier mod2 : rec.getAssignedModifiers()) {
					if (mod2.getColumn2Output().equals(mod1.getColumn2Output())) {
						continue OUTER;
					}
				}
				return false; // no match
			}
			return true;
		} else {
			return false;
		}
	}

	@Override
	public void restoreFromSave(Element root) {
		super.restoreFromSave(root);
		Element recRoot = root.getChild("POWER");
		if (recRoot != null) {
			rec.restoreFromSave(recRoot);
		}
	}

	public void setRecovery(EnduranceReserveRecovery val) {
		rec = val;
	}
}