package com.hero.ui;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Hashtable;

import com.hero.HeroDesigner;
import com.hero.Rules;
import com.hero.objects.GenericObject;
import com.hero.objects.enhancers.Enhancer;
import com.hero.objects.skills.Skill;
import com.hero.ui.widgets.PopupMessage;

/**
 * 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 SkillList extends GenericObjectList {

	private static final long serialVersionUID = 4020037646620379275L;

	public SkillList() {
		super("Skills", "Cost", "Skill", null, HeroDesigner.getActiveHero()
				.getSkills());
	}

	@Override
	public void addObject(GenericObject o) {
		if (HeroDesigner.getActiveHero().isPrefab()) {
			super.addObject(o);
			return;
		}
		boolean ret = true;
		boolean warned = false;
		Rules rules = HeroDesigner.getActiveHero().getRules();
		if (rules.getSkillMaxResponse() > Rules.IGNORE) {
			// check values...
			double total = 0;
			for (int i = 0; i < HeroDesigner.getActiveHero().getSkills().size(); i++) {
				GenericObject o2 = HeroDesigner.getActiveHero().getSkills()
						.get(i);
				total += o2.getRealCostPreList();
			}
			int avail = rules.getSkillMaxValue();
			if ((total > avail) && (o.getRealCostPreList() > 0)) {
				PopupMessage popup = PopupMessage
						.getInstance(
								HeroDesigner.getAppFrame(),
								this,
								"Total points of purchased Skills exceeds allowed maximum.",
								rules.getSkillMaxResponse() == Rules.WARN);
				popup.setVisible(true);
				warned = true;
				ret = rules.getSkillMaxResponse() == Rules.WARN;
			} else if ((total + o.getRealCostPreList() > avail)
					&& (o.getRealCostPreList() > 0)) {
				PopupMessage popup = PopupMessage
						.getInstance(
								HeroDesigner.getAppFrame(),
								this,
								"This purchase puts the total Skills points used over the allowable limit.",
								rules.getSkillMaxResponse() == Rules.WARN);
				popup.setVisible(true);
				warned = true;
				ret = rules.getSkillMaxResponse() == Rules.WARN;
			}
		}
		if (!warned && (rules.getAvailTotalPointsResponse() > Rules.IGNORE)) {
			double newVal = o.getRealCostPreList();
			if (newVal > 0) {
				double total = HeroDesigner.getActiveHero().getSpentTotal();
				total += newVal;
				double avail = HeroDesigner.getActiveHero().getBasePoints()
						+ HeroDesigner.getActiveHero().getDisadPoints()
						+ HeroDesigner.getActiveHero().getExperience();
				if (HeroDesigner.getActiveTemplate().is6E()) {
					avail -= HeroDesigner.getActiveHero().getDisadPoints();
				}
				if (total > avail) {
					PopupMessage popup = PopupMessage
							.getInstance(
									HeroDesigner.getAppFrame(),
									this,
									"This purchase puts the total points used over the available total for the character.",
									rules.getAvailTotalPointsResponse() == Rules.WARN);
					popup.setVisible(true);
					warned = true;
					ret = rules.getAvailTotalPointsResponse() == Rules.WARN;
				}
			}
		}
		if (!warned && (rules.getAttackAPMaxResponse() > Rules.IGNORE)
				&& o.getTypes().contains("ATTACK")) {
			double active = o.getActiveCost();
			if (active > rules.getAttackAPMaxValue()) {
				PopupMessage popup = PopupMessage
						.getInstance(
								HeroDesigner.getAppFrame(),
								this,
								"This Attack exceeds the maximum Active Points for an Attack set in the campaign rules.",
								rules.getAttackAPMaxResponse() == Rules.WARN);
				popup.setVisible(true);
				warned = true;
				ret = rules.getAttackAPMaxResponse() == Rules.WARN;
			}
		}
		if (!warned && (rules.getDefenseAPMaxResponse() > Rules.IGNORE)
				&& o.getTypes().contains("DEFENSE")) {
			double active = o.getActiveCost();
			if (active > rules.getDefenseAPMaxValue()) {
				PopupMessage popup = PopupMessage
						.getInstance(
								HeroDesigner.getAppFrame(),
								this,
								"This Defense ability exceeds the maximum Active Points for a Defense ability set in the campaign rules.",
								rules.getDefenseAPMaxResponse() == Rules.WARN);
				popup.setVisible(true);
				warned = true;
				ret = rules.getDefenseAPMaxResponse() == Rules.WARN;
			}
		}
		if (ret) {
			super.addObject(o);
			setEnhancerLists();
		}
	}

	@Override
	public boolean checkPaste() {
		if (HeroDesigner.getCopyBuffer() instanceof com.hero.objects.enhancers.Enhancer) {
			for (int i = 0; i < HeroDesigner.getActiveHero().getSkills().size(); i++) {
				GenericObject o = HeroDesigner.getActiveHero().getSkills().get(
						i);
				if (o.getXMLID()
						.equals(HeroDesigner.getCopyBuffer().getXMLID())) { // Enhancer
					// already
					// assigned....
					return false;
				}
			}
			boolean addIt = false;
			for (int i = 0; i < HeroDesigner.getActiveTemplate()
					.getSkillEnhancers().size(); i++) {
				GenericObject mi = HeroDesigner.getActiveTemplate()
						.getSkillEnhancers().get(i);
				if (mi.getXMLID().equals(
						HeroDesigner.getCopyBuffer().getXMLID())) {
					addIt = true;
				}
			}
			return addIt;
		} else if (HeroDesigner.getCopyBuffer() instanceof com.hero.objects.List) {
			com.hero.objects.List list = (com.hero.objects.List) HeroDesigner
					.getCopyBuffer();
			for (int i = 0; i < list.getObjects().size(); i++) {
				if (list.getObjects().get(i) instanceof Skill) {
					continue;
				} else {
					return false;
				}
			}
			return true;
		} else if (HeroDesigner.getCopyBuffer() instanceof Skill) {
			return true;
		} else {
			return false;
		}
	}

	@Override
	protected boolean checkReplace(GenericObject replacement,
			GenericObject replacee) {
		if (HeroDesigner.getActiveHero().isPrefab()) {
			return true;
		}
		boolean ret = true;
		boolean warned = false;
		Rules rules = HeroDesigner.getActiveHero().getRules();
		if (rules.getSkillMaxResponse() > Rules.IGNORE) {
			// check values...
			double total = 0;
			for (int i = 0; i < HeroDesigner.getActiveHero().getSkills().size(); i++) {
				GenericObject o2 = HeroDesigner.getActiveHero().getSkills()
						.get(i);
				total += o2.getRealCostPreList();
			}
			int avail = rules.getSkillMaxValue();
			if ((total > avail)
					&& (replacement.getRealCostPreList() > replacee
							.getRealCostPreList())) {
				PopupMessage popup = PopupMessage
						.getInstance(
								HeroDesigner.getAppFrame(),
								this,
								"This edit puts the total Skills points used over the allowed limit.",
								rules.getSkillMaxResponse() == Rules.WARN);
				popup.setVisible(true);
				warned = true;
				ret = rules.getSkillMaxResponse() == Rules.WARN;
			} else if (total - replacee.getRealCostPreList()
					+ replacement.getRealCostPreList() > avail) {
				PopupMessage popup = PopupMessage
						.getInstance(
								HeroDesigner.getAppFrame(),
								this,
								"This edit puts the total Skills points used over the allowed limit.",
								rules.getSkillMaxResponse() == Rules.WARN);
				popup.setVisible(true);
				warned = true;
				ret = rules.getSkillMaxResponse() == Rules.WARN;
			}
		}
		if (!warned && (rules.getAvailTotalPointsResponse() > Rules.IGNORE)) {
			double oldVal = replacee.getRealCostPreList();
			double newVal = replacement.getRealCostPreList();
			if (newVal > oldVal) {
				double total = HeroDesigner.getActiveHero().getSpentTotal();
				total -= oldVal;
				total += newVal;
				double avail = HeroDesigner.getActiveHero().getBasePoints()
						+ HeroDesigner.getActiveHero().getDisadPoints()
						+ HeroDesigner.getActiveHero().getExperience();
				if (HeroDesigner.getActiveTemplate().is6E()) {
					avail -= HeroDesigner.getActiveHero().getDisadPoints();
				}
				if (total > avail) {
					PopupMessage popup = PopupMessage
							.getInstance(
									HeroDesigner.getAppFrame(),
									this,
									"This edit puts the total points used over the available total for the character.",
									rules.getAvailTotalPointsResponse() == Rules.WARN);
					popup.setVisible(true);
					warned = true;
					ret = rules.getAvailTotalPointsResponse() == Rules.WARN;
				}
			}
		}
		if (!warned && (rules.getAttackAPMaxResponse() > Rules.IGNORE)
				&& replacement.getTypes().contains("ATTACK")) {
			double active = replacement.getActiveCost();
			if ((active > rules.getAttackAPMaxValue())
					&& (active > replacee.getActiveCost())) {
				PopupMessage popup = PopupMessage
						.getInstance(
								HeroDesigner.getAppFrame(),
								this,
								"This Attack exceeds the maximum Active Points for an Attack set in the campaign rules.",
								rules.getAttackAPMaxResponse() == Rules.WARN);
				popup.setVisible(true);
				warned = true;
				ret = rules.getAttackAPMaxResponse() == Rules.WARN;
			}
		}
		if (!warned && (rules.getDefenseAPMaxResponse() > Rules.IGNORE)
				&& replacement.getTypes().contains("DEFENSE")) {
			double active = replacement.getActiveCost();
			if ((active > rules.getDefenseAPMaxValue())
					&& (active > replacee.getActiveCost())) {
				PopupMessage popup = PopupMessage
						.getInstance(
								HeroDesigner.getAppFrame(),
								this,
								"This Defense ability exceeds the maximum Active Points for a Defense ability set in the campaign rules.",
								rules.getDefenseAPMaxResponse() == Rules.WARN);
				popup.setVisible(true);
				warned = true;
				ret = rules.getDefenseAPMaxResponse() == Rules.WARN;
			}
		}
		return ret;
	}

	@Override
	public void setData(ArrayList<GenericObject> data) {
		super.setData(data);
		setEnhancerLists();
	}

	public void setEnhancerLists() {
		// first take care of the "reordering" of the skill list to account for
		// enhancers
		Hashtable enhancerSkills = new Hashtable();
		ArrayList<Enhancer> enhancers = new ArrayList<Enhancer>();
		boolean restructureNeeded = false;
		for (int i = HeroDesigner.getActiveHero().getSkills().size() - 1; i >= 0; i--) {
			GenericObject o = HeroDesigner.getActiveHero().getSkills().get(i);
			o.setPosition(i);
			if (o instanceof Enhancer) {
				enhancers.add((Enhancer) o);
				restructureNeeded = true;
			} else if (o.getEnhancerApplied() != null) {
				Enhancer en = o.getEnhancerApplied();
				if ((o.getParentList() != null)
						&& (o.getParentList().getID() == en.getID())) {
					continue;
				} else if (o.getParentList() != null) {
					o.getParentList().getObjects().remove(o);
					o.setParent(en);
				}
				restructureNeeded = true;
				ArrayList<GenericObject> vec;
				if (enhancerSkills.get(en.getXMLID()) == null) {
					vec = new ArrayList<GenericObject>();
					enhancerSkills.put(en.getXMLID(), vec);
				} else {
					vec = (ArrayList<GenericObject>) enhancerSkills.get(en
							.getXMLID());
				}
				vec.add(o);
			}
		}
		Collections.sort(HeroDesigner.getActiveHero().getSkills(),
				new Comparator() {
					public int compare(Object o1, Object o2) {
						if ((o1 instanceof GenericObject)
								&& (o2 instanceof GenericObject)) {
							GenericObject g1 = (GenericObject) o1;
							GenericObject g2 = (GenericObject) o2;
							if (g1.getEnhancerApplied() != null) {
								if (g2.getEnhancerApplied() != null) {
									if (g1.getEnhancerApplied().equals(
											g2.getEnhancerApplied())) {
										return g1.getTextOutput().compareTo(
												g2.getTextOutput());
									} else {
										return compare(g1.getEnhancerApplied(),
												g2.getEnhancerApplied());
									}
								} else if (g1.getEnhancerApplied().equals(g2)) {
									return 1;
								} else {
									return compare(g1.getEnhancerApplied(), g2);
								}
							} else if (g2.getEnhancerApplied() != null) {
								if (g1.equals(g2.getEnhancerApplied())) {
									return -1;
								} else {
									return compare(g1, g2.getEnhancerApplied());
								}
							}
							return g1.getPosition() - g2.getPosition();
						}
						return o1.toString().compareTo(o2.toString());
					}

					@Override
					public boolean equals(Object o) {
						return false;
					}
				});
		for (int i = 0; (i < enhancers.size()) && restructureNeeded; i++) {
			Enhancer enhancer = enhancers.get(i);
			enhancer.setParent(null);
			int currentPosition = enhancer.getPosition() + 1;
			if (enhancerSkills.get(enhancer.getXMLID()) != null) {
				ArrayList<GenericObject> vec = (ArrayList<GenericObject>) enhancerSkills
						.get(enhancer.getXMLID());
				for (int j = vec.size() - 1; j >= 0; j--) {
					GenericObject o = vec.get(j);
					if (!enhancer.getObjects().contains(o)) {
						enhancer.addObject(o);
					}
					o.setParent(enhancer);
					o.setPosition(currentPosition);
					HeroDesigner.getActiveHero().getSkills().remove(o);
					if (currentPosition < HeroDesigner.getActiveHero()
							.getSkills().size()) {
						HeroDesigner.getActiveHero().getSkills().add(
								currentPosition, o);
					} else {
						HeroDesigner.getActiveHero().getSkills().add(o);
					}
					currentPosition++;
				}
			}
		}
	}
}