package com.hero.ui.dialog;

import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Collections;

import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.SwingConstants;
import javax.swing.WindowConstants;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;

import org.jdom.Element;

import com.hero.HeroDesigner;
import com.hero.objects.ElementalControl;
import com.hero.objects.GenericObject;
import com.hero.objects.List;
import com.hero.objects.Multipower;
import com.hero.objects.VariablePowerPool;
import com.hero.objects.characteristics.Characteristic;
import com.hero.objects.martialarts.Maneuver;
import com.hero.objects.modifiers.Modifier;
import com.hero.objects.powers.CompoundPower;
import com.hero.objects.powers.NakedModifier;
import com.hero.ui.SelectionList;
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 AvailableModifiersDialog extends JDialog {

	private static final long serialVersionUID = 643291338550999573L;

	private static ArrayList<Modifier> recentlySelected;

	/**
	 * Returns the Vector of Modifier objects that comprises the Recently
	 * Selected list.
	 * 
	 * @return
	 */
	public static ArrayList<Modifier> getRecentlySelectedList() {
		if (AvailableModifiersDialog.recentlySelected == null) {
			AvailableModifiersDialog.recentlySelected = new ArrayList<Modifier>();
		}
		return AvailableModifiersDialog.recentlySelected;
	}

	/**
	 * Sets the recently selected list. The Vector supplied should contain only
	 * Modifier objects.
	 * 
	 * @param vec
	 */
	public static void setRecentlySelectedList(ArrayList<Modifier> vec) {
		if (vec != null) {
			AvailableModifiersDialog.recentlySelected = vec;
		} else {
			AvailableModifiersDialog.recentlySelected = new ArrayList<Modifier>();
		}
	}

	GenericObject parent;

	SelectionList advList;

	SelectionList limList;

	SelectionList unAdvList;

	SelectionList unLimList;

	SelectionList recentList;

	JButton selectBtn;

	JButton cancelBtn;

	JButton defineBtn;

	JButton customModifierBtn;

	JButton clearBtn;

	Modifier selection;

	GenericDialog parentDialog;

	JTabbedPane tabPane;

	private boolean privateMods;

	/**
	 * @param caller
	 *            The GenericObject that the Modifiers are to be assigned to
	 *            (used for Modifier Intelligence as well)
	 * @param owner
	 *            The dialog that owns this popup.
	 */
	public AvailableModifiersDialog(GenericObject caller, GenericDialog owner) {
		this(caller, owner, false);
	}

	/**
	 * @param caller
	 *            The GenericObject that the Modifiers are to be assigned to
	 *            (used for Modifier Intelligence as well)
	 * @param owner
	 *            The dialog that owns this popup.
	 * @param isPrivate
	 *            Whether the Modifiers that are assigned are considered
	 *            "private" (for use on Lists only)
	 */
	public AvailableModifiersDialog(GenericObject caller, GenericDialog owner,
			boolean isPrivate) {
		super(owner, "Select Modifiers", true);
		privateMods = isPrivate;
		if (AvailableModifiersDialog.recentlySelected == null) {
			AvailableModifiersDialog.recentlySelected = new ArrayList<Modifier>();
		}
		parent = caller;
		parentDialog = owner;
		setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
		initWidgets();
		initListeners();
		layoutComponent();
		pack();
		if (HeroDesigner.getInstance().getPrefs().isRememberDialogPosition()) {
			if ((HeroDesigner.getInstance().getPrefs().getModX() > 50)
					&& (HeroDesigner.getInstance().getPrefs().getModY() > 50)) {
				setSize(new Dimension(HeroDesigner.getInstance().getPrefs()
						.getModX(), HeroDesigner.getInstance().getPrefs()
						.getModY()));
			} else {
				setSize(400, 500);
			}
			if ((HeroDesigner.getInstance().getPrefs().getModScreenX() > 0)
					&& (HeroDesigner.getInstance().getPrefs().getModScreenY() > 0)) {
				setLocation(HeroDesigner.getInstance().getPrefs()
						.getModScreenX(), HeroDesigner.getInstance().getPrefs()
						.getModScreenY());
			} else {
				setLocationRelativeTo(owner);
			}
		} else {
			setSize(400, 500);
			setLocationRelativeTo(owner);
		}
	}

	private String getDefinition(Modifier mod) {
		if (!HeroDesigner.getInstance().getPrefs().isModifierIntelligenceOn()) {
			return mod.getDefinition();
		}
		if (parent instanceof List) {
			List list = (List) parent;
			if ((list.getObjects().size() == 0)
					|| ((list instanceof VariablePowerPool) && mod.getTypes()
							.contains("VPP"))
					|| ((list instanceof Multipower) && mod.getTypes()
							.contains("MP"))
					|| ((list instanceof ElementalControl) && mod.getTypes()
							.contains("EC")) || mod.getTypes().contains("LIST")) {
				String check = mod.included(parent);
				if (check.trim().length() > 0) {
					return check;
				} else {
					return mod.getDefinition();
				}
			} else if (!mod.isLimitation()
					&& (parent instanceof ElementalControl)) {
				return "Advantages cannot be applied directly to an Elemental Control.   Apply them to each slot individually.";
			} else {
				for (int i = 0; i < list.getObjects().size(); i++) {
					GenericObject o = list.getObjects().get(i);
					if (o instanceof Maneuver) {
						String check = mod.included(parent);
						if (check.trim().length() > 0) {
							return check;
						}
					}
					if (o instanceof CompoundPower) {
						CompoundPower cp = (CompoundPower) o;
						for (int j = 0; j < cp.getPowers().size(); j++) {
							GenericObject o2 = cp.getPowers().get(j);
							String check = mod.included(o2);
							if ((check.trim().length() > 0)
									&& (GenericObject.findObjectByID(o2
											.getAssignedModifiers(), mod
											.getXMLID()) == null)) {
								check = "List contains item which does not allow this Modifier:\n\n"
										+ check;
								return check;
							}
						}
					} else {
						o.setListModCheck(true);
						String check = mod.included(o);
						o.setListModCheck(false);
						if ((check.trim().length() > 0)
								&& (GenericObject
										.findObjectByID(o
												.getAssignedModifiers(), mod
												.getXMLID()) == null)) {
							check = "List contains item which does not allow this Modifier:\n\n"
									+ check;
							return check;
						}
					}
				}
				// if we get here, then all objects in list match...
				return mod.getDefinition();
			}
		} else if (parent instanceof Characteristic) {
			Characteristic ch = (Characteristic) parent;
			if (ch.addModifiersToBase()) {
				ch = (Characteristic) ch.clone();
				for (int i = 0; i < HeroDesigner.getActiveHero()
						.getCharacteristics().size(); i++) {
					Characteristic c = (Characteristic) HeroDesigner
							.getActiveHero().getCharacteristics().get(i);
					if (c.getXMLID().equals(ch.getXMLID())) {
						ch.setLevels(ch.getLevels()
								+ (int) c.getCharacteristicValue());
						break;
					}
				}
			}
			String check = mod.included(parent);
			if (check.trim().length() == 0) {
				return mod.getDefinition();
			} else {
				return check;
			}
		} else {
			String check = mod.included(parent);
			if ((check.trim().length() == 0)
					|| ((parent instanceof NakedModifier) && !privateMods)) {
				return mod.getDefinition();
			} else {
				if (parent.getParentList() != null) {
					if (GenericObject.findObjectByID(parent.getParentList()
							.getAssignedModifiers(), mod.getXMLID()) != null) {
						return mod.getDefinition();
					} else {
						return check;
					}
				} else {
					return check;
				}
			}
		}
	}

	private boolean included(Modifier mod) {
		// if
		// (!HeroDesigner.getInstance().getPrefs().isModifierIntelligenceOn())
		// return true;
		if (parent instanceof List) {
			List list = (List) parent;
			if ((list.getObjects().size() == 0)
					|| ((list instanceof VariablePowerPool) && mod.getTypes()
							.contains("VPP"))
					|| ((list instanceof Multipower) && mod.getTypes()
							.contains("MP"))
					|| ((list instanceof ElementalControl) && mod.getTypes()
							.contains("EC")) || mod.getTypes().contains("LIST")) {
				String check = mod.included(parent);
				return check.trim().length() == 0;
			} else if (!mod.isLimitation()
					&& (parent instanceof ElementalControl)) {
				return false;
			} else {
				for (int i = 0; i < list.getObjects().size(); i++) {
					GenericObject o = list.getObjects().get(i);
					if (o instanceof Maneuver) {
						String check = mod.included(parent);
						if (check.trim().length() > 0) {
							return false;
						}
					}
					if (o instanceof CompoundPower) {
						CompoundPower cp = (CompoundPower) o;
						for (int j = 0; j < cp.getPowers().size(); j++) {
							GenericObject o2 = cp.getPowers().get(j);
							String check = mod.included(o2);
							if ((check.trim().length() > 0)
									&& (GenericObject.findObjectByID(o2
											.getAssignedModifiers(), mod
											.getXMLID()) == null)) {
								return false;
							}
						}
					} else {
						o.setListModCheck(true);
						String check = mod.included(o);
						o.setListModCheck(false);
						if ((check.trim().length() > 0)
								&& (GenericObject
										.findObjectByID(o
												.getAssignedModifiers(), mod
												.getXMLID()) == null)) {
							return false;
						}
					}
				}
				// if we get here, then all objects in list match...
				return true;
			}
		} else if (parent instanceof Characteristic) {
			Characteristic ch = (Characteristic) parent;
			if (ch.addModifiersToBase()) {
				ch = (Characteristic) ch.clone();
				for (int i = 0; i < HeroDesigner.getActiveHero()
						.getCharacteristics().size(); i++) {
					Characteristic c = (Characteristic) HeroDesigner
							.getActiveHero().getCharacteristics().get(i);
					if (c.getXMLID().equals(ch.getXMLID())) {
						ch.setLevels(ch.getLevels()
								+ (int) c.getCharacteristicValue());
						break;
					}
				}
			}
			String check = mod.included(ch);
			return check.trim().length() == 0;
		} else {
			String check = mod.included(parent);
			if ((check.trim().length() > 0)
					&& !(parent instanceof NakedModifier)) {
				return false;
			}
			if ((parent instanceof NakedModifier) && !privateMods) {
				return !mod.isLimitation();
			}
			return check.trim().length() == 0;
		}
	}

	private void initListeners() {
		clearBtn.addActionListener(new ActionListener() {

			public void actionPerformed(ActionEvent e) {
				AvailableModifiersDialog.recentlySelected.clear();
				recalcMods();
			}
		});
		tabPane.addChangeListener(new ChangeListener() {

			public void stateChanged(ChangeEvent e) {
				switch (tabPane.getSelectedIndex()) {
				case 0:
					setButtonStates(advList.getSelection());
					defineBtn.setText("Define");
					selectBtn.setText("Select");
					break;
				case 1:
					setButtonStates(limList.getSelection());
					defineBtn.setText("Define");
					selectBtn.setText("Select");
					break;
				case 2:
					setButtonStates(limList.getSelection());
					defineBtn.setText("Define");
					selectBtn.setText("Select");
					break;
				case 3:
					setButtonStates(unAdvList.getSelection());
					defineBtn.setText("View Reason");
					selectBtn.setText("Force Add");
					break;
				case 4:
					setButtonStates(unLimList.getSelection());
					defineBtn.setText("View Reason");
					selectBtn.setText("Force Add");
					break;
				}
			}
		});
		customModifierBtn.addActionListener(new ActionListener() {

			public void actionPerformed(ActionEvent e) {
				Modifier mod = Modifier.getInstance(new Element("MODIFIER"));
				mod.setDisplay("Custom Modifier");
				mod.setAlias("Custom Modifier");
				mod.setBaseCost(0);
				mod.setMinimumCost(-10);
				/*if (parent instanceof Maneuver) {
					mod.setMinimumCost(0);
				}
				removed per phone conversation with Steve Long -- 04/28/2010
				*/
				mod.setMaxCost(10);
				mod.setFixedValue(false);
				mod.setPrivate(privateMods);
				mod.resetID();
				ModifierDialog dialog = mod.getDialog(parent, true);
				dialog.setLocationRelativeTo(AvailableModifiersDialog.this);
				dialog.setVisible(true);
				if (!dialog.okButtonClicked) {
					return;
				}
				if (privateMods && (parent instanceof NakedModifier)) {
					mod.setPrivate(true);
					parent.getAssignedModifiers().add(mod);
				} else if (!privateMods || !(parent instanceof List)) {
					mod.setPrivate(false);
					parent.getAssignedModifiers().add(mod);
				} else {
					List list = (List) parent;
					mod.setPrivate(true);
					list.getPrivateMods().add(mod);
				}
				parentDialog.recalc();
				try {
					mod.setAvailableCheck(true);
					boolean addIt = true;
					LOOP: for (int i = 0; i < AvailableModifiersDialog.recentlySelected
							.size(); i++) {
						Modifier comp = AvailableModifiersDialog.recentlySelected
								.get(i);
						comp.setParent(mod.getProgenitor());
						comp.setFullDisplay(true);
						mod.setFullDisplay(true);
						if (comp.getXMLID().equals(mod.getXMLID())
								&& comp.toString().equals(mod.toString())) {
							addIt = false;
							break LOOP;
						}
					}
					mod.setFullDisplay(false);
					if (addIt) {
						if (AvailableModifiersDialog.recentlySelected.size() > 39) {
							AvailableModifiersDialog.recentlySelected.remove(0);
						}
						mod.setAvailableCheck(false);
						Modifier mod2 = mod.clone();
						mod2.setFullDisplay(true);
						AvailableModifiersDialog.recentlySelected.add(mod2);
					}
					mod.setAvailableCheck(false);
				} catch (Exception exp) {
				}
				customModifierBtn.setVisible(parent.allowsOtherModifiers());
			}
		});
		cancelBtn.addActionListener(new ActionListener() {

			public void actionPerformed(ActionEvent e) {
				setVisible(false);
			}
		});
		defineBtn.addActionListener(new ActionListener() {

			public void actionPerformed(ActionEvent e) {
				Modifier mod = null;
				switch (tabPane.getSelectedIndex()) {
				case 0:
					mod = (Modifier) advList.getSelection();
					break;
				case 1:
					mod = (Modifier) limList.getSelection();
					break;
				case 2:
					mod = (Modifier) limList.getSelection();
					break;
				case 3:
					mod = (Modifier) unAdvList.getSelection();
					break;
				case 4:
					mod = (Modifier) unLimList.getSelection();
					break;
				}
				if (mod == null) {
					return;
				}
				String display = getDefinition(mod);
				if ((display == null) || (display.trim().length() == 0)) {
					return;
				}
				PopupMessage popup = PopupMessage.getInstance(HeroDesigner
						.getAppFrame(), defineBtn, display, false);
				popup.setVisible(true);
			}
		});
		recentList.addTreeSelectionListener(new TreeSelectionListener() {

			public void valueChanged(TreeSelectionEvent e) {
				if ((recentList.getSelection() != null)
						&& (recentList.getSelection() instanceof Modifier)) {
					Modifier mod = (Modifier) recentList.getSelection();
					boolean force = mod.forceAllow();
					mod.setForceAllow(false);
					boolean allowed = included(mod);
					String check = getDefinition(mod);
					mod.setForceAllow(force);
					selectBtn.setEnabled(true);
					selectBtn.setText((allowed || !HeroDesigner.getInstance().getPrefs().isModifierIntelligenceOn())?
							"Select":"Force Add");
					defineBtn.setText(allowed ? "Define" : "View Reason");
					defineBtn.setEnabled(check.trim().length() > 0);
				} else {
					selectBtn.setEnabled(false);
					defineBtn.setEnabled(false);
				}
			}
		});
		advList.addTreeSelectionListener(new TreeSelectionListener() {

			public void valueChanged(TreeSelectionEvent e) {
				if ((advList.getSelection() != null)
						&& (advList.getSelection() instanceof Modifier)) {
					Modifier mod = (Modifier) advList.getSelection();
					boolean force = mod.forceAllow();
					mod.setForceAllow(false);
					boolean allowed = included(mod);
					String check = getDefinition(mod);
					mod.setForceAllow(force);
					selectBtn.setEnabled(true);
					selectBtn.setText((allowed || !HeroDesigner.getInstance().getPrefs().isModifierIntelligenceOn())?
							"Select":"Force Add");
					defineBtn.setText(allowed ? "Define" : "View Reason");
					defineBtn.setEnabled(check.trim().length() > 0);
				} else {
					selectBtn.setEnabled(false);
					defineBtn.setEnabled(false);
				}
			}
		});
		limList.addTreeSelectionListener(new TreeSelectionListener() {

			public void valueChanged(TreeSelectionEvent e) {
				if ((limList.getSelection() != null)
						&& (limList.getSelection() instanceof Modifier)) {
					Modifier mod = (Modifier) limList.getSelection();
					boolean force = mod.forceAllow();
					mod.setForceAllow(false);
					boolean allowed = included(mod);
					String check = getDefinition(mod);
					mod.setForceAllow(force);
					selectBtn.setEnabled(true);
					selectBtn.setText((allowed || !HeroDesigner.getInstance().getPrefs().isModifierIntelligenceOn())?
							"Select":"Force Add");
					defineBtn.setText(allowed ? "Define" : "View Reason");
					defineBtn.setEnabled(check.trim().length() > 0);
				} else {
					selectBtn.setEnabled(false);
					defineBtn.setEnabled(false);
				}
			}
		});
		unAdvList.addTreeSelectionListener(new TreeSelectionListener() {

			public void valueChanged(TreeSelectionEvent e) {
				if ((unAdvList.getSelection() != null)
						&& (unAdvList.getSelection() instanceof Modifier)) {
					Modifier mod = (Modifier) unAdvList.getSelection();
					boolean force = mod.forceAllow();
					mod.setForceAllow(false);
					boolean allowed = included(mod);
					String check = getDefinition(mod);
					mod.setForceAllow(force);
					selectBtn.setEnabled(true);
					selectBtn.setText((allowed || !HeroDesigner.getInstance().getPrefs().isModifierIntelligenceOn())?
							"Select":"Force Add");
					defineBtn.setText(allowed ? "Define" : "View Reason");
					defineBtn.setEnabled(check.trim().length() > 0);
				} else {
					selectBtn.setEnabled(false);
					defineBtn.setEnabled(false);
				}
			}
		});
		unLimList.addTreeSelectionListener(new TreeSelectionListener() {

			public void valueChanged(TreeSelectionEvent e) {
				if ((unLimList.getSelection() != null)
						&& (unLimList.getSelection() instanceof Modifier)) {
					Modifier mod = (Modifier) unLimList.getSelection();
					boolean force = mod.forceAllow();
					mod.setForceAllow(false);
					boolean allowed = included(mod);
					String check = getDefinition(mod);
					mod.setForceAllow(force);
					selectBtn.setEnabled(true);
					selectBtn.setText((allowed || !HeroDesigner.getInstance().getPrefs().isModifierIntelligenceOn())?
							"Select":"Force Add");
					defineBtn.setText(allowed ? "Define" : "View Reason");
					defineBtn.setEnabled(check.trim().length() > 0);
				} else {
					selectBtn.setEnabled(false);
					defineBtn.setEnabled(false);
				}
			}
		});
		recentList.addMouseListener(new MouseAdapter() {

			@Override
			public void mouseClicked(MouseEvent e) {
				if (e.getButton() != MouseEvent.BUTTON1) {
					int row = recentList.rowAtPoint(e.getPoint());
					if (row >= 0) {
						recentList.setSelectedRow(row);
					}
					Modifier mod = (Modifier) recentList.getSelection();
					if (mod == null) {
						return;
					}
					
					mod = mod.clone();
					if (!included(mod)
							&& HeroDesigner.getInstance().getPrefs()
									.isModifierIntelligenceOn()) {
						mod.setForceAllow(true);
					}
					mod.setParent(parent);
					if (privateMods && (parent instanceof NakedModifier)) {
						mod.setPrivate(true);
						parent.getAssignedModifiers().add(mod);
					} else if (!privateMods || !(parent instanceof List)) {
						mod.setPrivate(false);
						parent.getAssignedModifiers().add(mod);
					} else {
						List list = (List) parent;
						mod.setPrivate(true);
						list.getPrivateMods().add(mod);
					}
					mod.setAvailableCheck(true);
					boolean addIt = true;
					LOOP: for (int i = AvailableModifiersDialog.recentlySelected
							.size() - 1; i >= 0; i--) {
						Modifier comp = AvailableModifiersDialog.recentlySelected
								.get(i);
						comp.setParent(mod.getProgenitor());
						comp.setFullDisplay(true);
						mod.setFullDisplay(true);
						if (comp.getXMLID().equals(mod.getXMLID())
								&& comp.toString().equals(mod.toString())) {
							AvailableModifiersDialog.recentlySelected.remove(i);
							AvailableModifiersDialog.recentlySelected.add(0,
									mod.clone());
							addIt = false;
							break LOOP;
						}
					}
					mod.setFullDisplay(false);
					if (addIt) {
						if (AvailableModifiersDialog.recentlySelected.size() > 39) {
							AvailableModifiersDialog.recentlySelected.remove(0);
						}
						mod.setAvailableCheck(false);
						Modifier mod2 = mod.clone();
						mod2.setFullDisplay(true);
						AvailableModifiersDialog.recentlySelected.add(mod2);
					}
					mod.setAvailableCheck(false);
					selection = mod;
					parentDialog.recalc();
					customModifierBtn.setVisible(parent.allowsOtherModifiers());
					recalcMods();
				}
				if (e.getClickCount() == 2) {
					Modifier mod = (Modifier) recentList.getSelection();
					if (mod == null) {
						return;
					}
					selectBtn.doClick();
				}
			}
		});
		advList.addMouseListener(new MouseAdapter() {

			@Override
			public void mouseClicked(MouseEvent e) {
				if (e.getButton() != MouseEvent.BUTTON1) {
					int row = advList.rowAtPoint(e.getPoint());
					if (row >= 0) {
						advList.setSelectedRow(row);
					}
					Modifier mod = (Modifier) advList.getSelection();
					if (mod != null) {
						mod = mod.clone();
						if (!included(mod)
								&& HeroDesigner.getInstance().getPrefs()
										.isModifierIntelligenceOn()) {
							mod.setForceAllow(true);
						}
						mod.setParent(parent);
						if (privateMods && (parent instanceof NakedModifier)) {
							mod.setPrivate(true);
							parent.getAssignedModifiers().add(mod);
						} else if (!privateMods || !(parent instanceof List)) {
							mod.setPrivate(false);
							parent.getAssignedModifiers().add(mod);
						} else {
							List list = (List) parent;
							mod.setPrivate(true);
							list.getPrivateMods().add(mod);
						}
						mod.setAvailableCheck(true);
						boolean addIt = true;
						LOOP: for (int i = AvailableModifiersDialog.recentlySelected
								.size() - 1; i >= 0; i--) {
							Modifier comp = AvailableModifiersDialog.recentlySelected
									.get(i);
							comp.setParent(mod.getProgenitor());
							comp.setFullDisplay(true);
							mod.setFullDisplay(true);
							if (comp.getXMLID().equals(mod.getXMLID())
									&& comp.toString().equals(mod.toString())) {
								AvailableModifiersDialog.recentlySelected.remove(i);
								AvailableModifiersDialog.recentlySelected.add(0,
										mod.clone());
								addIt = false;
								break LOOP;
							}
						}
						mod.setFullDisplay(false);
						if (addIt) {
							if (AvailableModifiersDialog.recentlySelected.size() > 39) {
								AvailableModifiersDialog.recentlySelected.remove(0);
							}
							mod.setAvailableCheck(false);
							Modifier mod2 = mod.clone();
							mod2.setFullDisplay(true);
							AvailableModifiersDialog.recentlySelected.add(mod2);
						}
						mod.setAvailableCheck(false);
						selection = mod;
						parentDialog.recalc();
						customModifierBtn.setVisible(parent.allowsOtherModifiers());
						recalcMods();
					}
				}
				else if (e.getClickCount() == 2) {
					Modifier mod = (Modifier) advList.getSelection();
					if (mod == null) {
						return;
					}
					selectBtn.doClick();
				}
			}
		});
		limList.addMouseListener(new MouseAdapter() {

			@Override
			public void mouseClicked(MouseEvent e) {
				if (e.getButton() != MouseEvent.BUTTON1) {
					int row = limList.rowAtPoint(e.getPoint());
					if (row >= 0) {
						limList.setSelectedRow(row);
					}
					Modifier mod = (Modifier) limList.getSelection();
					if (mod != null) {
						mod = mod.clone();
						if (!included(mod)
								&& HeroDesigner.getInstance().getPrefs()
										.isModifierIntelligenceOn()) {
							mod.setForceAllow(true);
						}
						mod.setParent(parent);
						if (privateMods && (parent instanceof NakedModifier)) {
							mod.setPrivate(true);
							parent.getAssignedModifiers().add(mod);
						} else if (!privateMods || !(parent instanceof List)) {
							mod.setPrivate(false);
							parent.getAssignedModifiers().add(mod);
						} else {
							List list = (List) parent;
							mod.setPrivate(true);
							list.getPrivateMods().add(mod);
						}
						mod.setAvailableCheck(true);
						boolean addIt = true;
						LOOP: for (int i = AvailableModifiersDialog.recentlySelected
								.size() - 1; i >= 0; i--) {
							Modifier comp = AvailableModifiersDialog.recentlySelected
									.get(i);
							comp.setParent(mod.getProgenitor());
							comp.setFullDisplay(true);
							mod.setFullDisplay(true);
							if (comp.getXMLID().equals(mod.getXMLID())
									&& comp.toString().equals(mod.toString())) {
								AvailableModifiersDialog.recentlySelected.remove(i);
								AvailableModifiersDialog.recentlySelected.add(0,
										mod.clone());
								addIt = false;
								break LOOP;
							}
						}
						mod.setFullDisplay(false);
						if (addIt) {
							if (AvailableModifiersDialog.recentlySelected.size() > 39) {
								AvailableModifiersDialog.recentlySelected.remove(0);
							}
							mod.setAvailableCheck(false);
							Modifier mod2 = mod.clone();
							mod2.setFullDisplay(true);
							AvailableModifiersDialog.recentlySelected.add(mod2);
						}
						mod.setAvailableCheck(false);
						selection = mod;
						parentDialog.recalc();
						customModifierBtn.setVisible(parent.allowsOtherModifiers());
						recalcMods();
					}
				}
				else if (e.getClickCount() == 2) {
					Modifier mod = (Modifier) limList.getSelection();
					if (mod == null) {
						return;
					}
					selectBtn.doClick();
				}
			}
		});
		unAdvList.addMouseListener(new MouseAdapter() {

			@Override
			public void mouseClicked(MouseEvent e) {
				if (e.getButton() != MouseEvent.BUTTON1) {
					int row = unAdvList.rowAtPoint(e.getPoint());
					if (row >= 0) {
						unAdvList.setSelectedRow(row);
					}
					Modifier mod = (Modifier) unAdvList.getSelection();
					if (mod != null) {
						mod = mod.clone();
						if (!included(mod)
								&& HeroDesigner.getInstance().getPrefs()
										.isModifierIntelligenceOn()) {
							mod.setForceAllow(true);
						}
						mod.setParent(parent);
						if (privateMods && (parent instanceof NakedModifier)) {
							mod.setPrivate(true);
							parent.getAssignedModifiers().add(mod);
						} else if (!privateMods || !(parent instanceof List)) {
							mod.setPrivate(false);
							parent.getAssignedModifiers().add(mod);
						} else {
							List list = (List) parent;
							mod.setPrivate(true);
							list.getPrivateMods().add(mod);
						}
						mod.setAvailableCheck(true);
						boolean addIt = true;
						LOOP: for (int i = AvailableModifiersDialog.recentlySelected
								.size() - 1; i >= 0; i--) {
							Modifier comp = AvailableModifiersDialog.recentlySelected
									.get(i);
							comp.setParent(mod.getProgenitor());
							comp.setFullDisplay(true);
							mod.setFullDisplay(true);
							if (comp.getXMLID().equals(mod.getXMLID())
									&& comp.toString().equals(mod.toString())) {
								AvailableModifiersDialog.recentlySelected.remove(i);
								AvailableModifiersDialog.recentlySelected.add(0,
										mod.clone());
								addIt = false;
								break LOOP;
							}
						}
						mod.setFullDisplay(false);
						if (addIt) {
							if (AvailableModifiersDialog.recentlySelected.size() > 39) {
								AvailableModifiersDialog.recentlySelected.remove(0);
							}
							mod.setAvailableCheck(false);
							Modifier mod2 = mod.clone();
							mod2.setFullDisplay(true);
							AvailableModifiersDialog.recentlySelected.add(mod2);
						}
						mod.setAvailableCheck(false);
						selection = mod;
						parentDialog.recalc();
						customModifierBtn.setVisible(parent.allowsOtherModifiers());
						recalcMods();
					}
				} else if (e.getClickCount() == 2) {
					Modifier mod = (Modifier) unAdvList.getSelection();
					if (mod == null) {
						return;
					}
					selectBtn.doClick();
				}
			}
		});
		unLimList.addMouseListener(new MouseAdapter() {

			@Override
			public void mouseClicked(MouseEvent e) {
				if (e.getButton() != MouseEvent.BUTTON1) {
					int row = unLimList.rowAtPoint(e.getPoint());
					if (row >= 0) {
						unLimList.setSelectedRow(row);
					}
					Modifier mod = (Modifier) unLimList.getSelection();
					if (mod != null) {
						mod = mod.clone();
						if (!included(mod)
								&& HeroDesigner.getInstance().getPrefs()
										.isModifierIntelligenceOn()) {
							mod.setForceAllow(true);
						}
						mod.setParent(parent);
						if (privateMods && (parent instanceof NakedModifier)) {
							mod.setPrivate(true);
							parent.getAssignedModifiers().add(mod);
						} else if (!privateMods || !(parent instanceof List)) {
							mod.setPrivate(false);
							parent.getAssignedModifiers().add(mod);
						} else {
							List list = (List) parent;
							mod.setPrivate(true);
							list.getPrivateMods().add(mod);
						}
						mod.setAvailableCheck(true);
						boolean addIt = true;
						LOOP: for (int i = AvailableModifiersDialog.recentlySelected
								.size() - 1; i >= 0; i--) {
							Modifier comp = AvailableModifiersDialog.recentlySelected
									.get(i);
							comp.setParent(mod.getProgenitor());
							comp.setFullDisplay(true);
							mod.setFullDisplay(true);
							if (comp.getXMLID().equals(mod.getXMLID())
									&& comp.toString().equals(mod.toString())) {
								AvailableModifiersDialog.recentlySelected.remove(i);
								AvailableModifiersDialog.recentlySelected.add(0,
										mod.clone());
								addIt = false;
								break LOOP;
							}
						}
						mod.setFullDisplay(false);
						if (addIt) {
							if (AvailableModifiersDialog.recentlySelected.size() > 39) {
								AvailableModifiersDialog.recentlySelected.remove(0);
							}
							mod.setAvailableCheck(false);
							Modifier mod2 = mod.clone();
							mod2.setFullDisplay(true);
							AvailableModifiersDialog.recentlySelected.add(mod2);
						}
						mod.setAvailableCheck(false);
						selection = mod;
						parentDialog.recalc();
						customModifierBtn.setVisible(parent.allowsOtherModifiers());
						recalcMods();
					}
				} else if (e.getClickCount() == 2) {
					Modifier mod = (Modifier) unLimList.getSelection();
					if (mod == null) {
						return;
					}
					selectBtn.doClick();
				}
			}
		});
		selectBtn.addActionListener(new ActionListener() {

			public void actionPerformed(ActionEvent e) {
				Modifier mod = null;
				switch (tabPane.getSelectedIndex()) {
				case 0:
					mod = (Modifier) advList.getSelection();
					break;
				case 1:
					mod = (Modifier) limList.getSelection();
					break;
				case 2:
					mod = (Modifier) recentList.getSelection();
					break;
				case 3:
					mod = (Modifier) unAdvList.getSelection();
					break;
				case 4:
					mod = (Modifier) unLimList.getSelection();
					break;
				}
				if (mod != null) {
					
					mod = mod.clone();
					if (!included(mod)
							&& HeroDesigner.getInstance().getPrefs()
									.isModifierIntelligenceOn()) {
						mod.setForceAllow(true);
					}
					mod.setParent(parent);
					ModifierDialog dialog = mod.getDialog(parent, tabPane
							.getSelectedIndex() != 2);
					dialog.setLocationRelativeTo(AvailableModifiersDialog.this);
					dialog.setVisible(true);
					if (!dialog.okButtonClicked) {
						return;
					}
					if (privateMods && (parent instanceof NakedModifier)) {
						mod.setPrivate(true);
						parent.getAssignedModifiers().add(mod);
					} else if (!privateMods || !(parent instanceof List)) {
						mod.setPrivate(false);
						parent.getAssignedModifiers().add(mod);
					} else {
						List list = (List) parent;
						mod.setPrivate(true);
						list.getPrivateMods().add(mod);
					}
					mod.setAvailableCheck(true);
					boolean addIt = true;
					LOOP: for (int i = AvailableModifiersDialog.recentlySelected
							.size() - 1; i >= 0; i--) {
						Modifier comp = AvailableModifiersDialog.recentlySelected
								.get(i);
						comp.setParent(mod.getProgenitor());
						comp.setFullDisplay(true);
						mod.setFullDisplay(true);
						if (comp.getXMLID().equals(mod.getXMLID())
								&& comp.toString().equals(mod.toString())) {
							AvailableModifiersDialog.recentlySelected.remove(i);
							AvailableModifiersDialog.recentlySelected.add(0,
									mod.clone());
							addIt = false;
							break LOOP;
						}
					}
					mod.setFullDisplay(false);
					if (addIt) {
						if (AvailableModifiersDialog.recentlySelected.size() > 39) {
							AvailableModifiersDialog.recentlySelected.remove(0);
						}
						mod.setAvailableCheck(false);
						Modifier mod2 = mod.clone();
						mod2.setFullDisplay(true);
						AvailableModifiersDialog.recentlySelected.add(mod2);
					}
					mod.setAvailableCheck(false);
					selection = mod;
					parentDialog.recalc();
					customModifierBtn.setVisible(parent.allowsOtherModifiers());
					recalcMods();
				}
			}
		});
	}

	private void initWidgets() {
		tabPane = new JTabbedPane();
		advList = new SelectionList(new ArrayList<Modifier>());
		limList = new SelectionList(new ArrayList<Modifier>());
		unAdvList = new SelectionList(new ArrayList<Modifier>());
		unLimList = new SelectionList(new ArrayList<Modifier>());
		recentList = new SelectionList(new ArrayList<Modifier>());
		clearBtn = new JButton("Clear List");
		JPanel recentPanel = new JPanel(new GridBagLayout());
		recentPanel.add(recentList.getTree(), new GridBagConstraints(0, 0, 1,
				1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH,
				new Insets(0, 0, 0, 0), 0, 0));
		recentPanel.add(clearBtn, new GridBagConstraints(0, 1, 1, 1, 1, 0,
				GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(
						2, 0, 0, 0), 0, 0));
		tabPane.addTab("Advantages", advList.getTree());
		tabPane.addTab("Limitations", limList.getTree());
		tabPane.addTab("Recently Selected", recentPanel);
		tabPane.addTab(HeroDesigner.getInstance().getPrefs()
				.isModifierIntelligenceOn() ? "Unavailable Advantages"
				: "Non-Recommended Avantages", unAdvList.getTree());
		tabPane.addTab(HeroDesigner.getInstance().getPrefs()
				.isModifierIntelligenceOn() ? "Unavailable Limitations"
				: "Non-Recommended Limitations", unLimList.getTree());
		tabPane.setTabPlacement(SwingConstants.LEFT);
		selectBtn = new JButton("Select");
		selectBtn.setEnabled(false);
		cancelBtn = new JButton("Done");
		defineBtn = new JButton("Define");
		customModifierBtn = new JButton("Custom Modifier");
		customModifierBtn.setVisible(parent.allowsOtherModifiers());
		defineBtn.setEnabled(false);
		recalcMods();
	}

	private void layoutComponent() {
		JPanel panel = new JPanel(new GridBagLayout());
		GridBagConstraints gbc = new GridBagConstraints();
		gbc.gridx = 0;
		gbc.gridy = 0;
		gbc.weightx = 1;
		gbc.weighty = 1;
		gbc.anchor = GridBagConstraints.CENTER;
		gbc.fill = GridBagConstraints.BOTH;
		gbc.gridwidth = 1;
		gbc.insets = new Insets(0, 0, 5, 0);
		panel.add(tabPane, gbc);
		gbc.fill = GridBagConstraints.HORIZONTAL;
		gbc.weightx = 0;
		gbc.gridwidth = 1;
		gbc.gridy++;
		gbc.weighty = 0;
		JPanel buttons = new JPanel(new FlowLayout(FlowLayout.CENTER));
		buttons.add(selectBtn);
		buttons.add(customModifierBtn);
		buttons.add(defineBtn);
		buttons.add(cancelBtn);
		buttons.setOpaque(false);
		panel.add(buttons, gbc);
		panel.setOpaque(true);
		setContentPane(panel);
	}

	private void recalcMods() {
		ArrayList<Modifier> recent = new ArrayList<Modifier>();
		ArrayList<Modifier> adv = new ArrayList<Modifier>();
		ArrayList<Modifier> lim = new ArrayList<Modifier>();
		ArrayList<Modifier> unAdv = new ArrayList<Modifier>();
		ArrayList<Modifier> unLim = new ArrayList<Modifier>();
		List parentList = parent.getParentList();
		OUTER: for (int i = AvailableModifiersDialog.recentlySelected.size() - 1; i >= 0; i--) {
			Modifier mod = AvailableModifiersDialog.recentlySelected.get(i);
			mod.setAvailableCheck(true);
			if (!mod.getXMLID().equals("MODIFIER")
					&& (GenericObject.findObjectByID(parent
							.getAssignedModifiers(), mod.getXMLID()) != null)
					&& mod.isExclusive()) {
				mod.setAvailableCheck(false);
				continue OUTER;
			}
			mod.setAvailableCheck(false);
			if (included(mod)
					|| !HeroDesigner.getInstance().getPrefs()
							.isModifierIntelligenceOn()) {
				mod.setParent(parent);
				for (int j = 0; j < parent.getAssignedModifiers().size(); j++) {
					Modifier check = parent.getAssignedModifiers().get(j);
					if (check.getColumn2Output().equals(mod.getColumn2Output())) {
						continue OUTER;
					}
				}
				recent.add(mod);
			} else {
				if ((parentList != null)
						&& (GenericObject.findObjectByID(parentList
								.getAssignedModifiers(), mod.getXMLID()) != null)) {
					mod.setParent(parent);
					for (int j = 0; j < parent.getAssignedModifiers().size(); j++) {
						Modifier check = parent.getAssignedModifiers().get(j);
						if (check.getColumn2Output().equals(
								mod.getColumn2Output())) {
							continue OUTER;
						}
					}
					recent.add(mod);
				}
			}
		}
		Collections.sort(recent);
		for (int i = 0; i < parent.getAvailableModifiers().size(); i++) {
			Modifier mod = parent.getAvailableModifiers().get(i);
			mod.setAvailableCheck(true);
			if ((GenericObject.findObjectByID(parent.getAssignedModifiers(),
					mod.getXMLID()) != null)
					&& mod.isExclusive()) {
				mod.setAvailableCheck(false);
				continue;
			}
			mod.setAvailableCheck(false);
			if (included(mod)) {
				if (mod.isLimitation()) {
					lim.add(mod);
				} else {
					adv.add(mod);
				}
			} else {
				if ((parentList != null)
						&& (GenericObject.findObjectByID(parentList
								.getAssignedModifiers(), mod.getXMLID()) != null)) {
					if (mod.isLimitation()) {
						lim.add(mod);
					} else {
						adv.add(mod);
					}
				} else {
					if (mod.isLimitation()) {
						unLim.add(mod);
					} else {
						unAdv.add(mod);
					}
				}
			}
		}
		for (int i = 0; i < HeroDesigner.getActiveTemplate().getModifiers()
				.size(); i++) {
			Modifier mod = (Modifier) HeroDesigner.getActiveTemplate()
					.getModifiers().get(i);
			mod.setAvailableCheck(true);
			if (((GenericObject.findObjectByID(parent.getAssignedModifiers(),
					mod.getXMLID()) != null) && mod.isExclusive())
					|| (GenericObject.findObjectByID(parent
							.getAvailableModifiers(), mod.getXMLID()) != null)) {
				mod.setAvailableCheck(false);
				continue;
			}
			mod.setAvailableCheck(false);
			if (included(mod)) {
				if (mod.isLimitation()) {
					lim.add(mod);
				} else {
					adv.add(mod);
				}
			} else {
				if ((parentList != null)
						&& (GenericObject.findObjectByID(parentList
								.getAssignedModifiers(), mod.getXMLID()) != null)) {
					if (mod.isLimitation()) {
						lim.add(mod);
					} else {
						adv.add(mod);
					}
				} else {
					if (mod.isLimitation()) {
						unLim.add(mod);
					} else {
						unAdv.add(mod);
					}
				}
			}
		}
		Collections.sort(lim);
		Collections.sort(adv);
		Collections.sort(unLim);
		Collections.sort(unAdv);
		recentList.setAvailableList(recent);
		advList.setAvailableList(adv);
		limList.setAvailableList(lim);
		unAdvList.setAvailableList(unAdv);
		unLimList.setAvailableList(unLim);
	}

	private void setButtonStates(GenericObject o) {
		if ((o == null) || !(o instanceof Modifier)) {
			selectBtn.setEnabled(false);
			defineBtn.setEnabled(false);
		} else {
			String check = getDefinition((Modifier) o);
			// selectBtn.setEnabled(included((Modifier) o) || !HeroDesigner.getInstance().getPrefs().isModifierIntelligenceOn());
			defineBtn.setEnabled(check.trim().length() > 0);
		}
	}

	/**
	 * Sets the visibility of this dialog.
	 */
	@Override
	public void setVisible(boolean val) {
		if (!val) {
			HeroDesigner.getInstance().getPrefs().setModX(getSize().width);
			HeroDesigner.getInstance().getPrefs().setModY(getSize().height);
			HeroDesigner.getInstance().getPrefs().setModScreenX(
					(int) getLocation().getX());
			HeroDesigner.getInstance().getPrefs().setModScreenY(
					(int) getLocation().getY());
		}
		super.setVisible(val);
	}
}