package com.hero.objects.powers;

import java.text.NumberFormat;
import java.util.ArrayList;

import org.jdom.Element;

import com.hero.HeroDesigner;
import com.hero.objects.Adder;
import com.hero.objects.GenericObject;
import com.hero.objects.enhancers.Enhancer;
import com.hero.objects.modifiers.Modifier;
import com.hero.ui.dialog.GenericDialog;
import com.hero.ui.dialog.PowerDialog;

/**
 * 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 ChangeEnvironment extends Power {
	private static String xmlID = "CHANGEENVIRONMENT";

	private GenericDialog dialog;

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

	/**
	 * Only allows multiple Adders if Multiple Combat Effects has been taken.
	 */
	@Override
	public boolean canAdd(Adder value) {
		boolean ret = super.canAdd(value);
		if (!ret) {
			return false;
		}
		if (GenericObject.findObjectByID(assignedAdders,
				"MULTIPLECOMBATEFFECTS") != null) {
			return true;
		}
		if (value.getXMLID().equals("MULTIPLECOMBATEFFECTS")
				|| value.getXMLID().equals("VARYINGCOMBATEFFECTS")
				|| value.getXMLID().equals("LONG")) {
			return true;
		}
		if (GenericObject.findObjectByID(availableAdders,
				"MULTIPLECOMBATEFFECTS") == null) {
			return true;
		}
		for (Adder ad : assignedAdders) {
			if (!ad.isSelected()) {
				continue;
			}
			if (ad.getXMLID().equals("VARYINGCOMBATEFFECTS")
					|| ad.getXMLID().equals("LONG")) {
				continue;
			} else {
				return false;
			}
		}
		return true;
	}

	@Override
	public ArrayList<Adder> getAssignedAdders() {
		ArrayList<Adder> vec = super.getAssignedAdders();
		ArrayList<Adder> ret = new ArrayList<Adder>();
		if (vec.size() == 0) {
			return vec;
		}
		if (GenericObject.findObjectByID(availableAdders,
				"MULTIPLECOMBATEFFECTS") == null) {
			return vec;
		}
		if (GenericObject.findObjectByID(vec, "MULTIPLECOMBATEFFECTS") != null) {
			return vec;
		}
		Adder maxVal = null;
		for (Adder ad : vec) {
			if (!ad.isSelected()) {
				continue;
			}
			if (ad.getXMLID().equals("VARYINGCOMBATEFFECTS")
					|| ad.getXMLID().equals("LONG")) {
				ret.add(ad);
			} else if ((maxVal == null)
					|| (maxVal.getTotalCost() < ad.getTotalCost())) {
				maxVal = ad;
			}
		}
		if (maxVal != null) {
			ret.add(maxVal);
		}
		assignedAdders = ret;
		return ret;
	}

	@Override
	public ArrayList<Adder> getAvailableAdders() {
		ArrayList<Adder> vec = super.getAvailableAdders();
		ArrayList<Adder> ret = new ArrayList<Adder>();
		boolean effectsLocked = noMoreEffects();
		ArrayList<Adder> assigned = getAssignedAdders();
		if (vec.size() == 0) {
			return vec;
		}
		if (GenericObject.findObjectByID(availableAdders,
				"MULTIPLECOMBATEFFECTS") == null) {
			return vec;
		}
		for (Adder ad : vec) {
			if (ad.getXMLID().equals("VARYINGCOMBATEFFECTS")
					|| ad.getXMLID().equals("LONG")
					|| ad.getXMLID().equals("MULTIPLECOMBATEFFECTS")) {
				ret.add(ad);
			} else {
				if (GenericObject.findObjectByID(assigned, ad.getXMLID()) == null) {
					ad.setSelectable(!effectsLocked);
				}
				ret.add(ad);
			}
		}
		return ret;
	}

	@Override
	public String getColumn2Output() {
		String ret = getAlias() + " " + getDamageDisplay();
		ret = ret.trim();
		if (getName().trim().length() > 0) {
			ret = "<i>" + getName() + ":</i>  " + ret;
		}
		if ((getInput() != null) && (getInput().trim().length() > 0)) {
			ret += ":  " + getInput();
		}
		ret = ret + " (";
		String adderString = "";
		for (Adder ad : getAssignedAdders()) {
			if (ad.getXMLID().equals("PERROLL")
					|| ad.getXMLID().equals("PERROLLGROUP")) {
				if (adderString.trim().length() > 0) {
					adderString += ", ";
				}
				adderString += "-" + ad.getLevels() + " to "
						+ ad.getSelectedOption().getAlias() + " PER Rolls";
				ad.setDisplayInString(false);
			}
		}
		String check = getAdderString();
		if (check.trim().length() > 0) {
			if (adderString.trim().length() > 0) {
				adderString += ", ";
			}
			adderString += check;
		}
		if (getSelectedOption() != null) {
			ret += ", ";
			ret += getSelectedOption().getAlias();
			if (adderString.trim().length() > 0) {
				ret += ", " + adderString;
			}
		} else {
			if (adderString.trim().length() > 0) {
				ret += adderString;
			}
		}
		ret += ")";
		Modifier alteredShape = (Modifier) GenericObject.findObjectByID(
				getAssignedModifiers(), "ALTEREDSHAPE");
		if (alteredShape != null) {
			getAssignedModifiers().remove(alteredShape);
		}
		ret += getModifierString();
		if (alteredShape != null) {
			getAssignedModifiers().add(alteredShape);
		}
		if ((getEndUsage() > 0)
				&& (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() {
		String ret = "";
		if (!HeroDesigner.getActiveTemplate().is6E()) {
			double radius = Math.pow(getLevelPower(), getLevels() - 1);
			ret = NumberFormat.getIntegerInstance().format(radius)
					+ "\" radius";
			Modifier alteredShape = null;
			if (GenericObject.findObjectByID(getAssignedModifiers(),
					"ALTEREDSHAPE") != null) {
				alteredShape = (Modifier) GenericObject.findObjectByID(
						getAssignedModifiers(), "ALTEREDSHAPE");
			} else {
				return ret;
			}

			if ((alteredShape != null)
					&& (alteredShape.getSelectedOption() != null)
					&& alteredShape.getSelectedOption().getXMLID().equals(
							"CONE")) {
				ret += " ("
						+ NumberFormat.getIntegerInstance().format(radius * 2)
						+ "\" Cone; +0)";
			} else if ((alteredShape != null)
					&& (alteredShape.getSelectedOption() != null)
					&& alteredShape.getSelectedOption().getXMLID().equals(
							"LINE")) {
				double width = 1;
				if (GenericObject.findObjectByID(alteredShape
						.getAssignedAdders(), "DOUBLEWIDTH") != null) {
					Adder ad = (Adder) GenericObject.findObjectByID(
							alteredShape.getAssignedAdders(), "DOUBLEWIDTH");
					width = Math.pow(ad.getLevelPower(), ad.getLevels());
				}
				if (width == 1) {
					ret += " ("
							+ NumberFormat.getIntegerInstance().format(
									radius * 2) + "\" Line; +0)";
				} else {
					ret += " ("
							+ NumberFormat.getIntegerInstance().format(
									radius * 2)
							+ "\" long and "
							+ NumberFormat.getIntegerInstance().format(width)
							+ "\" wide Line; "
							+ alteredShape.getFraction(alteredShape
									.getTotalValue()) + ")";
				}
			} else if ((alteredShape != null)
					&& (alteredShape.getSelectedOption() != null)
					&& alteredShape.getSelectedOption().getXMLID()
							.equals("ANY")) {
				ret += " (" + NumberFormat.getIntegerInstance().format(radius)
						+ "\" Any Area; +0)";
			}

		}
		return ret;
	}

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

	@Override
	public double getTotalCost() {
		enhancerApplied = null;
		double total = getBaseCost();
		if (getLevelValue() != 0) {
			double bd = getLevels() / getLevelValue() * getLevelCost();
			total += bd;
		}
		double min = 99999;
		int minIndex = -1;
		int count = -1;
		for (Adder ad : getAssignedAdders()) {
			count++;
			if ((ad.getRealCost() > 0) && (ad.getLevelCost() > 0)
					&& (ad.getLevelValue() > 0)) {
				if (ad.getLevelCost() / ad.getLevelValue() < min) {
					min = ad.getLevelCost() / ad.getLevelValue();
					minIndex = count;
				}
			}
		}
		count = -1;
		for (Adder ad : getAssignedAdders()) {
			count++;
			if (ad.getRealCost() > 0) {
				total += ad.getRealCost();
				if (count == minIndex && !HeroDesigner.getActiveTemplate().is6E()) {
					total -= ad.getLevelCost() / ad.getLevelValue();
				}
			}
		}
		if ((total < getMinimumCost()) && isMinSet()) {
			total = getMinimumCost();
		} else if ((total > getMaxCost()) && isMaxSet()) {
			total = getMaxCost();
		}
		for (Adder ad : getAssignedAdders()) {
			if (ad.getRealCost() < 0) {
				total += ad.getRealCost();
			}
		}
		if ((getTypes() != null) && (getTypes().size() > 0)) {
			ArrayList<GenericObject> enhancers = HeroDesigner.getActiveHero()
					.getSkills();
			OUTER: for (GenericObject o : enhancers) {
				if (o instanceof Enhancer) {
					Enhancer enhancer = (Enhancer) o;
					for (String s : getTypes()) {
						if (enhancer.appliesToType(s)) {
							enhancerApplied = enhancer;
							// just take the first match and leave it at
							// that...
							if (total > enhancer.getCostSavings()) {
								total -= enhancer.getCostSavings();
							} else if (total > 0) {
								total = 1;
							}
							break OUTER;
						}
					}
				}
			}
			enhancers = HeroDesigner.getActiveHero().getPerks();
			OUTER: for (GenericObject o : enhancers) {
				if (o instanceof Enhancer) {
					Enhancer enhancer = (Enhancer) o;
					for (String s : getTypes()) {
						if (enhancer.appliesToType(s)) {
							enhancerApplied = enhancer;
							// just take the first match and leave it at
							// that...
							if (total > enhancer.getCostSavings()) {
								total -= enhancer.getCostSavings();
							} else if (total > 0) {
								total = 1;
							}
							break OUTER;
						}
					}
				}
			}
		}
		if (getTypes().contains("DEFENSE")
				&& (HeroDesigner.getActiveHero() != null)) {
			if (GenericObject.findObjectByID(HeroDesigner.getActiveHero()
					.getPowers(), "AUTOMATON") != null) {
				Automaton auto = (Automaton) GenericObject.findObjectByID(
						HeroDesigner.getActiveHero().getPowers(), "AUTOMATON");
				if (auto.getSelectedOption().getXMLID().toUpperCase()
						.startsWith("NOSTUN")) {
					total = total * auto.getDefenseCostMultiplier();
				}
			}
		}
		return total;
	}

	/**
	 * Whether other effect Adders can be assigned (required Multiple Combat
	 * Effects)
	 * 
	 * @return
	 */
	private boolean noMoreEffects() {
		ArrayList<Adder> vec = super.getAssignedAdders();
		if (vec.size() == 0) {
			return false;
		}
		if (GenericObject.findObjectByID(availableAdders,
				"MULTIPLECOMBATEFFECTS") == null) {
			return false;
		}
		if (GenericObject.findObjectByID(vec, "MULTIPLECOMBATEFFECTS") != null) {
			return false;
		}
		for (Adder ad : vec) {
			if (!ad.isSelected()) {
				continue;
			}
			if (ad.getXMLID().equals("VARYINGCOMBATEFFECTS")
					|| ad.getXMLID().equals("LONG")) {
				continue;
			} else {
				return true;
			}
		}
		return false;
	}
}