package com.hero.objects;

import java.util.ArrayList;

import javax.swing.JPanel;

import org.jdom.Element;

import com.hero.HeroDesigner;
import com.hero.Rules;
import com.hero.objects.modifiers.Linked;
import com.hero.objects.modifiers.Modifier;
import com.hero.objects.powers.CompoundPower;
import com.hero.ui.dialog.ElementalControlDialog;
import com.hero.ui.dialog.GenericDialog;
import com.hero.ui.widgets.PopupMessage;
import com.hero.util.Rounder;
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 ElementalControl extends List {

    private String error;

    public ElementalControl(Element root, String xmlID) {
        super(root, xmlID);
        minimumCost = 1;
        maxCost = 9999;
        minSet = true;
        maxSet = true;
    }

    public ElementalControl(Element root) {
        super(root);
        minimumCost = 1;
        maxCost = 9999;
        minSet = true;
        maxSet = true;
    }

    public ElementalControl(String name) {
        super(name);
        minimumCost = 1;
        baseCost = 5;
        maxCost = 9999;
        minSet = true;
        maxSet = true;
    }

    @Override
    public void init(Element root) {
        super.init(root);
        abbreviation = "EC";
    }

    @Override
    public double getRealCostForChild(GenericObject child) {
    	if (HeroDesigner.getActiveTemplate().is6E()) {
    		return super.getRealCostForChild(child);
    	}
        ArrayList<Adder> realAdders = child.getAssignedAdders();
        ArrayList<Modifier> realModifiers = child.getAssignedModifiers();

        ArrayList<Adder> calcAdders = (ArrayList<Adder>) realAdders.clone();
        calcAdders.addAll(getAssignedAdders());
        ArrayList<Modifier> calcModifiers = (ArrayList<Modifier>) realModifiers
                .clone();
        ArrayList<Modifier> ecMods = new ArrayList<Modifier>();
        for (int i=0; i<getAssignedModifiers().size(); i++) {
        	Modifier mod = getAssignedModifiers().get(i);
            if (mod.getTotalValue() < 0
                    && (GenericObject.findObjectByID(calcModifiers, mod.getXMLID()) == null
                            || mod.getXMLID().equals("GENERIC_OBJECT")
                            || mod.getXMLID().equals("CUSTOM_MODIFIER") || mod
                            .getXMLID().equals("MODIFIER"))) {
                ecMods.add(mod);
            }
        }
        calcModifiers.addAll(ecMods);

        child.setAssignedAdders(calcAdders);

        double active = child.getActiveCost();

        child.setAssignedAdders(realAdders);

        active = Math.max(getActiveCost(), active - getActiveCost());
        if (active == 0) {
            return 0;
        }
        double limitationTotal = 0d;
        for (Modifier mod : calcModifiers) {
            if (mod.getTotalValue() < 0) {
                limitationTotal += mod.getTotalValue();
            }
        }
        double ret = active / (1d + Math.abs(limitationTotal));
        if (limitationTotal != 0) {
            ret = Rounder.roundHalfDown(ret);
        }
        if (ret < 1) {
            ret = 1;
        }

        if (HeroDesigner.getActiveHero() != null
                && HeroDesigner.getActiveHero().getRules().multiplierAllowed()
                && child.getMultiplier() != 1) {
            ret = ret * child.getMultiplier();
            ret = Rounder.roundHalfDown(ret);
        } else if (HeroDesigner.getActiveHero() != null
                && HeroDesigner.getActiveHero().getRules().multiplierAllowed()
                && getMultiplier() != 1) {
            ret = ret * getMultiplier();
            ret = Rounder.roundHalfDown(ret);
        }

        return ret;
    }

    @Override
    public String getColumn2Output() {
    	if (HeroDesigner.getActiveTemplate().is6E()) return super.getColumn2Output();
        String ret = "";
        if (getName().trim().length() > 0) {
            ret += "<i>" + getName() + ":</i>  ";
        }
        ret += getAlias() + ", " + (int) getActiveCost() * 2 + "-point powers";
        String a = getAdderString();
        if (a.trim().length() > 0) {
            ret += ", " + a;
        }
        String m = getModifierString();
        ret += m;
        return ret;
    }

    @Override
    public boolean objectAllowed(GenericObject o, boolean displayPopup) {
    	if (HeroDesigner.getActiveTemplate().is6E()) return super.objectAllowed(o, displayPopup);
        boolean ret = true;
        if (o instanceof CompoundPower) {
            CompoundPower cp = (CompoundPower) o;
            for (int i=0; i<cp.getPowers().size(); i++) {
            	GenericObject obj = cp.getPowers().get(i);
                boolean check = objectAllowed(obj, displayPopup);
                if (!check) {
                    return check;
                }
            }
            if (cp.getPowers().size() > 0) {
                return true;
            }
        }
        com.hero.objects.List old = o.getParentList();
        o.setParent(this);
        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 VariablePowerPool) {
            error = "You cannot add a VPP into an Elemental Control.  The Variable Power Pool will be placed outside of the Elemental Control.";
            ret = false;
        } else if (o instanceof List) {
            error = "You cannot add a List into an Elemental Control.  New list will be placed outside of the Elemental Control.";
            ret = false;
        } else if (getAssignedModifiers().size() > 0
                && HeroDesigner.getInstance().getPrefs()
                        .isModifierIntelligenceOn()) {
            List oldParent = o.getParentList();
            o.setParent(null);

            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);
            INNER: 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) {
                    error = mod.getAlias()
                            + " cannot be applied to "
                            + o.getAlias()
                            + ".\n\nReason:  "
                            + check
                            + "\n\n"
                            + o.getAlias()
                            + " will be placed outside of the Elemental Control.";
                    ret = false;
                    break INNER;
                }
                slotMods.add(mod);
            }
            o.setAssignedModifiers(orig);
            o.setParent(oldParent);
        }

        if (!ret) {
            o.setParent(old);
            return ret;
        }

        if (GenericObject.findObjectByID(o.getAssignedModifiers(), "LINKED") != null
                && HeroDesigner.getActiveHero().getRules()
                        .getLinkAcrossFramework() > Rules.IGNORE) {
            Linked link = (Linked) GenericObject.findObjectByID(o.getAssignedModifiers(),
                    "LINKED");
            GenericObject linkObj = link.getValue();
            if (linkObj != null
                    && linkObj.getParentList() != null
                    && (o.getMainPower() == null
                            || linkObj.getMainPower() == null || !o
                            .getMainPower().equals(linkObj.getMainPower()))) {
                if (linkObj.getParentList() instanceof Multipower
                        || linkObj.getParentList() instanceof ElementalControl
                        || linkObj.getParentList() instanceof VariablePowerPool) {
                    if (HeroDesigner.getActiveHero().getRules()
                            .getLinkAcrossFramework() == Rules.DONOTALLOW) {
                        error = "You cannot Link two different slots of a Power Framework";
                        ret = false;
                    } else {
                        String msg = "Warning!  You should not Link two different slots of a Power Framework.  Use a Compound Power instead.";
                        if (displayPopup) {
                            PopupMessage popup = PopupMessage.getInstance(
                                    HeroDesigner.getAppFrame(),
                                    (JPanel) HeroDesigner.getAppFrame()
                                            .getContentPane(), msg, true);
                            popup.setVisible(true);
                            displayPopup = false;
                        }
                    }
                }
            }
        }
        if (!ret) {
            o.setParent(old);
            return ret;
        }
        if (o.getTypes().contains("SPECIAL")) {
            String msg = "Warning!  "
                    + o.getDisplay()
                    + " should not be placed in an Elemental Control (or any other Power Framework).";
            if (displayPopup
                    && HeroDesigner.getActiveHero().getRules()
                            .getSpecialTypeInFramework() == Rules.WARN) {
                PopupMessage popup = PopupMessage.getInstance(HeroDesigner
                        .getAppFrame(), (JPanel) HeroDesigner.getAppFrame()
                        .getContentPane(), msg, true);
                popup.setVisible(true);
            } else if (HeroDesigner.getActiveHero().getRules()
                    .getSpecialTypeInFramework() == Rules.DONOTALLOW) {
                error = msg;
                o.setParent(old);
                return false;
            }
            ret = true;
        } else if (o.getOrigAPPerEnd() == 0 && o.getEndUsage() == 0) {
            String msg = "Warning!  Elemental Controls should not contain abilities that do not cost END (barring GM permission).";
            if (displayPopup
                    && HeroDesigner.getActiveHero().getRules()
                            .getNonENDUsingAbilityInEC() == Rules.WARN) {
                PopupMessage popup = PopupMessage.getInstance(HeroDesigner
                        .getAppFrame(), (JPanel) HeroDesigner.getAppFrame()
                        .getContentPane(), msg, true);
                popup.setVisible(true);
            } else if (HeroDesigner.getActiveHero().getRules()
                    .getNonENDUsingAbilityInEC() == Rules.DONOTALLOW) {
                error = msg;
                o.setParent(old);
                return false;
            }
            ret = true;
        } else if (o instanceof CompoundPower) {
            CompoundPower cp = (CompoundPower) o;
            LOOP: for (int i=0; i<cp.getPowers().size(); i++) {
            	GenericObject ob = cp.getPowers().get(i);
                if (ob.getTypes().contains("SPECIAL")
                        && HeroDesigner.getActiveHero().getRules()
                                .getSpecialTypeInFramework() > Rules.IGNORE) {
                    String msg = "Warning!  "
                            + ob.getDisplay()
                            + " should not be placed in an Elemental Control (or any other Power Framework).";
                    if (displayPopup
                            && HeroDesigner.getActiveHero().getRules()
                                    .getSpecialTypeInFramework() == Rules.WARN) {
                        PopupMessage popup = PopupMessage.getInstance(
                                HeroDesigner.getAppFrame(),
                                (JPanel) HeroDesigner.getAppFrame()
                                        .getContentPane(), msg, true);
                        popup.setVisible(true);
                    } else if (HeroDesigner.getActiveHero().getRules()
                            .getSpecialTypeInFramework() == Rules.DONOTALLOW) {
                        error = msg;
                        o.setParent(old);
                        return false;
                    }
                    ret = true;
                    break LOOP;
                } else if (ob.getAPPerEnd() == 0
                        && ob.getEndUsage() == 0
                        && HeroDesigner.getActiveHero().getRules()
                                .getNonENDUsingAbilityInEC() > Rules.IGNORE) {
                    String msg = "Warning!  Elemental Controls should not contain abilities that do not cost END (barring GM permission).";
                    if (displayPopup
                            && HeroDesigner.getActiveHero().getRules()
                                    .getNonENDUsingAbilityInEC() == Rules.WARN) {
                        PopupMessage popup = PopupMessage.getInstance(
                                HeroDesigner.getAppFrame(),
                                (JPanel) HeroDesigner.getAppFrame()
                                        .getContentPane(), msg, true);
                        popup.setVisible(true);
                    } else if (HeroDesigner.getActiveHero().getRules()
                            .getNonENDUsingAbilityInEC() == Rules.DONOTALLOW) {
                        error = msg;
                        o.setParent(old);
                        return false;
                    }
                    ret = true;
                    break LOOP;
                }
            }
        } else if (o.getActiveCost() < getActiveCost() * 2 && o.getMainPower() == null
                || o.getMainPower() != null && o.getMainPower()
                        .getActiveCost() < getActiveCost() * 2) {
            String msg = "The Active Cost on the Power is less than the minimum for the EC.  The cost of the slot will be increased to match the EC minimum.";
            if (displayPopup) {
                PopupMessage popup = PopupMessage.getInstance(HeroDesigner
                        .getAppFrame(), (JPanel) HeroDesigner.getAppFrame()
                        .getContentPane(), msg, true);
                popup.setVisible(true);
            }
            ret = true;
        }
        o.setParent(old);
        return ret;
    }

    @Override
    public String getRejectionMessage() {
        if (error == null) {
            return "You cannot add a List into an Elemental Control.  New list will be placed outside of the Elemental Control.";
        } else {
            return error;
        }
    }

    @Override
    public Element getSaveXML() {
        Element root = getGeneralSaveXML();
        root.setName("ELEMENTAL_CONTROL");
        root.setAttribute("QUANTITY", getQuantity()+"");
        return root;
    }

    @Override
    public void restoreFromSave(Element root) {
        super.restoreFromSave(root);
        String check = XMLUtility.getValue(root, "QUANTITY");
        if (check != null && check.trim().length()>0) {
            try {
                quantity = Integer.parseInt(check);
            } catch(Exception exp) {
                quantity = 1;
            }
        } else {
            quantity = 1;
        }
    }
    @Override
    public GenericDialog getDialog(boolean isNew, boolean isPower) {
        return new ElementalControlDialog(this, isNew);
    }
}