package com.hero.objects.powers;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

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.VariablePowerPool;
import com.hero.objects.modifiers.Modifier;
import com.hero.ui.dialog.GenericDialog;
import com.hero.ui.dialog.NakedModifierDialog;
import com.hero.ui.widgets.PopupMessage;
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 NakedModifier extends Power {

	private static String xmlID = "NAKEDMODIFIER";

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

	protected NakedModifier(Element root, String xmlid) {
		super(root, xmlid);
	}

	@Override
	public double getActiveCost() {
		double ret = getNakedRealCost();
		double advantageTotal = 0;
		for (int i = 0; i < getAssignedModifiers().size(); i++) {
			Modifier mod = getAssignedModifiers().get(i);
			if (!mod.isPrivate()) {
				continue;
			}
			if (mod.getTotalValue() >= 0) {
				advantageTotal += mod.getTotalValue();
			}
		}
		if (getParentList() != null) {
			ArrayList<Modifier> parentMods = getParentList()
					.getAssignedModifiers();
			LOOP: for (int i = 0; i < parentMods.size(); i++) {
				Modifier mod = parentMods.get(i);
				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"))) {
					if ((getParentList() instanceof Multipower)
							|| (getParentList() instanceof ElementalControl)) {
						continue;
					} else {
						advantageTotal += mod.getTotalValue();
					}
				}
			}
		}
		if (advantageTotal > 0) {
			ret = Rounder.roundHalfDown(ret * (1 + advantageTotal));
		}
		return ret;
	}

	@Override
	public double getActiveCost(String excludedID) {
		double ret = getNakedRealCost();
		double advantageTotal = 0;
		for (int i = 0; i < getAssignedModifiers().size(); i++) {
			Modifier mod = getAssignedModifiers().get(i);
			if (!mod.isPrivate() || mod.getXMLID().equals(excludedID)) {
				continue;
			}
			if (mod.getTotalValue() >= 0) {
				advantageTotal += mod.getTotalValue();
			}
		}
		if (getParentList() != null) {
			ArrayList<Modifier> parentMods = getParentList()
					.getAssignedModifiers();
			LOOP: for (int i = 0; i < parentMods.size(); i++) {
				Modifier mod = parentMods.get(i);
				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"))) {
					if ((getParentList() instanceof Multipower)
							|| (getParentList() instanceof ElementalControl)
							|| mod.getXMLID().equals(excludedID)) {
						continue;
					} else {
						advantageTotal += mod.getTotalValue();
					}
				}
			}
		}
		if (advantageTotal > 0) {
			ret = Rounder.roundHalfDown(ret * (1 + advantageTotal));
		}
		return ret;
	}

	@Override
	public String getColumn2Output() {
		String ret = getNakedModifierString();
		if ((getInput() != null) && (getInput().trim().length() > 0)) {
			ret += " for up to " + getLevels() + " Active Points of "
					+ getInput();
		} else {
			ret = getAlias() + ": " + ret + " for up to " + getLevels()
					+ " Active Points";
		}
		if (getName().trim().length() > 0) {
			ret = "<i>" + getName() + ":</i>  " + ret;
		}
		ret = ret.trim();

		String adderString = getAdderString();
		if (adderString.trim().length() > 0) {
			ret += " (" + adderString + ")";
		}

		ret += getModifierString();
		if ((getEndUsage() > 0)
				&& (HeroDesigner.getActiveHero() != null)
				&& (GenericObject.findObjectByID(HeroDesigner.getActiveHero()
						.getPowers(), "ENDURANCERESERVE") != null)
				&& (GenericObject.findObjectByID(getAllAssignedModifiers(),
						"ENDRESERVEOREND") == null)
				&& !HeroDesigner.getInstance().getPrefs().useWG()) {
			if (getUseENDReserve()) {
				ret += " (uses END Reserve)";
			} else {
				ret += " (uses Personal END)";
			}
		}
		return ret;
	}

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

	@Override
	public String getDefinition() {
		String ret = "";
		for (Modifier mod : getAssignedModifiers()) {
			if (mod.isPrivate()) {
				continue;
			}
			if (ret.trim().length() > 0) {
				ret += "\n\n";
			}
			ret += mod.getAlias()
					+ ":  "
					+ (mod.getDefinition().trim().length() > 0 ? PopupMessage
							.normalizeText(mod.getDefinition())
							: "[no definition available]");
		}
		return ret;
	}

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

	@Override
	public int getEndUsage() {
		for (Modifier mod : getAssignedModifiers()) {
			if (mod.isPrivate()) {
				continue;
			}
			if (mod.getXMLID().equals("REDUCEDEND")) {
				return 0;
			}
			if (mod.getXMLID().equals("HARDENED")) {
				return 0;
			}
			if (mod.getXMLID().equals("RESISTANT")) {
				return 0;
			}
			if (mod.getXMLID().equals("IMPENETRABLE")) {
				return 0;
			}
		}
		return super.getEndUsage();
	}

	@Override
	public String getModifierString() {
		String ret = "";
		ArrayList<Modifier> vec = (ArrayList<Modifier>) assignedModifiers
				.clone();
		for (int i = vec.size() - 1; i >= 0; i--) {
			Modifier m = vec.get(i);
			if (!m.isPrivate()) {
				vec.remove(i);
			}
		}
		if ((getParentList() != null)
				&& HeroDesigner.getInstance().getPrefs()
						.showCommonLimitations()) {
			ArrayList<Modifier> parentMods = (ArrayList<Modifier>) getParentList()
					.getAssignedModifiers().clone();
			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) || (getParentList() instanceof VariablePowerPool))
						&& ((GenericObject.findObjectByID(assignedModifiers,
								mod.getXMLID()) == null)
								|| mod.getXMLID().equals("GENERIC_OBJECT")
								|| mod.getXMLID().equals("CUSTOM_MODIFIER") || mod
								.getXMLID().equals("MODIFIER"))) {
					vec.add(mod);
				}
			}
		}
		Collections.sort(vec, new Comparator() {
			public int compare(Object o1, Object o2) {
				if ((o1 instanceof Modifier) && (o2 instanceof Modifier)) {
					Modifier mod1 = (Modifier) o1;
					Modifier mod2 = (Modifier) o2;
					return (int) ((mod1.getTotalValue() - mod2.getTotalValue()) * 100d);
				} else {
					return -1;
				}
			}
		});
		for (Modifier m : vec) {
			if ((m.getTotalValue() >= 0) && m.displayInString()) {
				ret += ", ";
				ret += m.getColumn2Output();
			}
		}
		if (displayActiveCost
				&& ((getActiveCost() != getTotalCost()) || (getRealCost() != getTotalCost()))) {
			ret += " (" + Rounder.roundUp(getActiveCost()) + " Active Points)";
		}
		int numNegative = 0;
		for (Modifier m : vec) {
			if ((m.getTotalValue() < 0) && m.displayInString()) {
				numNegative++;
				if (numNegative == 1) {
					ret += "; ";
				} else {
					ret += ", ";
				}
				ret += m.getColumn2Output();
			}
		}
		return ret;
	}

	public String getNakedModifierString() {
		String ret = "";
		ArrayList<Modifier> vec = (ArrayList<Modifier>) assignedModifiers
				.clone();
		for (int i = vec.size() - 1; i >= 0; i--) {
			Modifier m = vec.get(i);
			if (m.isPrivate()) {
				vec.remove(i);
			}
		}
		Collections.sort(vec, new Comparator() {
			public int compare(Object o1, Object o2) {
				if ((o1 instanceof Modifier) && (o2 instanceof Modifier)) {
					Modifier mod1 = (Modifier) o1;
					Modifier mod2 = (Modifier) o2;
					return (int) ((mod1.getTotalValue() - mod2.getTotalValue()) * 100d);
				} else {
					return -1;
				}
			}
		});
		for (int i = 0; i < vec.size(); i++) {
			Modifier m = vec.get(i);
			if ((m.getTotalValue() >= 0) && m.displayInString()) {
				if (ret.trim().length() > 0) {
					ret += ", ";
				}
				ret += m.getColumn2Output();
			}
		}

		int numNegative = 0;
		for (Modifier m : vec) {
			if ((m.getTotalValue() < 0) && m.displayInString()) {
				numNegative++;
				if (numNegative == 1) {
					ret += "; ";
				} else {
					ret += ", ";
				}
				ret += m.getColumn2Output();
			}
		}
		return ret;
	}

	public double getNakedRealCost() {
		double ret = 0;
		double advantageTotal = 0;
		double limitationTotal = 0;
		for (Modifier mod : getAssignedModifiers()) {
			if (mod.isPrivate()) {
				continue;
			}
			if (mod.getTotalValue() >= 0) {
				advantageTotal += mod.getTotalValue();
			} else {
				limitationTotal += mod.getTotalValue();
			}
		}

		if (advantageTotal > 0) {
			/*
			 * if (limitationTotal != 0) { ret = Rounder
			 * .roundHalfDown((getLevels() * (1 + advantageTotal))); ret =
			 * Rounder.roundHalfDown(ret / (1 + Math.abs(limitationTotal))); ret =
			 * ret - getLevels(); } else {
			 */
			ret = Rounder.roundHalfDown(getLevels() * (1 + advantageTotal)
					- getLevels());
			/* } */
		} /*
		 * else if (limitationTotal != 0) { ret =
		 * Rounder.roundHalfDown(getLevels() / (1 +
		 * Math.abs(limitationTotal)) - getLevels()); }
		 */

		return ret;
	}

	@Override
	public double getRealCostPreList() {
		double ret = getActiveCost();
		double limitationTotal = 0;
		double advantageTotal = 0;
		boolean nakedAdvantagesApplied = false;
		boolean nakedLimitationsApplied = false;
		for (int i = 0; i < getAssignedModifiers().size(); i++) {
			Modifier mod = getAssignedModifiers().get(i);
			if (!mod.isPrivate()) {
				if (mod.getTotalValue() > 0) {
					nakedAdvantagesApplied = true;
				} else {
					nakedLimitationsApplied = true;
				}
			}
			if (mod.isPrivate() && (mod.getTotalValue() > 0)) {
				advantageTotal += mod.getTotalValue();
			} else if (mod.isPrivate() && (mod.getTotalValue() <= 0)) {
				limitationTotal += mod.getTotalValue();
			} else {
				continue;
			}
		}
		if (getParentList() != null) {
			ArrayList<Modifier> parentMods = (ArrayList<Modifier>) getParentList()
					.getAssignedModifiers().clone();
			LOOP: for (Modifier mod : parentMods) {
				if (mod.getTypes().contains("VPP")) {
					continue LOOP;
				}
				if (mod.getXMLID().equals("CHARGES")
						&& (getParentList() instanceof Multipower)) {
					continue LOOP;
				}
				if ((GenericObject.findObjectByID(assignedModifiers, mod
						.getXMLID()) == null)
						|| mod.getXMLID().equals("GENERIC_OBJECT")
						|| mod.getXMLID().equals("CUSTOM_MODIFIER")) {
					if (mod.getTotalValue() < 0) {
						limitationTotal += mod.getTotalValue();
					}
				}

			}
		}
		if (limitationTotal != 0) {
			ret = Rounder.roundHalfDown(ret / (1 + Math.abs(limitationTotal)));
		}

		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 (nakedAdvantagesApplied && !nakedLimitationsApplied && (ret < 1)) {
			ret = 1;
		}
		if (getQuantity() > 1) {
			double q = getQuantity();
			int doublings = 0;
			while (q > 1d) {
				doublings += 1;
				q = q / 2d;
			}
			ret += doublings * 5;
		}
		return ret;
	}

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

	@Override
	public void restoreFromSave(Element root) {
		super.restoreFromSave(root);
	}

}