package com.hero.objects;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

import org.jdom.Element;

import com.hero.HeroDesigner;
import com.hero.objects.modifiers.Modifier;
import com.hero.objects.powers.Automaton;
import com.hero.objects.powers.CompoundPower;
import com.hero.ui.dialog.GenericDialog;
import com.hero.ui.dialog.ListDialog;
import com.hero.util.Rounder;

/**
 * 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 List extends GenericObject {

    protected ArrayList<GenericObject> containedObjects;

    private ArrayList<Modifier> privateMods;

    private ArrayList<Adder> privateAdders;

    @Override
    public void restoreFromSave(Element root) {
        super.restoreFromSave(root);
        separatePrivateMods();
        separatePrivateAdders();
    }

    private void separatePrivateMods() {
        for (int i = getAssignedModifiers().size() - 1; i >= 0; i--) {
            Modifier mod = getAssignedModifiers().get(i);
            if (mod.isPrivate()) {
                getAssignedModifiers().remove(i);
                getPrivateMods().add(mod);
            }
        }
    }

    private void separatePrivateAdders() {
        for (int i = getAssignedAdders().size() - 1; i >= 0; i--) {
            Adder ad = getAssignedAdders().get(i);
            if (ad.isPrivate()) {
                getAssignedAdders().remove(i);
                getPrivateAdders().add(ad);
            }
        }
    }

    public List(Element root, String xmlID) {
        super(root, xmlID);
    }

    public List(Element root) {
        super(root);
    }

    /**
     * Creates an empty list with the given name.
     * 
     * @param name
     */
    public List(String name) {
        super();
        containedObjects = new ArrayList<GenericObject>();
        init(new Element("LIST")); // fool it into initializing for
        // us
        display = name;
        alias = name;
        resetID();
    }

    @Override
    protected void init(Element element) {
        containedObjects = new ArrayList<GenericObject>();
        duration = "";
        super.init(element);
        availableModifiers = new ArrayList<Modifier>();
        availableAdders = new ArrayList<Adder>();
    }

    @Override
    public List clone() {
        List clone;
        clone = (List) super.clone();
        clone.containedObjects = (ArrayList<GenericObject>) containedObjects
                .clone();
        if (privateMods == null) {
            privateMods = new ArrayList<Modifier>();
        }
        clone.privateMods = new ArrayList<Modifier>();
        if (privateAdders == null) {
            privateAdders = new ArrayList<Adder>();
        }
        clone.privateAdders = new ArrayList<Adder>();
        for (Modifier mod : privateMods) {
            mod = mod.clone();
            clone.privateMods.add(mod);
        }
        for (Adder ad : privateAdders) {
            Adder ad2 = (Adder) ad.clone();
            clone.privateAdders.add(ad);
        }
        return clone;
    }

    /**
     * Adds the specified object into the List.
     * 
     * @param obj
     */
    public void addObject(GenericObject obj) {
        for (int i=0; i<containedObjects.size() && obj.getID() > 1; i++) {
            if (containedObjects.get(i).getID() == obj.getID()) {
                containedObjects.set(i, obj);
                return;
            }
        }
        containedObjects.add(obj);
    }

    private int objectSizeCheck = -1;
    /**
     * Returns a Vector of GenericObjects representing the slots in the List.
     * 
     * @return
     */
    public ArrayList<GenericObject> getObjects() {
    	if (containedObjects != null && containedObjects.size() != objectSizeCheck) {
    		cleanupObjects();
    		objectSizeCheck = containedObjects.size();
    	}
        return containedObjects;
    }
    
    private void cleanupObjects() {
    	ArrayList<Long> ids = new ArrayList<Long>();
    	for (int i = containedObjects.size()-1; i>=0; i--) {
    		if (ids.contains(containedObjects.get(i).getID())) {
    			containedObjects.remove(i);
    		} else {
    			ids.add(containedObjects.get(i).getID());
    		}
    	}
    }
    
    public void remove(GenericObject object) {
    	for (int i = containedObjects.size()-1; i>=0; i--) {
    		GenericObject o = containedObjects.get(i);
    		if (o.getID() == object.getID()) {
    			containedObjects.remove(i);
    		}
    	}
    	updateChildPositions();
    }

    /**
     * Sets the slots in the List. Vector should contain GenericObjects. No
     * nested Lists.
     * 
     * @param val
     */
    public void setObjects(ArrayList<GenericObject> val) {
        containedObjects = val;
    }

    /**
     * Removes the specified slot from the list.
     * 
     * @param position
     */
    public void removeObject(int position) {
        updateChildPositions();
        containedObjects.remove(position);
    }

    @Override
    public Element getSaveXML() {
        Element ret = getGeneralSaveXML();
        ret.setName("LIST");
        return ret;
    }

    @Override
    public String getColumn2Output() {
        String ret = getAlias();
        String a = getAdderString();
        if (a.trim().length() > 0) {
            ret += ", " + a;
        }
        String m = getModifierString();
        ret += m;
        return ret;
    }

    /**
     * Determines the actual cost of a slot. By default, a plain list will
     * simply apply any adders to the slot's real cost.
     * 
     * @param child
     * @return
     */
    public double getRealCostForChild(GenericObject child) {
        ArrayList realAdders = child.getAssignedAdders();
        ArrayList calcAdders = (ArrayList) realAdders.clone();
        calcAdders.addAll(getAssignedAdders());
        child.setAssignedAdders(calcAdders);
        double val = child.getRealCostPreList();
        child.setAssignedAdders(realAdders);
        return val;
    }

    /**
     * Returns the String to use for the prefix to the main display of a slot.
     * 
     * @param child
     * @return
     */
    public String getColumn2Prefix(GenericObject child) {
        String ret = "";
        updateChildPositions();
        // int childPosition = getObjects().indexOf(child);
        // childPosition++;
        int childPosition = child.getPosition() - getPosition();

        if (childPosition < 10) {
            ret = childPosition + ")  ";
        } else {
            ret = childPosition + ") ";
        }
        return ret;
    }

    /**
     * Returns the suffix to append to the main display of a slot.
     * 
     * @param child
     * @return
     */
    public String getColumn2Suffix(GenericObject child) {
        return "";
    }

    /**
     * Returns the suffix to append to the column 1 output for a slot (typically
     * the cost).
     * 
     * @param child
     * @return
     */
    public String getColumn1Suffix(GenericObject child) {
        return "";
    }

    /**
     * Re-orders the list's objects Vector by position of the child in the
     * display.
     */
    public void updateChildPositions() {

        for (int i = getObjects().size() - 1; i >= 0; i--) {
            if (getObjects().get(i) == null) {
                getObjects().remove(i);
            }
        }
        Collections.sort(getObjects(), new Comparator() {

            public int compare(Object o1, Object o2) {
                if (o1 instanceof GenericObject && o2 instanceof GenericObject) {
                    GenericObject g1 = (GenericObject) o1;
                    GenericObject g2 = (GenericObject) o2;
                    return g1.getPosition() - g2.getPosition();
                } else {
                    return o1.toString().compareTo(o2.toString());
                }
            }

            @Override
            public boolean equals(Object obj) {
                return false;
            }
        });

    }

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

    /**
     * Whether or not the object is allowed to be added to the List.
     * 
     * @param o
     * @return
     */
    public boolean objectAllowed(GenericObject o) {
        return objectAllowed(o, true);
    }

    /**
     * Whether or not the object is allowed to be added to the list. If
     * displayPopup is true, a popup dialog will be shown if the item cannot be
     * added to the list or if the item triggers any warnings.
     * 
     * @param o
     * @param displayPopup
     * @return
     */
    public boolean objectAllowed(GenericObject o, boolean displayPopup) {
        if (getAlias().trim().length() == 0) {
            error = "";
            return false;
        }
        if (o instanceof CompoundPower) {
            CompoundPower cp = (CompoundPower) o;
            for (int i = 0; i < cp.getPowers().size(); i++) {
                GenericObject obj = cp.getPowers().get(i).clone();
                obj.setMainPower(null);
                boolean check = objectAllowed(obj, displayPopup);
                if (!check) {
                    return check;
                }
            }
            if (cp.getPowers().size() > 0) {
                return true;
            }
        }
        if (!o.allowsOtherModifiers() && getAssignedModifiers().size() > 0) {
            error = o.getAlias()
                    + " is not allowed to have Modifiers assigned to it in its current configuration.\n\n"
                    + o.getAlias() + " will be placed outside of the list.";
            return false;
        }
        if (o instanceof List) {
            error = "You cannot add a List into another List.  New list will be placed outside of selection.";
            return false;
        } else if (o instanceof VariablePowerPool) {
            error = "You cannot add a VPP into a List.  The Variable Power Pool will be placed outside of the selection.";
            return false;
        } else if (getAssignedModifiers().size() > 0
                && HeroDesigner.getInstance().getPrefs()
                        .isModifierIntelligenceOn()) {
            List oldParent = o.getParentList();
            o.setParent(null);
            o.setListModCheck(true);
            ArrayList<Modifier> listMods = getAssignedModifiers();
            ArrayList<Modifier> orig = o.getAssignedModifiers();
            ArrayList<Modifier> slotMods = (ArrayList<Modifier>) orig.clone();
            ArrayList<Modifier> addFromList = new ArrayList<Modifier>();
            for (int i=0; i<listMods.size(); i++) {
            	Modifier mod = listMods.get(i);
                if (GenericObject.findObjectByID(orig, mod.getXMLID()) == null) {
                    addFromList.add(mod);
                }
            }
            slotMods.addAll(addFromList);
            o.setAssignedModifiers(slotMods);
            for (int j = addFromList.size() - 1; j >= 0; j--) {
                Modifier mod = addFromList.get(j);
                slotMods.remove(mod);
                o.setAssignedModifiers(slotMods);
                String check = mod.included(o);
                if (check.trim().length() > 0) {
                    o.setListModCheck(false);
                    error = mod.getAlias() + " cannot be applied to "
                            + o.getAlias() + ".\n\nReason:  " + check + "\n\n"
                            + o.getAlias()
                            + " will be placed outside of the list.";
                    return false;
                }
                slotMods.add(mod);
            }
            o.setAssignedModifiers(orig);
            o.setListModCheck(false);
            o.setParent(oldParent);
        }
        return true;
    }

    protected String error;

    /**
     * Returns the reason why an item failed to be added to a list. This value
     * is over-written with each call to objectAllowed().
     * 
     * @return
     */
    public String getRejectionMessage() {
        if (error == null) {
            return "You cannot add a List into another List.  New list will be placed outside of selection.";
        } else {
            return error;
        }
    }

    @Override
    public String toString() {
        String ret = getName();
        if (ret == null) {
            ret = "";
        }
        if (ret.trim().length() > 0) {
            ret += ":  ";
        }
        ret += getAlias();
        return ret;
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.hero.objects.GenericObject#getColumn3Output()
     */
    @Override
    public String getColumn3Output() {
        return "";
    }

    /**
     * Returns a Vector of Modifier objects that have been Assigned to the List
     * as private Modifiers.
     * 
     * @return
     */
    public ArrayList<Modifier> getPrivateMods() {
        if (privateMods == null) {
            privateMods = new ArrayList<Modifier>();
        }
        return privateMods;
    }

    public ArrayList<Adder> getPrivateAdders() {
        if (privateAdders == null) {
            privateAdders = new ArrayList<Adder>();
        }
        return privateAdders;
    }

    public void setPrivateAdders(ArrayList<Adder> val) {
        privateAdders = val;
    }

    /**
     * Sets the private Modifiers assigned to the LIst. Vector should contain
     * only Modifier objects.
     * 
     * @param vec
     */
    public void setPrivateMods(ArrayList<Modifier> vec) {
        privateMods = vec;
    }

    @Override
    protected void getModifierSaveXML(Element root) {
    	for (int i=0; i<getModifiers().size(); i++) {
    		Modifier mod = getModifiers().get(i);
            root.addContent(mod.getSaveXML());
        }
    	for (int i=0; i<getPrivateMods().size(); i++) {
    		Modifier mod = getPrivateMods().get(i);
    		root.addContent(mod.getSaveXML());
        }
    }

    @Override
    protected void getAdderSaveXML(Element parent) {
        super.getAdderSaveXML(parent);
        for (Adder ad : getPrivateAdders()) {
            if (!ad.isSelected()) {
                continue;
            }
            parent.addContent(ad.getSaveXML());
        }
    }

    @Override
    public String getModifierString() {
        String publicAdv = "";
        String privateAdv = "";
        String publicLim = "";
        String privateLim = "";
        String ret = "";
        ArrayList<Modifier> vec = (ArrayList<Modifier>) assignedModifiers
                .clone();
        ArrayList<Modifier> vec2 = (ArrayList<Modifier>) getPrivateMods()
                .clone();
        Comparator comparator = new Comparator() {

            public int compare(Object o1, Object o2) {
                if (o1 instanceof Modifier && o2 instanceof Modifier) {
                    Modifier mod1 = (Modifier) o1;
                    Modifier mod2 = (Modifier) o2;
                    return (int) ((mod1.getTotalValue() - mod2.getTotalValue()) * 100d);
                } else {
                    return -1;
                }
            }
        };
        Collections.sort(vec, comparator);
        Collections.sort(vec2, comparator);
        for (Modifier m : vec) {
            if (m.getTotalValue() >= 0) {
                if (publicAdv.trim().length() > 0) {
                    publicAdv += ", ";
                }
                publicAdv += m.getColumn2Output();
            }
            if (m.getTotalValue() < 0) {
                if (publicLim.trim().length() > 0) {
                    publicLim += ", ";
                }
                publicLim += m.getColumn2Output();
            }
        }
        for (Modifier m : vec2) {
            if (m.getTotalValue() >= 0) {
                if (privateAdv.trim().length() > 0) {
                    privateAdv += ", ";
                }
                privateAdv += m.getColumn2Output();
            }
            if (m.getTotalValue() < 0) {
                if (privateLim.trim().length() > 0) {
                    privateLim += ", ";
                }
                privateLim += m.getColumn2Output();
            }
        }
        if (privateAdv.trim().length() > 0) {
            ret += privateAdv;
        }
        if (publicAdv.trim().length() > 0) {
            if (ret.trim().length() > 0) {
                ret += "; ";
            }
            ret += "all slots " + publicAdv;
        }
        if (displayActiveCost
                && (getActiveCost() != getTotalCost() || getRealCost() != getTotalCost())) {
            ret += " (" + Rounder.roundUp(getActiveCost()) + " Active Points)";
        }
        if (privateLim.trim().length() > 0) {
            if (ret.trim().length() > 0) {
                ret += "; ";
            }
            ret += privateLim;
        }
        if (publicLim.trim().length() > 0) {
            if (ret.trim().length() > 0) {
                ret += "; ";
            }
            ret += "all slots " + publicLim;
        }
        if (ret.trim().length() > 0) {
            ret = ", " + ret;
        }
        return ret;
    }

    /**
     * Returns the display string for all assigned adders. Takes into account
     * the display settings for each Adder.
     * 
     * @return
     */
    @Override
    public String getAdderString() {
        ArrayList<String> vec = new ArrayList<String>();
        ArrayList<String> vec2 = new ArrayList<String>();
        ArrayList<String> groupVec = new ArrayList<String>();
        for (Adder adder : getAssignedAdders()) {
            if ((adder.getAvailableAdders().size() > 0 || adder.isGroup())
                    && adder.isSelected()) {
                adder.addAliasToVector(groupVec);
            } else {
                adder.addAliasToVector(vec);
            }
        }
        for (Adder adder : getPrivateAdders()) {
            adder.addAliasToVector(vec2);
        }
        Collections.sort(groupVec, new Comparator() {

            public int compare(Object o1, Object o2) {
                String s1 = o1.toString().toUpperCase();
                String s2 = o2.toString().toUpperCase();
                return s1.compareTo(s2);
            }

            @Override
            public boolean equals(Object o) {
                return false;
            }
        });
        Collections.sort(vec, new Comparator() {

            public int compare(Object o1, Object o2) {
                String s1 = o1.toString().toUpperCase();
                String s2 = o2.toString().toUpperCase();
                return s1.compareTo(s2);
            }

            @Override
            public boolean equals(Object o) {
                return false;
            }
        });
        Collections.sort(vec2, new Comparator() {

            public int compare(Object o1, Object o2) {
                String s1 = o1.toString().toUpperCase();
                String s2 = o2.toString().toUpperCase();
                return s1.compareTo(s2);
            }

            @Override
            public boolean equals(Object o) {
                return false;
            }
        });
        StringBuffer ret = new StringBuffer();
        for (String a : vec2) {
            if (a.toString().trim().length() > 0) {
                if (ret.length() > 0) {
                    ret.append(", ");
                }
                ret.append(a.toString().trim());
            }
        }
        boolean others = false;
        for (String s : groupVec) {
            if (s.toString().trim().length() > 0) {
                others = true;
                break;
            }
        }
        for (String s : vec) {
            if (s.trim().length() > 0) {
                others = true;
                break;
            }
        }
        if (others) {
            if (ret.length() > 0) {
                ret.append("; ");
            }
            ret.append("all slots: ");
        }
        for (int i = 0; i < groupVec.size(); i++) {
            if (groupVec.get(i).trim().length() > 0) {
                if (i > 0) {
                    ret.append(", ");
                }
                ret.append(groupVec.get(i).trim());
            }
        }
        for (int i = 0; i < vec.size(); i++) {
            if (vec.get(i).trim().length() > 0) {
                if (i > 0 || groupVec.size() > 0) {
                    ret.append(", ");
                }
                ret.append(vec.get(i).trim());
            }
        }
        return ret.toString();
    }

    /**
     * The main output for the first column of the purchase list. This is
     * typically the cost of the object.
     * 
     * @return
     */
    @Override
    public String getColumn1Output() {
        if (getAlias().trim().length() == 0
                || getRealCost() == 0 && !(this instanceof Multipower
                        || this instanceof ElementalControl || this instanceof VariablePowerPool)) {
            if (isEquipment() && getPrice() != 0) {
                BigDecimal bd = new BigDecimal(getTotalPrice());
                bd = bd.setScale(HeroDesigner.getActiveHero().getRules()
                        .getEquipmentCostDecimalPlaces(),
                        BigDecimal.ROUND_HALF_UP);
                String ret = "" + bd.toString();
                if (HeroDesigner.getActiveHero().getRules()
                        .isEquipmentUnitsPrefix()) {
                    ret = HeroDesigner.getActiveHero().getRules()
                            .getEquipmentCostUnits()
                            + ret;
                } else {
                    ret += HeroDesigner.getActiveHero().getRules()
                            .getEquipmentCostUnits();
                }
                return ret;
            } else {
                return "";
            }
        } else {
            return super.getColumn1Output();
        }
    }

    @Override
    public double getActiveCost() {
        double total = getTotalCost();
        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;
            }
        }
        for (int i=0; i<getPrivateMods().size(); i++) {
        	Modifier mod = getPrivateMods().get(i);
            if (!mod.getXMLID().equals("LINKED") && mod.getTotalValue() > 0) {
                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 = getTotalCost();
        double advantageTotal = 0d;
        boolean advantagesApplied = false;
        for (int i = 0; i < assignedModifiers.size(); i++) {
            Modifier mod = assignedModifiers.get(i);
            if (mod.getTotalValue() > 0 && !mod.getXMLID().equals(excludeID)) {
                advantageTotal += mod.getTotalValue();
                advantagesApplied = true;
            }
        }
        for (int i=0; i<getPrivateMods().size(); i++) {
        	Modifier mod = getPrivateMods().get(i);
            if (mod.getTotalValue() > 0 && !mod.getXMLID().equals(excludeID)) {
                advantageTotal += mod.getTotalValue();
                advantagesApplied = true;
            }
        }
        double val = total * (1 + advantageTotal);
        if (advantagesApplied) {
            val = Rounder.roundHalfDown(val);
        }
        return val;
    }

    @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;
            }
        }
        for (int i=0; i<getPrivateMods().size(); i++) {
        	Modifier mod = getPrivateMods().get(i);
            if (mod.getTotalValue() < 0) {
                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);
        }
        if (getQuantity() > 1) {
            double q = (double) getQuantity();
            int doublings = 0;
            while (q > 1d) {
                doublings += 1;
                q = q / 2d;
            }
            ret += doublings * 5;
        }
        return ret;
    }

    /**
     * Returns the total cost of the object, before any Modifiers are applied.
     * 
     * @return
     */
    @Override
    public double getTotalCost() {
        double total = getBaseCost();
        
        ArrayList<Adder> availAds = getAvailableAdders();
        if (getLevelValue() != 0) {
            total += getLevels() / getLevelValue() * getLevelCost();
            if (getLevelCost() < getLevelValue()) {
                if (total > 0 && total < 1) {
                    total = 1;
                } else {
                    total = Rounder.roundHalfDown(total);
                }
            }
        }
        for (Adder ad : getAssignedAdders()) {
            if (ad.isRequired()) {
                total += ad.getRealCost();
            }
            if (!ad.isRequired()
                    && GenericObject.findObjectByID(availAds, ad.getXMLID()) != null) {
                total += ad.getRealCost();
            }
        }
        if (total < getMinimumCost() && isMinSet()) {
            total = getMinimumCost();
        } else if (total > getMaxCost() && isMaxSet()) {
            total = getMaxCost();
        }
        for (int i = 0; i < getAssignedAdders().size()
                && getPrivateAdders().size() == 0; i++) {
            Adder ad = getAssignedAdders().get(i);
            if (!ad.isRequired()
                    && GenericObject.findObjectByID(availAds, ad.getXMLID()) == null) {
                total += ad.getRealCost();
            }
        }
        for (int i=0; i<getPrivateAdders().size(); i++) {
        	Adder ad = getPrivateAdders().get(i);
            total += ad.getRealCost();
        }
        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;
    }
}