package com.hero.objects.modifiers;

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.characteristics.Strength;
import com.hero.objects.martialarts.Maneuver;
import com.hero.objects.powers.Absorption;
import com.hero.objects.powers.Aid;
import com.hero.objects.powers.Dispel;
import com.hero.objects.powers.Drain;
import com.hero.objects.powers.Healing;
import com.hero.objects.powers.Images;
import com.hero.objects.powers.NakedModifier;
import com.hero.objects.powers.Power;
import com.hero.objects.powers.Succor;
import com.hero.objects.powers.Suppress;
import com.hero.objects.powers.Transfer;
import com.hero.objects.powers.Transform;
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 Autofire extends Modifier {
    private static String xmlID = "AUTOFIRE";

    private boolean surcharge;

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

    /**
     * Whether to tack on the +1 additional cost for Autofire when applied to
     * attacks which are not targeted on DCV. Will not be applied if the +1
     * Adder is selected.
     * 
     * @return
     */
    public boolean surchargeIncluded() {
        getTotalValue();
        if (GenericObject.findObjectByID(getAssignedAdders(), "ODDPOWER") != null) {
            return true;
        } else {
            return surcharge;
        }
    }

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

        if (forceAllow()) return ret;
        if (o instanceof Strength) {
            return "";
        }
        if (o instanceof Maneuver) {
            return "";
        }
        if (o instanceof Absorption) {
        	return "";
        }
        if (o.getTarget().equals("SELFONLY") || o.getTarget().equals("N/A")) {
            return getDisplay()
                    + " can only be applied to abilities which require an Attack Roll";
        } else {
            return "";
        }
    }

    @Override
    public String getColumn2Output() {
        String adderString = "";
        String ret = "";
        ret += getAlias();
        int numShots = getSelectedOption().getLevels();
        int multiplier = 1;
        double val = getTotalValue();
        for (Adder ad : getAssignedAdders()) {
            if (ad.getXMLID().equals("DOUBLE")) {
                multiplier = (int) Math.pow(ad.getLevelPower(), ad.getLevels());
                continue;
            }
            if (adderString.length() > 0) {
                adderString += ", ";
            }
            adderString += ad.getAlias() + " (" + 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 += numShots * multiplier + " shots;";
        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 double getTotalValue() {
        double val = getBaseCost();
        for (Adder ad : getAssignedAdders()) {
            val += ad.getDoubleTotal();
        }
        if (getLevelValue() > 0) {
            val += getLevels() / getLevelValue() * getLevelCost();
        }
        // if (getLevelPower()>1) val +=
        // Math.pow(getLevelPower(),getLevels()*getLevelValue());
        double advantageTotal = 0d;
        for (Modifier mod : getAssignedModifiers()) {
            if (mod.getTotalValue() > 0) {
                advantageTotal += mod.getTotalValue();
            }
        }
        double active = val * (1 + advantageTotal);
        double limitationTotal = 0d;
        for (Modifier mod : assignedModifiers) {
            if (mod.getTotalValue() < 0) {
                limitationTotal += Math.abs(mod.getTotalValue());
            }
        }
        val = active / (1 + limitationTotal);
        // the following effectively "rounds" the value to the closest 1/4
        val = val * 4d;
        int mult = 1;
        if (val < 0) {
            mult = -1;
        }
        val = val * mult;
        val = Rounder.roundHalfUp(val);
        val = val * mult;
        val = val / 4d;
        // Apply the +1 surcharge if "non standard" attack...
        surcharge = false;
        if (parent != null) {
            if (parent instanceof Power && !(parent instanceof NakedModifier)
                    && !(parent instanceof Images) && !(parent instanceof Absorption)) {
                Power pow = (Power) parent;
                ArrayList<Modifier> orig = pow.getAssignedModifiers();
                ArrayList<Modifier> combined = pow.getAllAssignedModifiers();
                pow.setAssignedModifiers(combined);
                if (!pow.getTarget().equals("DCV")) {
                    surcharge = true;
                }
                if (pow.getTypes().contains("MENTAL")) {
                    surcharge = true;
                }
                if (GenericObject.findObjectByID(pow.getAssignedModifiers(), "NND") != null) {
                    surcharge = true;
                }
                if (GenericObject.findObjectByID(pow.getAssignedModifiers(), "AVLD") != null) {
                    surcharge = true;
                }
                pow.setAssignedModifiers(orig);
                if (pow instanceof Drain) {
                    surcharge = true;
                }
                if (pow instanceof Transform) {
                    surcharge = true;
                }
                if (pow instanceof Transfer) {
                    surcharge = true;
                }
                if (pow instanceof Aid) {
                    surcharge = true;
                }
                if (pow instanceof Dispel) {
                    surcharge = true;
                }
                if (pow instanceof Healing) {
                    surcharge = true;
                }
                if (pow instanceof Succor) {
                    surcharge = true;
                }
                if (pow instanceof Suppress) {
                    surcharge = true;
                }
            }
            if (GenericObject.findObjectByID(getAssignedAdders(), "ODDPOWER") != null) {
                surcharge = false;
            }
        }
        if (surcharge
                && HeroDesigner.getInstance().getPrefs()
                        .isModifierIntelligenceOn()) {
            val += 1;
        }
        if (val < getMinimumCost() && isMinSet()) {
            return getMinimumCost();
        } else if (val > getMaxCost() && isMaxSet()) {
            return getMaxCost();
        } else {
            return val;
        }
    }
}