package com.hero.objects.modifiers;

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

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.List;
import com.hero.objects.characteristics.Characteristic;
import com.hero.objects.powers.Power;
import com.hero.objects.talents.MageSight;
import com.hero.objects.talents.Talent;
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 Charges extends Modifier {
	// make sure special attention is paid to the continuing ADDER.....it uses
	// LVLVAL to
	// represent how many levels to adjust for the time table...
	private static String xmlID = "CHARGES";

	private int clipsLevel;

	private int clipsMultiplier;

	private int clipsAdvantageMultiplier;

	private int boostableLevel;

	private int recoverableLevel;

	private boolean refreshOnUpdate = false;

	private int currentLevels = 0;

	// private long lastTimeStamp = 0;
	private ArrayList<Adder> availAds = new ArrayList<Adder>();

	long lastCall = 0;

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

	public void resetInternal() {
		lastCall = 0;
	}

	private boolean childUsesEND(GenericObject child) {
		if (child == null) {
			return false;
		}
		if (GenericObject.findObjectByID(child.getAssignedModifiers(),
				"LINGERING") != null) {
			return false;
		}
		com.hero.objects.List parent = child.getParentList();
		ArrayList<Modifier> orig = (ArrayList<Modifier>) child
				.getAssignedModifiers().clone();
		ArrayList<Modifier> vec = (ArrayList<Modifier>) child
				.getAssignedModifiers().clone();
		for (int i = vec.size() - 1; i >= 0; i--) {
			Modifier mod = vec.get(i);
			if (mod.getXMLID().equals("CHARGES")) {
				vec.remove(i);
			}
		}
		child.setParent(null);
		child.setAssignedModifiers(vec);
		boolean ret = child.usesEND();
		child.setParent(parent);
		child.setAssignedModifiers(orig);
		return ret;
	}

	private void cleanAssignedAdders() {
		ArrayList<Adder> assignAds = new ArrayList<Adder>();
		for (Adder ad : assignedAdders) {
			if (ad.getXMLID().equals("CONTINUING")
					|| (ad.getXMLID().indexOf("FUEL") >= 0)) {
				if ((parent != null) && (HeroDesigner.getActiveHero() != null)
						&& !HeroDesigner.getActiveHero().isLoading()
						&& !getProgenitor().getIsPrefab()) {
					if (parent instanceof Power) {
						Power pow = (Power) parent;
						if (!pow.getDuration().equals("INSTANT")
								|| (GenericObject.findObjectByID(pow
										.getAssignedModifiers(), "LINGERING") != null || GenericObject
										.findObjectByID(pow
												.getAssignedModifiers(),
												"TIMELIMIT") != null)) {
							assignAds.add(ad);
						}
					} else if (parent instanceof Characteristic) {
						assignAds.add(ad);
					} else if ((parent instanceof Talent)
							|| (parent instanceof MageSight)) {
						assignAds.add(ad);
					} else if (parent instanceof List) {
						assignAds.add(ad);
					} else {
						assignAds.add(ad);
					}
				} else {
					assignAds.add(ad);
				}
			} else {
				assignAds.add(ad);
			}
		}
		assignedAdders = assignAds;
	}

	public ArrayList<Adder> getAssignedAdders() {
		ArrayList<Adder> ret = super.getAssignedAdders();
		if ((parent == null)
				|| (GenericObject.findObjectByID(parent.getAssignedModifiers(),
						"LINGERING") == null) || getProgenitor().getIsPrefab()) {
			return ret;
		}
		GenericObject linger = GenericObject.findObjectByID(parent
				.getAssignedModifiers(), "LINGERING");
		GenericObject cont = GenericObject.findObjectByID(ret, "CONTINUING");
		if (cont != null) {
			ret.remove(cont);
		}
		ArrayList<Adder> avail = getAvailableAdders();
		cont = GenericObject.findObjectByID(avail, "CONTINUING");
		if (cont != null) {
			Adder ad = new Adder(cont);
			ad.setOptions((ArrayList<Adder>) ad.getOptions().clone());
			int count = 0;
			for (Adder adder : linger.getOptions()) {
				count++;
				if (adder.equals(linger.getSelectedOption())) {
					ad.setSelectedOption(ad.getOptions().get(count - 1));
					ad.getOptions().clear();
					ad.getOptions().add(ad.getSelectedOption());
				}
			}
			ad.setSelected(true);
			ret.add(ad);
		}
		return ret;
	}

	public ArrayList<Adder> getAvailableAdders() {
		availAds = new ArrayList<Adder>();
		OUTER: for (Adder ad : availableAdders) {
			if (ad.getXMLID().equals("CLIPS")) {
				for (Adder check : assignedAdders) {
					if (check.getXMLID().equals("CLIPS")) {
						availAds.add(check);
						continue OUTER;
					}
				}
			}
			if (ad.getXMLID().equals("CONTINUING")
					|| (ad.getXMLID().indexOf("FUEL") >= 0)) {
				if ((parent != null) && (HeroDesigner.getActiveHero() != null)
						&& !HeroDesigner.getActiveHero().isLoading()
						&& !getProgenitor().getIsPrefab()) {
					if (!parent.getDuration().equals("INSTANT")
							|| (GenericObject.findObjectByID(parent
									.getAssignedModifiers(), "LINGERING") != null || GenericObject
									.findObjectByID(parent
											.getAssignedModifiers(),
											"TIMELIMIT") != null)) {
						availAds.add(ad);
					} else if (parent instanceof List) {
						boolean okToAdd = true;
						for (GenericObject o : ((List) parent).getObjects()) {
							if (o.getDuration().equals("INSTANT")
									&& GenericObject.findObjectByID(o
											.getAssignedModifiers(),
											"LINGERING") == null
									&& GenericObject.findObjectByID(o
											.getAssignedModifiers(),
											"TIMELIMIT") == null) {
								okToAdd = false;
							}
						}
						if (okToAdd) {
							availAds.add(ad);
						} else {
							continue;
						}
					} else {
						continue;
					}
				} else {
					availAds.add(ad);
				}
			} else {
				availAds.add(ad);
			}
		}
		return availAds;
	}

	public String getColumn2Output() {
		validationCheck();
		String clipsString = "";
		String boostableString = "";
		String recoverableString = "";
		String continuingString1 = "";
		String continuingString2 = "";
		String fuelString = "";
		String increasedTimeString = "";
		String adderString = "";
		String ret = "";
		boolean moreThan1 = true;
		try {
			int check = Integer.parseInt(getSelectedOption().getAlias());
			moreThan1 = check != 1;
		} catch (Exception exp) {
		}
		double val = getTotalValue();
		for (Adder ad : getAssignedAdders()) {
			if (ad.getXMLID().equals("CLIPS")) {
				clipsString = ad.getAlias() + " of";
				continue;
			} else if (ad.getXMLID().equals("CONTINUING")) {
				continuingString1 = ad.getAlias();
				if (moreThan1) {
					continuingString2 = "lasting "
							+ (ad.getSelectedOption() != null ? ad
									.getSelectedOption().getAlias() : "???")
							+ " each";
				} else {
					continuingString2 = "lasting "
							+ (ad.getSelectedOption() != null ? ad
									.getSelectedOption().getAlias() : "???");
				}
				continue;
			} else if (ad.getXMLID().equals("FUEL")) {
				fuelString = ad.getAlias();
				continue;
			} else if (ad.getXMLID().equals("BOOSTABLE")) {
				boostableString = ad.getAlias();
				continue;
			} else if (ad.getXMLID().equals("RECOVERABLE")) {
				recoverableString = ad.getAlias();
				continue;
			} else if (ad.getXMLID().equals("INCREASEDTIME")) {
				if (moreThan1) {
					increasedTimeString = "which Recover every "
							+ ad.getSelectedOption().getAlias();
				} else {
					increasedTimeString = "which Recovers every "
							+ ad.getSelectedOption().getAlias();
				}
				continue;
			} else if (ad.getXMLID().equals("NEVERRECOVER")) {
				increasedTimeString = "which Never Recover";
				if (!moreThan1) {
					increasedTimeString += "s";
				}
				continue;
			}
			if (!ad.displayInString()) {
				continue;
			}
			if (adderString.length() > 0) {
				adderString += "; ";
			}
			adderString += ad.getAlias();
			if ((ad.getSelectedOption() != null)
					&& (ad.getSelectedOption().getAlias().trim().length() > 0)) {
				adderString += ": " + ad.getSelectedOption().getAlias().trim();
			}
		}
		ret = clipsString;
		ret = ret.trim();
		if (getSelectedOption() != null) {
			ret += " " + getSelectedOption().getAlias();
		}
		ret += " " + boostableString;
		ret = ret.trim();
		ret += " " + recoverableString;
		ret = ret.trim();
		ret += " " + continuingString1;
		ret = ret.trim();
		ret += " " + fuelString;
		ret = ret.trim();
		if (moreThan1 || !getAlias().trim().toUpperCase().endsWith("S")) {
			ret += " " + getAlias();
		} else {
			ret += " " + getAlias().substring(0, getAlias().length() - 1);
		}
		ret = ret.trim();
		ret += " " + continuingString2;
		ret = ret.trim();
		ret += " " + increasedTimeString;
		ret = ret.trim();
		if ((getInput() != null) && (getInput().trim().length() > 0)) {
			if (ret.trim().length() > 0) {
				ret += ":  ";
			}
			ret += getInput();
		}
		for (Modifier mod : getAssignedModifiers()) {
			ret += ", " + mod.getAlias();
		}
		ret += " (";
		if (adderString.trim().length() > 0) {
			ret += adderString + "; ";
		}
		if (getComments().trim().length() > 0) {
			ret += getComments() + "; ";
		}
		ret += getFraction(val) + ")";
		return ret;
	}

	public double getLevelCost() {
		return 0;
	}

	public double getLevelValue() {
		return -1;
	}

	public Element getSaveXML() {
		Element root = super.getSaveXML();
		if (GenericObject.findObjectByID(getAssignedAdders(), "CLIPS") != null) {
			Adder clips = (Adder) GenericObject.findObjectByID(
					getAssignedAdders(), "CLIPS");
			root.setAttribute("CLIPS_COST", "" + clips.getBaseCost());
		}
		return root;
	}

	public double getTotalValue() {
		if (parent == null) {
			return 0;
		}
		boolean setmax = false;
		double max = 1;
		if (!parentUsesEND()) {
			max = 0;
			setmax = true;
		}
		if (GenericObject.findObjectByID(getAssignedAdders(), "BOOSTABLE") != null) {
			GenericObject ad = GenericObject.findObjectByID(
					getAssignedAdders(), "BOOSTABLE");
			max += ad.getTotalCost();
		}
		if (GenericObject.findObjectByID(getAssignedAdders(), "CONTINUING") != null) {
			// nothing
		} else {
			setmax = true;
		}
		if (setmax) {
			maxSet = true;
			setMaxCost(max);
		} else {
			maxSet = false;
		}
		minSet = false;
		double ret = super.getTotalValue();
		return ret;
	}

	protected void init(Element element) {
		clipsLevel = 1;
		clipsMultiplier = 2;
		clipsAdvantageMultiplier = 4;
		boostableLevel = 1;
		recoverableLevel = 1;
		super.init(element);
		String check = XMLUtility.getValue(element, "CLIPSLEVEL");
		if ((check != null) && (check.trim().length() > 0)) {
			try {
				clipsLevel = Integer.parseInt(check);
			} catch (NumberFormatException ex) {
			}
		}
		check = XMLUtility.getValue(element, "CLIPSMULTIPLIER");
		if ((check != null) && (check.trim().length() > 0)) {
			try {
				clipsMultiplier = Integer.parseInt(check);
			} catch (NumberFormatException ex) {
			}
		}
		check = XMLUtility.getValue(element, "CLIPSADVANTAGEMULTIPLIER");
		if ((check != null) && (check.trim().length() > 0)) {
			try {
				clipsAdvantageMultiplier = Integer.parseInt(check);
			} catch (NumberFormatException ex) {
			}
		}
		check = XMLUtility.getValue(element, "BOOSTABLELEVEL");
		if ((check != null) && (check.trim().length() > 0)) {
			try {
				boostableLevel = Integer.parseInt(check);
			} catch (NumberFormatException ex) {
			}
		}
		check = XMLUtility.getValue(element, "RECOVERABLELEVEL");
		if ((check != null) && (check.trim().length() > 0)) {
			try {
				recoverableLevel = Integer.parseInt(check);
			} catch (NumberFormatException ex) {
			}
		}
		if (availableAdders == null) {
			availableAdders = new ArrayList<Adder>();
		}
		for (Adder ad : availableAdders) {
			if (ad.getXMLID().equals("CLIPS")) {
				ad.setLevelCost(0);
				ad.setBaseCost(0);
				ad.setMinimumCost(0);
				ad.setMaxCost(0);
			}
		}
	}

	public boolean isLimitation() {
		return true;
	}

	private boolean parentUsesEND() {
		if (parent == null) {
			return false;
		}
		if (GenericObject.findObjectByID(parent.getAssignedModifiers(),
				"LINGERING") != null) {
			return false;
		}
		if (parent instanceof com.hero.objects.List) {
			com.hero.objects.List list = (com.hero.objects.List) parent;
			for (GenericObject o : list.getObjects()) {
				if (childUsesEND(o)) {
					return true;
				}
			}
			return false;
		}
		ArrayList<Modifier> orig = parent.getAssignedModifiers();
		ArrayList<Modifier> temp = (ArrayList<Modifier>) orig.clone();
		if (GenericObject.findObjectByID(orig, getXMLID()) != null) {
			temp.remove(GenericObject.findObjectByID(orig, getXMLID()));
		}
		parent.setAssignedModifiers(temp);
		boolean ret = parent.usesEND();
		parent.setAssignedModifiers(orig);
		if (ret && (HeroDesigner.getActiveHero() != null)) {
			ret = HeroDesigner.getActiveHero().getRules().getAPPerEND() > 0;
		}
		ArrayList<Modifier> vec = (ArrayList<Modifier>) parent
				.getAssignedModifiers().clone();
		if (parent.getParentList() != null) {
			ArrayList<Modifier> par = parent.getParentList()
					.getAssignedModifiers();
			for (Modifier mod : par) {
				if (mod.getXMLID().equals("CHARGES")) {
					continue;
				}
				if (parent.getParentList() instanceof ElementalControl) {
					if (mod.getTotalValue() < 0) {
						vec.add(mod);
					}
				} else {
					vec.add(mod);
				}
			}
		}
		if (GenericObject.findObjectByID(vec, "COSTSEND") != null) {
			ret = true;
		}
		if (GenericObject.findObjectByID(vec, "REDUCEDEND") != null) {
			GenericObject mod = GenericObject.findObjectByID(vec, "REDUCEDEND");
			if (mod.getSelectedOption().getXMLID().equals("HALFEND")) {
				ret = true;
			} else {
				ret = false;
			}
		}
		return ret;
	}

	public boolean refreshAddersOnUpdate() {
		return refreshOnUpdate;
	}

	public void restoreFromSave(Element root) {
		// correct for old problem with 5 Years option on continuing not having
		// a proper XMLID.
		Iterator iter = root.getChildren("ADDER").iterator();
		while (iter.hasNext()) {
			Element el = (Element) iter.next();
			if ((el.getAttributeValue("XMLID") != null)
					&& el.getAttributeValue("XMLID").equals("CONTINUING")) {
				if ((el.getAttributeValue("OPTIONID") != null)
						&& el.getAttributeValue("OPTIONID").equals(
								"GENERIC_OBJECT")) {
					el.setAttribute("OPTIONID", "FIVEYEARS");
					el.setAttribute("OPTION", "FIVEYEARS");
				}
				break;
			}
		}

		super.restoreFromSave(root);

		cleanAssignedAdders();

		if (GenericObject.findObjectByID(getAssignedAdders(), "CLIPS") != null) {
			GenericObject clips = GenericObject.findObjectByID(
					getAssignedAdders(), "CLIPS");
			String cost = XMLUtility.getValue(root, "CLIPS_COST");
			if ((cost != null) && (cost.trim().length() > 0)) {
				try {
					clips.setBaseCost(Double.parseDouble(cost));
					// necessary to correct for the number of clips during a
					// restore:
				} catch (NumberFormatException ex) {
				}
			}
		}
		Adder hold = getSelectedOption();
		selectedOption = null;
		setSelectedOption(hold);

	}

	public void setRefreshAddersOnUpdate(boolean val) {
		refreshOnUpdate = val;
	}

	public void setSelectedOption(Adder option) {
		currentLevels = 0;
		long check = System.currentTimeMillis();
		Adder cur = getSelectedOption();
		ArrayList<Adder> assigned = getAssignedAdders();
		ArrayList<Adder> avail = getAvailableAdders();
		if (option == null) {
			super.setSelectedOption(null);
			return;
		}
		if (check - lastCall > 1000) {
			lastCall = check;
			if ((cur == null)
					|| ((option != null) && (option.getID() != cur.getID()))) {
				refreshOnUpdate = true;
			} else if ((cur != null)
					&& cur.getXMLID().equals(option.getXMLID())) {
				return;
			}
		}
		super.setSelectedOption(option);
		Collections.sort(getOptions(), new Comparator<Adder>() {
			public int compare(Adder o1, Adder o2) {
				try {
					int i1 = Integer.parseInt(o1.getDisplay());
					int i2 = Integer.parseInt(o2.getDisplay());
					return i1 - i2;
				} catch (Exception exp) {

				}
				return o1.getDisplay().compareTo(o2.getDisplay());
			}
		});
		int selectedIndex = getOptions().indexOf(option);
		if (selectedIndex < 0) {
			selectedIndex = 0;
		}
		baseCost = option.getBaseCost();
		for (Adder ad : assigned) {
			if (ad.getXMLID().equals("CONTINUING")
					&& (ad.getSelectedOption() != null)) {
				int contLevel = (int) ad.getSelectedOption().getLevelValue();
				double lastValue = getOptions().get(getOptions().size() - 1)
						.getBaseCost();
				double penultimateValue = getOptions().get(
						getOptions().size() - 2).getBaseCost();
				if (selectedIndex + contLevel + currentLevels < getOptions()
						.size()) {
					Adder m = getOptions().get(
							selectedIndex + contLevel + currentLevels);
					Adder m2 = getOptions().get(selectedIndex + currentLevels);
					ad.getSelectedOption().setBaseCost(
							m.getBaseCost() - m2.getBaseCost());
				} else {
					if (selectedIndex + currentLevels < getOptions().size() - 1) {
						Adder m2 = getOptions().get(
								selectedIndex + currentLevels);
						double val = lastValue - m2.getBaseCost();
						int diff = selectedIndex + contLevel + currentLevels
								- (getOptions().size() - 1);
						for (int k = 0; k < diff; k++) {
							val += lastValue - penultimateValue;
						}
						ad.getSelectedOption().setBaseCost(val);
					} else {
						double val = 0;
						for (int k = 0; k < contLevel; k++) {
							val += lastValue - penultimateValue;
						}
						ad.getSelectedOption().setBaseCost(val);
					}
				}
				for (Adder op : ad.getOptions()) {
					int numLevels = (int) op.getLevelValue();
					if (selectedIndex + numLevels + currentLevels < getOptions()
							.size()) {
						Adder m = getOptions().get(
								selectedIndex + numLevels + currentLevels);
						Adder m2 = getOptions().get(
								selectedIndex + currentLevels);
						op.setBaseCost(m.getBaseCost() - m2.getBaseCost());
					} else {
						if (selectedIndex + currentLevels < getOptions().size() - 1) {
							Adder m2 = getOptions().get(
									selectedIndex + currentLevels);
							double val = lastValue - m2.getBaseCost();
							int diff = selectedIndex + numLevels
									+ currentLevels - (getOptions().size() - 1);
							for (int k = 0; k < diff; k++) {
								val += lastValue - penultimateValue;
							}
							op.setBaseCost(val);
						} else {
							double val = 0;
							for (int k = 0; k < numLevels; k++) {
								val += lastValue - penultimateValue;
							}
							op.setBaseCost(val);
						}
					}
				}
				Adder op = ad.getSelectedOption();
				ad.setSelectedOption(op);
				currentLevels += contLevel;
			} else if (ad.getXMLID().equals("BOOSTABLE")) {
				if (option.getLevelValue() < 2) {
					ad.setSelectable(false);
				} else {
					ad.setSelectable(true);
				}
				if (selectedIndex < getOptions().size() - boostableLevel
						- currentLevels) {
					Adder mod1 = getOptions()
							.get(selectedIndex + currentLevels);
					Adder mod2 = getOptions().get(
							selectedIndex + boostableLevel + currentLevels);
					ad.setBaseCost(mod2.getBaseCost() - mod1.getBaseCost());
					ad.setMinimumCost(mod2.getBaseCost() - mod1.getBaseCost());
					ad.setMaxCost(mod2.getBaseCost() - mod1.getBaseCost());
				} else {
					Adder mod1 = getOptions().get(
							getOptions().size() - boostableLevel - 1);
					Adder mod2 = getOptions().get(getOptions().size() - 1);
					ad.setBaseCost(mod2.getBaseCost() - mod1.getBaseCost());
					ad.setMinimumCost(mod2.getBaseCost() - mod1.getBaseCost());
					ad.setMaxCost(mod2.getBaseCost() - mod1.getBaseCost());
				}
				currentLevels += boostableLevel;
			} else if (ad.getXMLID().equals("RECOVERABLE")) {
				if (selectedIndex < getOptions().size() - recoverableLevel
						- currentLevels) {
					Adder mod1 = getOptions()
							.get(selectedIndex + currentLevels);
					Adder mod2 = getOptions().get(
							selectedIndex + recoverableLevel + currentLevels);
					ad.setBaseCost(mod2.getBaseCost() - mod1.getBaseCost());
					ad.setMinimumCost(mod2.getBaseCost() - mod1.getBaseCost());
					ad.setMaxCost(mod2.getBaseCost() - mod1.getBaseCost());
				} else {
					Adder mod1 = getOptions().get(
							getOptions().size() - recoverableLevel - 1);
					Adder mod2 = getOptions().get(getOptions().size() - 1);
					ad.setBaseCost(mod2.getBaseCost() - mod1.getBaseCost());
					ad.setMinimumCost(mod2.getBaseCost() - mod1.getBaseCost());
					ad.setMaxCost(mod2.getBaseCost() - mod1.getBaseCost());
				}
				currentLevels += recoverableLevel;
			}
		}
		updateClips();
		for (Adder ad : avail) {
			if (ad.getXMLID().equals("CONTINUING")) {
				int contLevel = (int) ad.getSelectedOption().getLevelValue();
				double lastValue = getOptions().get(getOptions().size() - 1)
						.getBaseCost();
				double penultimateValue = getOptions().get(
						getOptions().size() - 2).getBaseCost();
				if (selectedIndex + contLevel + currentLevels < getOptions()
						.size()) {
					Adder m = getOptions().get(
							selectedIndex + contLevel + currentLevels);
					Adder m2 = getOptions().get(selectedIndex + currentLevels);
					ad.getSelectedOption().setBaseCost(
							m.getBaseCost() - m2.getBaseCost());
				} else {
					if (selectedIndex + currentLevels < getOptions().size() - 1) {
						Adder m2 = getOptions().get(
								selectedIndex + currentLevels);
						double val = lastValue - m2.getBaseCost();
						int diff = selectedIndex + contLevel + currentLevels
								- (getOptions().size() - 1);
						for (int k = 0; k < diff; k++) {
							val += lastValue - penultimateValue;
						}
						ad.getSelectedOption().setBaseCost(val);
					} else {
						double val = 0;
						for (int k = 0; k < contLevel; k++) {
							val += lastValue - penultimateValue;
						}
						ad.getSelectedOption().setBaseCost(val);
					}
				}
				for (Adder op : ad.getOptions()) {
					int numLevels = (int) op.getLevelValue();
					if (selectedIndex + numLevels + currentLevels < getOptions()
							.size()) {
						Adder m = getOptions().get(
								selectedIndex + numLevels + currentLevels);
						Adder m2 = getOptions().get(
								selectedIndex + currentLevels);
						op.setBaseCost(m.getBaseCost() - m2.getBaseCost());
					} else {
						if (selectedIndex + currentLevels < getOptions().size() - 1) {
							Adder m2 = getOptions().get(
									selectedIndex + currentLevels);
							double val = lastValue - m2.getBaseCost();
							int diff = selectedIndex + numLevels
									+ currentLevels - (getOptions().size() - 1);
							for (int k = 0; k < diff; k++) {
								val += lastValue - penultimateValue;
							}
							op.setBaseCost(val);
						} else {
							double val = 0;
							for (int k = 0; k < numLevels; k++) {
								val += lastValue - penultimateValue;
							}
							op.setBaseCost(val);
						}
					}
				}
				Adder op = ad.getSelectedOption();
				ad.setSelectedOption(op);
			} else if (ad.getXMLID().equals("BOOSTABLE")) {
				if (option.getLevelValue() < 2) {
					ad.setSelectable(false);
				} else {
					ad.setSelectable(true);
				}
				if (selectedIndex < getOptions().size() - boostableLevel
						- currentLevels) {
					Adder mod1 = getOptions()
							.get(selectedIndex + currentLevels);
					Adder mod2 = getOptions().get(
							selectedIndex + boostableLevel + currentLevels);
					ad.setBaseCost(mod2.getBaseCost() - mod1.getBaseCost());
					ad.setMinimumCost(mod2.getBaseCost() - mod1.getBaseCost());
					ad.setMaxCost(mod2.getBaseCost() - mod1.getBaseCost());
				} else {
					Adder mod1 = getOptions().get(
							getOptions().size() - boostableLevel - 1);
					Adder mod2 = getOptions().get(getOptions().size() - 1);
					ad.setBaseCost(mod2.getBaseCost() - mod1.getBaseCost());
					ad.setMinimumCost(mod2.getBaseCost() - mod1.getBaseCost());
					ad.setMaxCost(mod2.getBaseCost() - mod1.getBaseCost());
				}
			} else if (ad.getXMLID().equals("RECOVERABLE")) {
				if (selectedIndex < getOptions().size() - recoverableLevel
						- currentLevels) {
					Adder mod1 = getOptions()
							.get(selectedIndex + currentLevels);
					Adder mod2 = getOptions().get(
							selectedIndex + recoverableLevel + currentLevels);
					ad.setBaseCost(mod2.getBaseCost() - mod1.getBaseCost());
					ad.setMinimumCost(mod2.getBaseCost() - mod1.getBaseCost());
					ad.setMaxCost(mod2.getBaseCost() - mod1.getBaseCost());
				} else {
					Adder mod1 = getOptions().get(getOptions().size() - 1);
					if (getOptions().size() - recoverableLevel - currentLevels
							- 1 >= 0) {
						mod1 = getOptions().get(
								getOptions().size() - recoverableLevel
										- currentLevels - 1);
					}
					Adder mod2 = getOptions().get(getOptions().size() - 2);
					if (getOptions().size() - currentLevels - 1 >= 0) {
						mod2 = getOptions().get(
								getOptions().size() - currentLevels - 1);
					}
					ad.setBaseCost(mod2.getBaseCost() - mod1.getBaseCost());
					ad.setMinimumCost(mod2.getBaseCost() - mod1.getBaseCost());
					ad.setMaxCost(mod2.getBaseCost() - mod1.getBaseCost());
				}
			}
		}
	}

	private void updateClips() {
		try {
			Adder clips = null;
			Adder assignedClips = null;
			ArrayList<Adder> avail = availableAdders;
			ArrayList<Adder> assigned = assignedAdders;
			double otherAdders = 0;
			double checkVal = getBaseCost();
			for (Adder ad : avail) {
				if (ad.getXMLID().equals("CLIPS")) {
					clips = ad;
					break;
				}
			}
			for (Adder ad : assigned) {
				if (ad.getXMLID().equals("CLIPS")) {
					assignedClips = ad;
					continue;
				}
				// checkVal += ad.getTotalCost();
				otherAdders += ad.getTotalCost();
			}

			if (getSelectedOption() == null) {
				return;
			}
			double clipBase = clips.getBaseCost();
			if (assignedClips != null) {
				clipBase = assignedClips.getBaseCost();
			}
			int numLevels = 0;
			int numAdvantageLevels = 0;
			int selectedIndex = getOptions().indexOf(getSelectedOption());
			if (selectedIndex < 0) {
				selectedIndex = 0;
			}
			double minVal = 0;
			double lastVal = 0;
			double increment = 0;
			Adder last = getOptions().get(getOptions().size() - 1);
			Adder penultimate = getOptions().get(
					getOptions().size() - clipsLevel - 1);
			lastVal = last.getBaseCost() - penultimate.getBaseCost();
			if (lastVal <= 0) {
				lastVal = .25;
			}

			if (selectedIndex + currentLevels < getOptions().size()) {
				checkVal = getOptions().get(selectedIndex + currentLevels)
						.getBaseCost();
			} else {
				checkVal = getOptions().get(getOptions().size() - 1)
						.getBaseCost();
				for (int i = getOptions().size(); i < selectedIndex
						+ currentLevels; i++) {
					checkVal += lastVal;
				}
			}

			if (selectedIndex + currentLevels < getOptions().size()
					- clipsLevel) {
				Adder next = getOptions().get(
						selectedIndex + clipsLevel + currentLevels);
				Adder cur = getOptions().get(selectedIndex + currentLevels);
				minVal = next.getBaseCost() - cur.getBaseCost();
			} else {
				minVal = lastVal;
			}

			if (selectedIndex + currentLevels < getOptions().size()
					- clipsLevel) {
				Adder next = getOptions().get(
						selectedIndex + clipsLevel + currentLevels);
				Adder cur = getOptions().get(selectedIndex + currentLevels);
				increment = next.getBaseCost() - cur.getBaseCost();
			} else {
				increment = minVal;
			}

			if (assignedClips == null) {
				// reset the available
				clipBase = minVal;
			}
			boolean done = false;
			for (int i = selectedIndex + 1 + currentLevels; (i < getOptions()
					.size())
					&& (i >= 0); i += clipsLevel) {
				double check = getOptions().get(i).getBaseCost();
				if (check <= checkVal + clipBase) {
					numLevels++;
					double check2 = getOptions().get(i - currentLevels)
							.getBaseCost()
							+ otherAdders;
					if (check2 > 0) {
						numAdvantageLevels++;
					}
				} else {
					done = true;
					break;
				}
			}
			if (!done) {
				for (int i = getOptions().size(); i < selectedIndex
						+ currentLevels; i++) {
					numLevels++;
					if (last.getBaseCost() + otherAdders + (minVal)
							* (i - getOptions().size()) > 0) {
						numAdvantageLevels++;
					}
				}
			}

			if ((selectedIndex + currentLevels < getOptions().size()
					- clipsLevel * numLevels)
					&& (selectedIndex + currentLevels >= 0)) {
				Adder mod1 = getOptions().get(selectedIndex + currentLevels);
				Adder mod2 = getOptions().get(
						selectedIndex + currentLevels + clipsLevel * numLevels);
				clips.setBaseCost(mod2.getBaseCost() - mod1.getBaseCost());
				clips.setLevelCost(0);
				clips.setLevels(numLevels);
				clips.setMinimumLevel(1);
				clips.setMinimumCost(minVal);
				clips.setMaxCost(10);
				if (assignedClips != null) {
					assignedClips.setBaseCost(mod2.getBaseCost()
							- mod1.getBaseCost());
					assignedClips.setLevelCost(0);
					assignedClips.setLevels(numLevels);
					assignedClips.setMinimumLevel(1);
					assignedClips.setMinimumCost(minVal);
					assignedClips.setMaxCost(10);
				}
			} else {
				clips.setBaseCost(numLevels * minVal);
				clips.setMinimumCost(minVal);
				clips.setMinimumLevel(1);
				clips.setLevels(numLevels);
				clips.setLevelCost(0);
				clips.setMaxCost(10);
				if (assignedClips != null) {
					clips.setLevels(numLevels);
					clips.setMinimumLevel(1);
					assignedClips.setBaseCost(numLevels * minVal);
					assignedClips.setLevelCost(0);
					assignedClips.setMinimumCost(minVal);
					assignedClips.setMaxCost(10);
				}
			}

			// set the adder displays...
			int availNum = 1;
			availNum = (int) Math.pow(clipsMultiplier,
					(numLevels - numAdvantageLevels));
			if (numAdvantageLevels > 0) {
				if (numLevels - numAdvantageLevels <= 0) {
					availNum = 1;
				}
				availNum = availNum
						* (int) Math.pow(clipsAdvantageMultiplier,
								numAdvantageLevels);
			}
			clips.setDisplay(availNum + " clips");
			clips.setAlias(clips.getDisplay());
			if (assignedClips != null) {
				assignedClips.setDisplay(availNum + " clips");
				assignedClips.setAlias(assignedClips.getDisplay());
				currentLevels += clipsLevel * numLevels;
			}
		} catch (Exception exp) {
			exp.printStackTrace();
		}
	}

	public boolean useMultiplier() {
		return false;
	}

	private void validationCheck() {
		if ((getProgenitor() == null)
				|| (GenericObject.findObjectByID(getProgenitor()
						.getAssignedModifiers(), "LINGERING") != null)
				|| (GenericObject.findObjectByID(getProgenitor()
						.getAssignedModifiers(), "TIMELIMIT") != null)
				|| !(getProgenitor() instanceof Power)
				|| !((Power) getProgenitor()).getDuration().equals("INSTANT")
				|| getProgenitor().getIsPrefab()) {
			return;
		}
		for (int i = getAssignedAdders().size() - 1; i >= 0; i--) {
			Adder ad = getAssignedAdders().get(i);
			if (ad.getXMLID().equals("CONTINUING")) {
				getAssignedAdders().remove(i);
			} else if (ad.getXMLID().indexOf("FUEL") >= 0) {
				getAssignedAdders().remove(i);
			}
		}
	}
}