package com.hero.objects.enhancers;

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.List;
import com.hero.objects.powers.Automaton;
import com.hero.objects.skills.Language;
import com.hero.objects.skills.Skill;
import com.hero.ui.dialog.EnhancerDialog;
import com.hero.ui.dialog.GenericDialog;
import com.hero.util.Constants;
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 Enhancer extends List {

    protected int costSavings;
    protected int intBasedCost = 3;
    protected int generalCost = 2;
    protected boolean intBased = false;

    public Enhancer(Element template) {
        super(template);
    }

    public int getCostSavings() {
		if (HeroDesigner.getActiveHero().getRules().useSkillMultipliers() && !(this.getXMLID().equalsIgnoreCase("WELL_CONNECTED"))) {
			return 0;
		}
        return costSavings;
    }
    
    public void setIntBased(boolean val) {
    	intBased = val;
    }
    
    public boolean getIntBased() {
    	return intBased;
    }

    /**
     * Determines whether the enhancer applies to the given ability type.
     * 
     * @param type
     * @return
     */
    public boolean appliesToType(String type) {
        return types.contains(type);
    }

    @Override
    protected void init(Element element) {
        display = "Generic Enhancer";
        alias = "Generic Enhancer";
        baseCost = 3;
        levelCost = 0;
        levelValue = 0;
        minimumCost = 3;
        minimumLevel = 0;
        super.init(element);
        String check = XMLUtility.getValue(element, "COSTSAVINGS");
        if (check != null && check.trim().length() > 0) {
            try {
                costSavings = Integer.parseInt(check);
            } catch (Exception exp) {
                costSavings = 1;
            }
        } else {
            costSavings = 1;
        }
    }

    @Override
    public Element getSaveXML() {
        Element root = getGeneralSaveXML();
        root.setName(getXMLID());
        root.setAttribute("INTBASED", (intBased?"YES":"NO"));
        return root;
    }

    @Override
    public void restoreFromSave(Element root) {
        super.restoreFromSave(root);
        alias = display;
        String check = XMLUtility.getValue(root, "INTBASED");
        if (check != null && check.trim().toUpperCase().startsWith("Y")) {
        	intBased = true;
        } else {
        	intBased = false;
        }
    }

    @Override
    public String getColumn1Output() {
        return "" + Rounder.roundHalfDown(getRealCost());
    }

    @Override
    public String getColumn1Suffix(GenericObject child) {
        return "";
    }

    @Override
    public String getColumn2Prefix(GenericObject child) {
        updateChildPositions();
        int childPosition = getObjects().indexOf(child);
        childPosition++;
        return child.getPosition() - getPosition() + ")  ";
    }

    @Override
    public boolean objectAllowed(GenericObject o, boolean displayPopup) {
        return false;
    }

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


	@Override
	public double getRealCostForChild(GenericObject pChild) {
		if (HeroDesigner.getActiveHero().getRules().useSkillMultipliers() && !(this.getXMLID().equalsIgnoreCase("WELL_CONNECTED"))) {
			if (pChild instanceof Language) {
				if (getIntBased()) {
					if (pChild.getSelectedOption().getXMLID().equals("BASIC")) {
						return pChild.getRealCostPreList() -1;
					} else {
						return pChild.getRealCostPreList() - 2;
					}
				} else {
					return pChild.getRealCostPreList() -1;
				}
			}
			else if (pChild instanceof Skill) {
				//ensure that the skill is always based on the right roll type for the multiplier
				Skill s = (Skill) pChild;
				if (getIntBased()) {
					s.setCharacteristic(Constants.INT);
				} else {
					s.setCharacteristic(Constants.GENERAL);
				}
			}
			double pre = pChild.getRealCostPreList();
			double ret = pre - pChild.getBaseCost();
			return ret;
		}
		return super.getRealCostForChild(pChild);
	}

	@Override
	public double getBaseCost() {
		if (HeroDesigner.getActiveHero().getRules().useSkillMultipliers() && !(this.getXMLID().equalsIgnoreCase("WELL_CONNECTED"))) {
			return getLevels()*getLevelCost();
		}
		else {
			return super.getBaseCost();
		}
	}

	@Override
	public double getLevelCost() {
		if (HeroDesigner.getActiveHero().getRules().useSkillMultipliers() && !(this.getXMLID().equalsIgnoreCase("WELL_CONNECTED"))) {
			if (getIntBased()) {
				return 3;
			} else {
				return 2;
			}
		}
		return super.getLevelCost();
	}

	@Override
	public int getLevels() {
		if (HeroDesigner.getActiveHero().getRules().useSkillMultipliers() && !(this.getXMLID().equalsIgnoreCase("WELL_CONNECTED"))) {
			
			int slots = getObjects().size();
			int multiples = 1;
			double check = Math.pow(2,multiples-1);
			while (check < slots) {
				check = Math.pow(2, multiples);
				multiples++;
			}
			return multiples;
		}
		return super.getLevels();
	}

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

	@Override
	public double getTotalCost() {
		double total = getBaseCost();
        
        ArrayList<Adder> availAds = getAvailableAdders();
        
        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 (Adder ad : getPrivateAdders()) {
            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;
	}

}