package com.hero.objects.characteristics;

import java.math.BigDecimal;

import org.jdom.Element;

import com.hero.HeroDesigner;
import com.hero.objects.Adder;
import com.hero.objects.CharAffectingObject;
import com.hero.objects.GenericObject;
import com.hero.objects.powers.Automaton;
import com.hero.objects.powers.CompoundPower;
import com.hero.util.Constants;
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 Speed extends Characteristic {

    private static String xmlID = "SPD";

    public Speed(Element template) {
        super(template, Speed.xmlID);
        doubleBase = baseLevel;
    }

    @Override
    protected void calcBaseValue() {
        double bonus = 0;
        if (HeroDesigner.getActiveHero() != null) {
            for (int i = 0; i < HeroDesigner.getActiveHero()
                    .getCharacteristics().size(); i++) {
                Characteristic ch = (Characteristic) HeroDesigner
                        .getActiveHero().getCharacteristics().get(i);
                if (!ch.getXMLID().equals(getXMLID())
                        && ch.getIncreaseLevels(getType()) > 0
                        && ch.getIncrease(getType()) != 0) {
                    double mult = ch.getCharacteristicValue()
                            * ch.getIncrease(getType()) / ch
                                    .getIncreaseLevels(getType());
                    doubleBase += mult;
                    bonus += mult;
                }
            }
            for (int i = 0; i < HeroDesigner.getActiveHero().getPowers().size(); i++) {
                if (HeroDesigner.getActiveHero().getPowers().get(i)
                        .getXMLID().equals(getXMLID())) {
                    continue;
                } else if (HeroDesigner.getActiveHero().getPowers().get(i) instanceof CompoundPower) {
                    CompoundPower cp = (CompoundPower) HeroDesigner
                            .getActiveHero().getPowers().get(i);
                    for (int j = 0; j < cp.getPowers().size(); j++) {
                        if (cp.getPowers().get(j).getXMLID().equals(
                                getXMLID())) {
                            continue;
                        } else if (cp.getPowers().get(j) instanceof Characteristic) {
                            CharAffectingObject power = (CharAffectingObject) cp
                                    .getPowers().get(j);
                            if (power.getIncreaseLevels(getType()) > 0
                                    && power.getIncrease(getType()) != 0) {
                                if (power.getAffectPrimary()
                                        && CharAffectingObject.checkFigured(power, getType())
                                        && power.getAffectTotal()) {
                                    double mult = power.getIncreaseValue(
                                            getType(), true);
                                    doubleBase += mult;
                                    bonus += mult;
                                }
                            }
                        }
                    }
                } else if (HeroDesigner.getActiveHero().getPowers().get(i) instanceof Characteristic) {
                    CharAffectingObject power = (CharAffectingObject) HeroDesigner
                            .getActiveHero().getPowers().get(i);
                    if (power.getIncreaseLevels(getType()) > 0
                            && power.getIncrease(getType()) != 0) {
                        if (power.getAffectPrimary()
                                && CharAffectingObject.checkFigured(power, getType())
                                && power.getAffectTotal()) {
                            double mult = power.getIncreaseValue(getType(),
                                    true);
                            doubleBase += mult;
                            bonus += mult;
                        }
                    }
                }
            }
            for (int i = 0; i < HeroDesigner.getActiveHero().getEquipment()
                    .size(); i++) {
                if (HeroDesigner.getActiveHero().getEquipment().get(i)
                        .getXMLID().equals(getXMLID())) {
                    continue;
                } else if (HeroDesigner.getActiveHero().getEquipment().get(i) instanceof CompoundPower) {
                    CompoundPower cp = (CompoundPower) HeroDesigner
                            .getActiveHero().getEquipment().get(i);
                    for (int j = 0; j < cp.getPowers().size(); j++) {
                        if (cp.getPowers().get(j).getXMLID().equals(
                                getXMLID())) {
                            continue;
                        } else if (cp.getPowers().get(j) instanceof Characteristic) {
                            CharAffectingObject power = (CharAffectingObject) cp
                                    .getPowers().get(j);
                            if (power.getIncreaseLevels(getType()) > 0
                                    && power.getIncrease(getType()) != 0) {
                                if (power.getAffectPrimary()
                                        && CharAffectingObject.checkFigured(power, getType())
                                        && power.getAffectTotal()) {
                                    double mult = power.getIncreaseValue(
                                            getType(), true);
                                    doubleBase += mult;
                                    bonus += mult;
                                }
                            }
                        }
                    }
                } else if (HeroDesigner.getActiveHero().getEquipment().get(i) instanceof Characteristic) {
                    CharAffectingObject power = (CharAffectingObject) HeroDesigner
                            .getActiveHero().getEquipment().get(i);
                    if (power.getIncreaseLevels(getType()) > 0
                            && power.getIncrease(getType()) != 0) {
                        if (power.getAffectPrimary()
                                && CharAffectingObject.checkFigured(power, getType())
                                && power.getAffectTotal()) {
                            double mult = power.getIncreaseValue(getType(),
                                    true);
                            doubleBase += mult;
                            bonus += mult;
                        }
                    }
                }
            }
        }
        if (Rounder.roundDown(baseLevel + bonus) <= maxVal) {
            baseValue = baseLevel + bonus;
        } else {
            baseValue = maxVal;
        }

        baseValueCalcTime = System.currentTimeMillis();
    }

    @Override
    protected void calcNCMCharValue() {
        double bonus = getLevels() + origBaseLevel;
        if (HeroDesigner.getActiveHero() != null) {
            for (int i = 0; i < HeroDesigner.getActiveHero()
                    .getCharacteristics().size(); i++) {
                Characteristic ch = (Characteristic) HeroDesigner
                        .getActiveHero().getCharacteristics().get(i);
                if (!ch.getXMLID().equals(getXMLID())
                        && ch.getIncreaseLevels(getType()) > 0
                        && ch.getIncrease(getType()) != 0) {
                    double mult = ch.getNCMCharValue()
                            * ch.getIncrease(getType()) / ch
                                    .getIncreaseLevels(getType());
                    doubleBase += mult;
                    bonus += mult;
                }
            }

            if (bonus < maxVal) {
                ncmCharValue = bonus;
            } else {
                ncmCharValue = maxVal;
            }

            ncmCharValueCalcTime = System.currentTimeMillis();
        }
    }

    @Override
    protected void calcSecondaryValue() {
        double bonus = 0;
        for (int i = 0; i < HeroDesigner.getActiveHero().getPowers().size(); i++) {
            if (HeroDesigner.getActiveHero().getPowers().get(i).getXMLID()
                    .equals(getXMLID())) {
                Characteristic power = (Characteristic) HeroDesigner
                        .getActiveHero().getPowers().get(i);
                if (!power.getAffectPrimary() && power.getAffectTotal()) {
                    bonus += power.getLevels();
                }
            } else if (HeroDesigner.getActiveHero().getPowers().get(i) instanceof CharAffectingObject) {
                CharAffectingObject power = (CharAffectingObject) HeroDesigner
                        .getActiveHero().getPowers().get(i);
                if (power.getIncreaseLevels(getType()) > 0
                        && CharAffectingObject.checkFigured(power, getType())) {
                    double add = power.getIncreaseValue(getType(), false);

                    bonus += Rounder.roundDown(add);
                }
            }
        }
        for (int i = 0; i < HeroDesigner.getActiveHero().getEquipment().size(); i++) {
            if (HeroDesigner.getActiveHero().getEquipment().get(i).getXMLID()
                    .equals(getXMLID())) {
                Characteristic power = (Characteristic) HeroDesigner
                        .getActiveHero().getEquipment().get(i);
                if (!power.getAffectPrimary() && power.getAffectTotal()) {
                    bonus += power.getLevels();
                }
            } else if (HeroDesigner.getActiveHero().getEquipment().get(i) instanceof CharAffectingObject) {
                CharAffectingObject power = (CharAffectingObject) HeroDesigner
                        .getActiveHero().getEquipment().get(i);
                if (power.getIncreaseLevels(getType()) > 0
                        && CharAffectingObject.checkFigured(power, getType())) {
                    double add = power.getIncreaseValue(getType(), false);

                    bonus += Rounder.roundDown(add);
                }
            }
        }
        double ret = getPrimaryValue() + bonus;

        ret = Rounder.roundDown(ret);
        if (ret < maxVal) {
            secondaryValue = ret;
        } else {
            secondaryValue = maxVal;
        }

        secondaryValueCalcTime = System.currentTimeMillis();
    }

    @Override
    public String getCharacteristicBase() {
        BigDecimal bd = new BigDecimal(getBaseValue());
        bd = bd.setScale(1, BigDecimal.ROUND_HALF_UP);
        return bd.toString();
    }

    @Override
    public double getCharacteristicValue() {
        return Rounder.roundDown(getBaseValue() + getLevels());
    }

    @Override
    public String getDisplayNotes() {
        String phases = "";
        String phases2 = "";
        double p = getPrimaryValue();
        if (p > 12) p = 12;
        switch ((int) Rounder.roundDown(p)) {
            case 0:
                phases = "(none)";
                break;
            case 1:
                phases = "7";
                break;
            case 2:
                phases = "6, 12";
                break;
            case 3:
                phases = "4, 8, 12";
                break;
            case 4:
                phases = "3, 6, 9, 12";
                break;
            case 5:
                phases = "3, 5, 8, 10, 12";
                break;
            case 6:
                phases = "2, 4, 6, 8, 10, 12";
                break;
            case 7:
                phases = "2, 4, 6, 7, 9, 11, 12";
                break;
            case 8:
                phases = "2, 3, 5, 6, 8, 9, 11, 12";
                break;
            case 9:
                phases = "2, 3, 4, 6, 7, 8, 10, 11, 12";
                break;
            case 10:
                phases = "2, 3, 4, 5, 6, 8, 9, 10, 11, 12";
                break;
            case 11:
                phases = "2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12";
                break;
            case 12:
                phases = "1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12";
                break;
            default:
                phases = "???";
        }
        p = getSecondaryValue();
        if (p>12) p = 12;
        switch ((int) Rounder.roundDown(p)) {
            case 0:
                phases2 = "(none)";
                break;
            case 1:
                phases2 = "7";
                break;
            case 2:
                phases2 = "6, 12";
                break;
            case 3:
                phases2 = "4, 8, 12";
                break;
            case 4:
                phases2 = "3, 6, 9, 12";
                break;
            case 5:
                phases2 = "3, 5, 8, 10, 12";
                break;
            case 6:
                phases2 = "2, 4, 6, 8, 10, 12";
                break;
            case 7:
                phases2 = "2, 4, 6, 7, 9, 11, 12";
                break;
            case 8:
                phases2 = "2, 3, 5, 6, 8, 9, 11, 12";
                break;
            case 9:
                phases2 = "2, 3, 4, 6, 7, 8, 10, 11, 12";
                break;
            case 10:
                phases2 = "2, 3, 4, 5, 6, 8, 9, 10, 11, 12";
                break;
            case 11:
                phases2 = "2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12";
                break;
            case 12:
                phases2 = "1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12";
                break;
            default:
                phases2 = "???";
        }
        if (!phases.equals(phases2)) {
            phases = phases + "/" + phases2;
        }
        return "Phases:  " + phases;
    }

    @Override
    public String getRoll() {
        return "";
    }

    @Override
    public double getTotalCost() {
        double total = getBaseCost();
        if (!isPower()) {
            double val = getValue(false, getType());
            double base = getBaseValue();
            if (val < base) {
                base = Rounder.roundDown(base);
            }
            double realLevels = val - base;
            if (Math.abs(realLevels) < 1 && realLevels < 0) {
                realLevels = 0;
            }
            double additional = realLevels / levelValue * levelCost;
            total += Rounder.roundHalfDown(additional);
        } else {
            total += getLevels() * getLevelCost() / getLevelValue();
        }
        if (HeroDesigner.getActiveTemplate().is6E() || (HeroDesigner.getActiveHero().isNCMSelected()
                && HeroDesigner.getActiveTemplate().getNcmCostMultiplier() > 0
                && !isPower()
                && (getLevels() > 0 || getTrueBase() > getNCMLevel()))) {
            if (getNCMCharValue() > getNCMLevel() && !isPower()) {
                double val = Rounder.roundDown(getNCMCharValue());
                double base = getNCMCharValue() - getLevels();
                if (val < base) {
                    base = Rounder.roundDown(base);
                }
                double realLevels = val - base;
                if (Math.abs(realLevels) < 1 && realLevels < 0) {
                    realLevels = 0;
                }
                double expensiveLevels = val - getNCMLevel();
                if (expensiveLevels > realLevels
                        && getTrueBase() < getNCMLevel()) {
                    expensiveLevels = realLevels;
                }
                total += expensiveLevels / levelValue * levelCost * (HeroDesigner
                        .getActiveTemplate().getNcmCostMultiplier() - 1);
            }
        }
        for (Adder ad : getAssignedAdders()) {
            if (ad.getRealCost() > 0) {
                total += ad.getRealCost();
            }
        }
        if (total < minimumCost && minSet) {
            total = minimumCost;
        } else if (total > maxCost && maxSet) {
            total = maxCost;
        }
        for (Adder ad : getAssignedAdders()) {
            if (ad.getRealCost() < 0) {
                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;
    }

    @Override
    public int getType() {
        return Constants.SPD;
    }

    @Override
    public double getValue(boolean figured, int figuredType) {
        double val = figured ? getFiguredBaseValue(figuredType)
                : getBaseValue();
        val = Rounder.roundDown(val);
        if (val + getLevels() < minimumLevel) {
            setLevels((int) (minimumLevel - getBaseValue()));
            return minimumLevel;
        }
        if (val + getLevels() <= maxVal) {
            return val + getLevels();
        } else {
            setLevels((int) (maxVal - getBaseValue()));
            return maxVal;
        }
    }

    @Override
    public String getValueDisplay() {
        if (getPrimaryValue() != getSecondaryValue()) {
            return Rounder.roundDown(getPrimaryValue()) + "/"
                    + Rounder.roundDown(getSecondaryValue());
        } else {
            return "" + Rounder.roundHalfUp(getPrimaryValue());
        }
    }

    @Override
    public void setValue(double val) {

        double check = getCharacteristicValue();
        if (val == check) {
            return; // no action needed...
        } else {
            if (val < minimumLevel) {
                setLevels((int) Rounder.roundUp(minimumLevel - val));
            }
            if (val <= maxVal) {
                setLevels((int) Rounder.roundUp(val - getBaseValue()));
            } else {
                setLevels((int) Rounder.roundUp(maxVal - getBaseValue()));
            }
        }
    }
}