package com.hero.objects.powers;

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

import org.jdom.Element;

import com.hero.HeroDesigner;
import com.hero.objects.Adder;
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.CustomPowerDialog;
import com.hero.ui.dialog.GenericDialog;
import com.hero.util.Rounder;
import com.hero.util.XMLUtility;

/**
 * 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 CustomPower extends Power {

	private static String xmlID = "CUSTOMPOWER";

	private String col3Output = null;

	private boolean useCustomColumn3 = false;

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

	@Override
	public double getActiveCost() {
		double total = baseCost;

		for (Adder ad : getAssignedAdders()) {
			if (ad.isRequired()) {
				total += ad.getRealCost();
			}
		}
		for (Adder ad : getAssignedAdders()) {
			if (!ad.isRequired() && (ad.getRealCost() > 0)) {
				total += ad.getRealCost();
			}
		}
		if ((total < getMinimumCost()) && isMinSet()) {
			total = getMinimumCost();
		} else if ((total > getMaxCost()) && isMaxSet()) {
			total = getMaxCost();
		}
		for (Adder ad : getAssignedAdders()) {
			if (!ad.isRequired() && (ad.getRealCost() < 0)) {
				total += ad.getRealCost();
			}
		}
		double advantageTotal = 0d;
		boolean advantagesApplied = false;
		for (int i=0; i<assignedModifiers.size(); i++) {
			Modifier mod = assignedModifiers.get(i);
			if (mod.getTotalValue() > 0) {
				advantageTotal += mod.getTotalValue();
				advantagesApplied = 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") || mod
								.getXMLID().equals("MODIFIER"))) {
					if ((getParentList() instanceof Multipower)
							|| (getParentList() instanceof ElementalControl)) {
						continue;
					} else {
						advantageTotal += mod.getTotalValue();
					}
					advantagesApplied = true;
				}
			}
		}
		double val = total * (1 + advantageTotal);
		if (advantagesApplied) {
			val = Rounder.roundHalfDown(val);
		}
		return val;
	}

	@Override
	public double getActiveCost(String excludeID) {
		double total = baseCost;
		for (Adder ad : getAssignedAdders()) {
			if (ad.isRequired()) {
				total += ad.getRealCost();
			}
		}
		for (Adder ad : getAssignedAdders()) {
			if (!ad.isRequired() && (ad.getRealCost() > 0)) {
				total += ad.getRealCost();
			}
		}
		if ((total < getMinimumCost()) && isMinSet()) {
			total = getMinimumCost();
		} else if ((total > getMaxCost()) && isMaxSet()) {
			total = getMaxCost();
		}
		for (Adder ad : getAssignedAdders()) {
			if (!ad.isRequired() && (ad.getRealCost() < 0)) {
				total += ad.getRealCost();
			}
		}
		double advantageTotal = 0d;
		boolean advantagesApplied = false;
		for (Modifier mod : assignedModifiers) {
			if ((mod.getTotalValue() > 0) && !mod.getXMLID().equals(excludeID)) {
				advantageTotal += mod.getTotalValue();
				advantagesApplied = 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)
						&& !mod.getXMLID().equals(excludeID)
						&& ((GenericObject.findObjectByID(assignedModifiers,
								mod.getXMLID()) == null)
								|| mod.getXMLID().equals("GENERIC_OBJECT")
								|| mod.getXMLID().equals("CUSTOM_MODIFIER") || mod
								.getXMLID().equals("MODIFIER"))) {
					if ((getParentList() instanceof Multipower)
							|| (getParentList() instanceof ElementalControl)) {
						continue;
					} else {
						advantageTotal += mod.getTotalValue();
					}
					advantagesApplied = true;
				}
			}
		}
		double val = total * (1 + advantageTotal);
		if (advantagesApplied) {
			val = Rounder.roundHalfDown(val);
		}
		return val;
	}

	@Override
	public String getColumn3Output() {
		if ((col3Output == null) || !useCustomColumn3()) {
			return super.getColumn3Output();
		} else {
			return col3Output;
		}
	}

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

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

	@Override
	public int getLevels() {
		return (int) Rounder.roundUp(baseCost);
	}

	@Override
	public double getRealCostPreList() {
		enhancerApplied = null;
		double active = getActiveCost();
		boolean limitationsApplied = false;
		double limitationTotal = 0d;
		for (int i=0; i<assignedModifiers.size(); i++) {
			Modifier mod = assignedModifiers.get(i);
			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")
						|| mod.getXMLID().equals("MODIFIER")) {
					limitationTotal += mod.getTotalValue();
					limitationsApplied = true;
				}
			}
		}
		double ret = active / (1d + Math.abs(limitationTotal));
		if (limitationsApplied) {
			ret = Rounder.roundHalfDown(ret);
		}
		if ((ret < 1)
				&& ((active > 0) || ((getLevels() > 0)
						&& (getAssignedAdders().size() == 0) && (getBaseCost() >= 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;
	}

	@Override
	public Element getSaveXML() {
		Element root = super.getSaveXML();
		root.setAttribute("DOESBODY", doesBODY ? "Yes" : "No");
		root.setAttribute("DOESDAMAGE", doesDamage ? "Yes" : "No");
		root.setAttribute("DOESKNOCKBACK", doesKnockback ? "Yes" : "No");
		root.setAttribute("KILLING", killing ? "Yes" : "No");
		root.setAttribute("DEFENSE", getDefense());
		root.setAttribute("END", (usesEND ? "Yes" : "No"));
		root.setAttribute("VISIBLE", visible ? "Yes" : "No");
		root.setAttribute("RANGE", range);
		root.setAttribute("DURATION", duration);
		root.setAttribute("TARGET", target);
		root.setAttribute("BASECOST", "" + baseCost);
		root.setAttribute("ENDCOLUMNOUTPUT", (col3Output == null)
				|| (col3Output.trim().length() == 0) ? "" : col3Output);
		root
				.setAttribute("USECUSTOMENDCOLUMN", useCustomColumn3 ? "Yes"
						: "No");
		return root;
	}

	@Override
	public ArrayList<String> getTypes() {
		ArrayList<String> ret = new ArrayList<String>();
		for (Adder ad : getAssignedAdders()) {
			ret.add(ad.getXMLID());
		}
		if (GenericObject.findObjectByID(getAllAssignedModifiers(), "UOO") != null) {
			GenericObject uoo = GenericObject.findObjectByID(
					getAllAssignedModifiers(), "UOO");
			if ((uoo.getSelectedOption() != null)
					&& uoo.getSelectedOption().getXMLID().equals("UAA")) {
				ret.add("ATTACK");
			}
		}
		return ret;
	}

	@Override
	protected void init(Element element) {
		duration = "INSTANT";
		target = "SELFONLY";
		range = "SELF";
		end = 10;
		display = "Custom Power";
		super.init(element);
		if (baseCost == 0) {
			baseCost = 1;
		}
		minimumLevel = -999;
		Collections.sort(availableAdders);
	}

	@Override
	public void restoreFromSave(Element root) {
		super.restoreFromSave(root);
		String check = XMLUtility.getValue(root, "END");
		if ((check != null) && (check.trim().length() > 0)) {
			if (check.trim().toUpperCase().startsWith("Y")) {
				usesEND = true;
			} else {
				usesEND = false;
			}
		}
		check = XMLUtility.getValue(root, "DOESBODY");
		doesBODY = (check != null) && check.trim().startsWith("Y");
		check = XMLUtility.getValue(root, "DOESDAMAGE");
		doesDamage = (check != null) && check.trim().startsWith("Y");
		check = XMLUtility.getValue(root, "DOESKNOCKBACK");
		doesKnockback = (check != null) && check.trim().startsWith("Y");
		check = XMLUtility.getValue(root, "KILLING");
		killing = (check != null) && check.trim().startsWith("Y");
		check = XMLUtility.getValue(root, "VISIBLE");
		visible = (check != null) && check.trim().startsWith("Y");
		check = XMLUtility.getValue(root, "DEFENSE");
		if ((check != null) && (check.trim().length() > 0)) {
			defense = check;
		} else {
			defense = "NONE";
		}
		check = XMLUtility.getValue(root, "RANGE");
		if ((check != null) && (check.trim().length() > 0)) {
			range = check;
		}
		check = XMLUtility.getValue(root, "DURATION");
		if ((check != null) && (check.trim().length() > 0)) {
			duration = check;
		}
		check = XMLUtility.getValue(root, "TARGET");
		if ((check != null) && (check.trim().length() > 0)) {
			target = check;
		}
		check = XMLUtility.getValue(root, "BASECOST");
		if ((check != null) && (check.trim().length() > 0)) {
			try {
				baseCost = Integer.parseInt(check);
			} catch (NumberFormatException ex) {
			}
		}
		check = XMLUtility.getValue(root, "ENDCOLUMNOUTPUT");
		if ((check != null) && (check.trim().length() > 0)) {
			col3Output = check;
		}
		check = XMLUtility.getValue(root, "USECUSTOMENDCOLUMN");
		useCustomColumn3 = (check != null) && check.trim().startsWith("Y");
	}

	public void setColumn3Output(String val) {
		col3Output = val;
	}

	public void setDefense(String val) {
		defense = val;
	}

	public void setDoesBODY(boolean val) {
		doesBODY = val;
	}

	public void setDoesDamage(boolean val) {
		doesDamage = val;
	}

	public void setDoesKnockback(boolean val) {
		doesKnockback = val;
	}

	public void setDuration(String val) {
		duration = val;
	}

	public void setKilling(boolean val) {
		killing = val;
	}

	@Override
	public void setLevels(int val) {
		baseCost = val;
	}

	public void setRange(String val) {
		range = val;
	}

	public void setTarget(String val) {
		target = val;
	}

	public void setUseCustomColumn3(boolean val) {
		useCustomColumn3 = val;
	}

	public boolean useCustomColumn3() {
		if (getAPPerEnd() != 0) {
			return false;
		}
		return useCustomColumn3;
	}

	public void usesEnd(boolean val) {
		usesEND = val;
	}
}