package com.hero.objects.modifiers;

import java.text.NumberFormat;

import org.jdom.Element;

import com.hero.HeroDesigner;
import com.hero.objects.Adder;
import com.hero.objects.GenericObject;
import com.hero.objects.powers.MindScan;
import com.hero.objects.powers.Sense;
import com.hero.ui.dialog.MegascaleDialog;
import com.hero.ui.dialog.ModifierDialog;
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 Megascale extends Modifier {
	private static String xmlID = "MEGASCALE";

	private String scale;

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

	@Override
	public String getColumn2Output() {
		String adderString = "";
		String ret = "";
		ret += getAlias();
		double val = getTotalValue();
		for (Adder ad : getAssignedAdders()) {
			if (adderString.length() > 0) {
				adderString += ", ";
			}
			adderString += ad.getColumn2Output() + " ("
					+ getFraction(ad.getBaseCost()) + ")";
			val -= ad.getBaseCost();
		}
		if ((getInput() != null) && (getInput().trim().length() > 0)) {
			if (ret.trim().length() > 0) {
				ret += ":  ";
			}
			ret += getInput();
		}
		for (Modifier mod : getAssignedModifiers()) {
			ret += ", " + mod.getAlias();
		}
		ret += " (";
		ret += getScale() + "; ";
		if (getSelectedOption() != null) {
			ret += getSelectedOption().getAlias();
			ret += "; ";
		}
		if (getComments().trim().length() > 0) {
			ret += getComments() + "; ";
		}
		ret += getFraction(val) + ")";
		if (adderString.trim().length() > 0) {
			if (ret.trim().length() > 0) {
				ret += ", ";
			}
			ret += adderString;
		}
		return ret;
	}

	@Override
	public ModifierDialog getDialog(GenericObject parent, boolean isNew) {
		return new MegascaleDialog(this, isNew, parent);
	}

	@Override
	public Element getSaveXML() {
		Element ret = super.getSaveXML();
		ret.setAttribute("SCALE", getScale());
		return ret;
	}

	/**
	 * Returns the scale of the Power (e.g. 1" = 1 million km). So long as the
	 * input value is different from the default, the app will not change the
	 * scale automatically. Once they are back in sync, the scale will change
	 * based on the levels purchased.
	 * 
	 * @param val
	 */
	public String getScale() {
		String ret = getScaleValue();
		if ((scale == null) || (scale.trim().length() == 0)
				|| scale.equals(ret)) {
			return ret;
		} else {
			return scale;
		}
	}

	/**
	 * Returns what the default value for the scale is.
	 * 
	 * @return
	 */
	public String getScaleValue() {
		String ret = "1\" = ";
		if (HeroDesigner.getActiveTemplate().is6E()) {
			ret = "1m = ";
		}
		int additional = 0;
		if (getProgenitor() instanceof MindScan) {
			additional = 5;
		}
		if (HeroDesigner.getActiveTemplate().is6E()) {
			additional += 1;
		}
		double val = 1;
		if (HeroDesigner.getActiveTemplate().is6E()) {
			if (getLevels() == 1) val = 10;
		}
		if (getLevels()>1 || !HeroDesigner.getActiveTemplate().is6E()) val = Math.pow(getLevelPower(), getLevels() - 1 + additional);
		double check = 0;
		if (getLevels()>2 || !HeroDesigner.getActiveTemplate().is6E()) check = Math.pow(getLevelPower(), getLevels() - 2 + additional);
		if ((val <= 0) || (val < check)) { // overflow
			ret += "a LONG way";
		} else if (val < 1000000d) {
			ret += NumberFormat.getIntegerInstance().format(val) + " km";
		} else if (val < 1000000000l) {
			ret += NumberFormat.getIntegerInstance().format(val / 1000000)
					+ " million km";
		} else if (val < 1000000000000l) {
			ret += NumberFormat.getIntegerInstance().format(val / 1000000000l)
					+ " billion km";
		} else if (val < 10000000000000l) {
			ret += NumberFormat.getIntegerInstance().format(
					val / 1000000000000l)
					+ " trillion km";
		} else if (val < 10000000000000000000000000000000d) {
			val = val / 10000000000000l;
			if (val < 1000000d) {
				ret += NumberFormat.getIntegerInstance().format(val)
						+ " lightyear" + (val < 1.5 ? "" : "s");
			} else if (val < 1000000000l) {
				ret += NumberFormat.getIntegerInstance().format(val / 1000000)
						+ " million lightyears";
			} else if (val < 1000000000000l) {
				ret += NumberFormat.getIntegerInstance().format(
						val / 1000000000l)
						+ " billion lightyears";
			} else if (val < 1000000000000000l) {
				ret += NumberFormat.getIntegerInstance().format(
						val / 1000000000000l)
						+ " trillion lightyears";
			} else if (val < 1000000000000000000l) {
				ret += NumberFormat.getIntegerInstance().format(
						val / 1000000000000000l)
						+ " quadrillion lightyears";
			}
		} else {
			ret += "a LONG way";
		}
		return ret;
	}

	@Override
	public String included(GenericObject o) {
		String ret = super.included(o);
		if (ret.trim().length() > 0) {
			return ret;
		}

        if (forceAllow()) return ret;
		if (o.getTarget().equals("HEX")) {
			return "";
		} else if (o.getTypes().contains("MOVEMENT")
				&& !o.getXMLID().equals("FTL")
				&& !o.getXMLID().equals("EXTRADIMENSIONALMOVEMENT")) {
			return "";
		}
		if (o.getRangeValue() > 0) {
			return "";
		} else if (o instanceof MindScan) {
			return "";
		} else if (o instanceof Sense) {
			Sense s = (Sense) o;
			if (s.getBuiltInSenseAdders().contains("RANGE")) {
				return "";
			}
		}
		return getDisplay()
				+ " can only be applied to Powers which already affect an area, Movement Powers (except Extradimensional Movement and FTL Travel), and Powers which work at Range.";
	}

	@Override
	public boolean noDisplayDialog() {
		return false;
	}

	@Override
	public void restoreFromSave(Element root) {
		super.restoreFromSave(root);
		String check = XMLUtility.getValue(root, "SCALE");
		if ((check != null) && (check.trim().length() > 0)) {
			setScale(check);
		}
	}

	@Override
	public void setLevels(int val) {
		String orig = getScaleValue();
		super.setLevels(val);
		if ((scale == null) || (scale.trim().length() == 0)
				|| scale.equals(orig)) {
			setScale(getScaleValue());
		}
	}

	/**
	 * Overrides the default scale. So long as the input value is different from
	 * the default, the app will not change the scale automatically. Once they
	 * are back in sync, the scale will change based on the levels purchased.
	 * 
	 * @param val
	 */
	public void setScale(String val) {
		if ((val != null) && (val.trim().length() > 0)) {
			scale = val;
		} else {
			scale = getScaleValue();
		}
	}
}