package com.hero.objects.powers;

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.modifiers.Modifier;
import com.hero.ui.dialog.ForceWallDialog;
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 ForceWall extends Power {

	private static String xmlID = "FORCEWALL";

	private int pdLevels;

	private int edLevels;

	private int mdLevels;

	private int powdLevels;

	private int lengthLevels;

	private int heightLevels;

	private double widthLevels;

	private int bodyLevels;

	private int costPerInch;

	private int costPerBody;

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

	public int getBody() {
		return bodyLevels;
	}

	public void setBody(int val) {
		bodyLevels = val;
	}

	public void setWidth(double val) {
		widthLevels = val-.5;
	}

	public double getWidth() {
		return widthLevels+.5;
	}

	@Override
	public ArrayList<Adder> getAvailableAdders() {
		ArrayList<Adder> ret = (ArrayList<Adder>) super.getAvailableAdders()
				.clone();
		for (int i = ret.size() - 1; i >= 0; i--) {
			Adder ad = ret.get(i);
			if (ad.equals("FLASHDEFENSE")) {
				for (Modifier mod : getAssignedModifiers()) {
					if (mod.getXMLID().equals("TRANSPARENT")) {
						ArrayList<Adder> sel = mod.getAssignedAdders();
						if (GenericObject.findObjectByID(sel, "FLASHD") != null) {
							ret.remove(i);
							return ret;
						}
					}
				}
			}
		}
		return ret;
	}

	@Override
	public String getColumn2Output() {
		boolean is6E = HeroDesigner.getActiveTemplate().is6E();
		String ret = getAlias() + " " + getDamageDisplay();
		if (getName().trim().length() > 0) {
			ret = "<i>" + getName() + ":</i>  " + ret;
		}
		if (is6E) {
			ret = ret.trim();
			ret += " ";
		} else {
			ret += "(";
		}

		boolean added = false;
		if (getPdLevels() > 0) {
			if (added) {
				ret += "/";
			}
			ret += getPdLevels() + " PD";
			added = true;
		}
		if (getEdLevels() > 0) {
			if (added) {
				ret += "/";
			}
			ret += getEdLevels() + " ED";
			added = true;
		}
		if (getMdLevels() > 0) {
			if (added) {
				ret += "/";
			}
			ret += getMdLevels() + " Mental Defense";
			added = true;
		}
		if (getPowdLevels() > 0) {
			if (added) {
				ret += "/";
			}
			ret += getPowdLevels() + " Power Defense";
			added = true;
		}
		ret = ret.trim();
		// check for flash defense...
		ArrayList<Adder> orig = getAssignedAdders();
		ArrayList<Adder> copy = (ArrayList<Adder>) orig.clone();
		for (int i = copy.size() - 1; i >= 0; i--) {
			Adder ad = copy.get(i);
			if (ad.getXMLID().equals("FLASHDEFENSE")) {
				if (added) {
					ret += "/";
				}
				ret += ad.getLevels();
				ret += " " + ad.getAlias() + ":  "
						+ ad.getSelectedOption().getAlias();
				added = true;
				copy.remove(i);
			}
		}
		setAssignedAdders(copy);
		String adderString = getAdderString();
		setAssignedAdders(orig);

		if (HeroDesigner.getActiveTemplate().is6E()) {
			ret += ", " + getBody() + " BODY";
			ret += " (up to ";
			// check for length/height
			ret += getLength() + "m long, " + getHeight() + "m tall, and "
					+ getFraction(getWidth()) + "m thick)";
		} else {
			// check for length/height
			if ((getLength() > 1) || (getHeight() > 1)) {
				ret += "; " + getLength() + "\" long and " + getHeight()
						+ "\" tall";
			}
		}

		if (!is6E)
			ret += ")";

		if ((getInput() != null) && (getInput().trim().length() > 0)) {
			ret += ":  " + getInput();
		}
		if (getSelectedOption() != null) {
			ret += " (";
			ret += getSelectedOption().getAlias();

			if (adderString.trim().length() > 0) {
				ret += "; " + adderString;
			}
			ret += ")";
		} else {
			if (adderString.trim().length() > 0) {
				if (is6E) {
					ret += ", " + adderString;
				} else {
					ret += " (" + adderString + ")";
				}
			}
		}
		ret += getModifierString();
		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 = "";
		return ret;
	}

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

	public int getEdLevels() {
		return edLevels;
	}

	public int getHeight() {
		return heightLevels + 1;
	}

	public int getLength() {
		return lengthLevels + 1;
	}

	@Override
	public int getLevels() {
		return pdLevels + edLevels + mdLevels + powdLevels;
	}

	@Override
	public int getMdLevels() {
		return mdLevels;
	}

	public int getPdLevels() {
		return pdLevels;
	}

	public int getPowdLevels() {
		return powdLevels;
	}

	@Override
	public Element getSaveXML() {
		Element root = super.getSaveXML();
		root.setAttribute("PDLEVELS", "" + pdLevels);
		root.setAttribute("EDLEVELS", "" + edLevels);
		root.setAttribute("MDLEVELS", "" + mdLevels);
		root.setAttribute("POWDLEVELS", "" + powdLevels);
		root.setAttribute("LENGTHLEVELS", "" + lengthLevels);
		root.setAttribute("HEIGHTLEVELS", "" + heightLevels);
		root.setAttribute("BODYLEVELS", "" + bodyLevels);
		root.setAttribute("WIDTHLEVELS", "" + widthLevels);
		return root;
	}

	@Override
	public double getTotalCost() {
		double total = super.getTotalCost();
		int mult = 1;
		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")) {
					mult = auto.getDefenseCostMultiplier();
				}
			}
		}
		if (HeroDesigner.getActiveTemplate().is6E()) {
			total += costPerInch/2 * ((lengthLevels)) * mult;
			total += costPerInch/2 * ((heightLevels)) * mult;
			total += costPerInch * ((widthLevels)) * mult;
			total += costPerBody * ((bodyLevels)) * mult;
		} else {
			total += costPerInch * ((lengthLevels)) * mult;
			total += costPerInch * ((heightLevels)) * mult;
		}
		return total;
	}

	@Override
	protected void init(Element element) {
		duration = "CONSTANT";
		target = "HEX";
		range = "Yes";
		end = 10;
		display = "Force Wall";
		levelCost = 5;
		levelValue = 2;
		minimumCost = 5;
		baseCost = 0;
		costPerInch = 2;
		super.init(element);
		canAffectPrimary = true;
		String check = XMLUtility.getValue(element, "COSTPERINCH");
		if ((check != null) && (check.trim().length() > 0)) {
			try {
				costPerInch = Integer.parseInt(check);
			} catch (NumberFormatException ex) {
			}
		}
		check = XMLUtility.getValue(element, "COSTPERBODY");
		if ((check != null) && (check.trim().length() > 0)) {
			try {
				costPerBody = Integer.parseInt(check);
			} catch (NumberFormatException ex) {
			}
		}
	}

	@Override
	public void restoreFromSave(Element root) {
		super.restoreFromSave(root);
		String check = XMLUtility.getValue(root, "PDLEVELS");
		if ((check != null) && (check.trim().length() > 0)) {
			try {
				pdLevels = Integer.parseInt(check);
			} catch (NumberFormatException ex) {
			}
		}
		check = XMLUtility.getValue(root, "EDLEVELS");
		if ((check != null) && (check.trim().length() > 0)) {
			try {
				edLevels = Integer.parseInt(check);
			} catch (NumberFormatException ex) {
			}
		}
		setLevels(edLevels + pdLevels);
		check = XMLUtility.getValue(root, "MDLEVELS");
		if ((check != null) && (check.trim().length() > 0)) {
			try {
				mdLevels = Integer.parseInt(check);
			} catch (NumberFormatException ex) {
			}
		}
		setLevels(edLevels + pdLevels);
		check = XMLUtility.getValue(root, "POWDLEVELS");
		if ((check != null) && (check.trim().length() > 0)) {
			try {
				powdLevels = Integer.parseInt(check);
			} catch (NumberFormatException ex) {
			}
		}
		check = XMLUtility.getValue(root, "LENGTHLEVELS");
		if ((check != null) && (check.trim().length() > 0)) {
			try {
				lengthLevels = Integer.parseInt(check);
			} catch (NumberFormatException ex) {
			}
		}
		check = XMLUtility.getValue(root, "HEIGHTLEVELS");
		if ((check != null) && (check.trim().length() > 0)) {
			try {
				heightLevels = Integer.parseInt(check);
			} catch (NumberFormatException ex) {
			}
		}
		if (HeroDesigner.getActiveTemplate().is6E()) {
			check = XMLUtility.getValue(root, "BODYLEVELS");
			if ((check != null) && (check.trim().length() > 0)) {
				try {
					bodyLevels = Integer.parseInt(check);
				} catch (NumberFormatException ex) {
				}
			}
			check = XMLUtility.getValue(root, "WIDTHLEVELS");
			if ((check != null) && (check.trim().length() > 0)) {
				try {
					widthLevels = Double.parseDouble(check);
				} catch (NumberFormatException ex) {
				}
			}
		}
		setLevels(edLevels + pdLevels + mdLevels + powdLevels);
	}

	public void setEdLevels(int edLevels) {
		this.edLevels = edLevels;
		setLevels(getPdLevels() + getEdLevels() + getMdLevels()
				+ getPowdLevels());
	}

	public void setHeight(int val) {
		heightLevels = val - 1;
	}

	public void setLength(int val) {
		lengthLevels = val - 1;
	}

	public void setMdLevels(int val) {
		mdLevels = val;
		setLevels(getPdLevels() + getEdLevels() + getMdLevels()
				+ getPowdLevels());
	}

	public void setPdLevels(int pdLevels) {
		this.pdLevels = pdLevels;
		setLevels(getPdLevels() + getEdLevels() + getMdLevels()
				+ getPowdLevels());
	}

	public void setPowdLevels(int val) {
		powdLevels = val;
		setLevels(getPdLevels() + getEdLevels() + getMdLevels()
				+ getPowdLevels());
	}

	private String getFraction(double val) {
		String ret = "";
		if (val == 0) {
			return "0";
		}
		val = Math.abs(val);
		if (val > 1) {
			ret += (int) Rounder.roundDown(val);
			val = val - Rounder.roundDown(val);
		}
		if (val == 0) {
			return ret;
		}
		String closestMatch = "";
		double closest = 1d;
		if (Math.abs((double) 1 / (double) 4 - val) < closest) {
			closest = Math.abs((double) 1 / (double) 4 - val);
			closestMatch = "1/4";
		}
		if (Math.abs((double) 1 / (double) 2 - val) < closest) {
			closest = Math.abs((double) 1 / (double) 2 - val);
			closestMatch = "1/2";
		}
		if (Math.abs((double) 3 / (double) 4 - val) < closest) {
			closest = Math.abs((double) 3 / (double) 4 - val);
			closestMatch = "3/4";
		}
		if (Math.abs(1 - val) < closest) {
			closestMatch = "";
			if (ret.length() > 1) {
				int check = Integer.parseInt(ret.substring(1, ret.length()));
				ret = ret.substring(0, 1) + (check + 1);
			} else if ((ret.length() == 1)) {
				ret = "" + (Integer.parseInt(ret) + 1);
			} else if ((ret.trim().length() == 0)) {
				ret = "1";
			} else {
				ret = "-1";
			}
		}
		if (ret.length() > 1) {
			ret += " ";
		}
		ret += closestMatch;
		ret = ret.trim();
		return ret;
	}
}