package com.hero.ui.widgets;

import java.awt.Color;
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.ItemEvent;
import java.awt.event.ItemListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;

import com.hero.HeroDesigner;
import com.hero.objects.Adder;
import com.hero.objects.GenericObject;
import com.hero.objects.List;
import com.hero.objects.modifiers.Modifier;
import com.hero.ui.dialog.GenericDialog;
import com.hero.ui.dialog.ModifierDialog;

/**
 * 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 ModifierPanel extends JPanel {
	private static final long serialVersionUID = -2429582580726557971L;

	Modifier modifier;

	GenericObject parent;

	GenericDialog main;

	JCheckBox checkbox;

	FractionTF fractionTF;

	LevelTF levelTF;

	JLabel valueLbl;

	JTextField aliasTF;

	ArrayList<ActionListener> listeners;

	ActionListener checkboxListener;

	JButton editBtn;

	JButton helpBtn;

	JComboBox combo;

	ModifierPanel childPanel;

	boolean selectionLocked = false;

	public ModifierPanel(GenericObject object, Modifier mod,
			GenericDialog dialog) {
		super(new GridBagLayout());
		setOpaque(true);
		listeners = new ArrayList<ActionListener>();
		setBackground(Color.white);
		modifier = mod;
		parent = object;
		main = dialog;
		aliasTF = new JTextField(modifier.getAlias());
		aliasTF.setOpaque(false);
		aliasTF.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
		aliasTF.getDocument().addDocumentListener(new DocumentListener() {
			public void changedUpdate(DocumentEvent e) {
				modifier.setAlias(aliasTF.getText());
			}

			public void insertUpdate(DocumentEvent e) {
				modifier.setAlias(aliasTF.getText());
			}

			public void removeUpdate(DocumentEvent e) {
				modifier.setAlias(aliasTF.getText());
			}
		});
		checkbox = new JCheckBox();
		checkbox.setOpaque(false);
		if (!modifier.isPrivate() || !(parent instanceof List)) {
			checkbox.setSelected(parent.getAssignedModifiers().contains(
					modifier));
		} else {
			checkbox.setSelected(((List) main.getObject()).getPrivateMods()
					.contains(modifier));
		}
		aliasTF.setFont(checkbox.getFont());
		checkboxListener = new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				if (checkbox.isSelected()) {

					// uncheck any "excluded" modifiers
					for (int i = 0; i < modifier.getExcludes().size(); i++) {
						String id = modifier.getExcludes().get(i).trim()
								.toUpperCase();
						Modifier mod = null;
						ArrayList<Modifier> vec = (ArrayList<Modifier>) main
								.getObject().getAssignedModifiers().clone();
						if (main.getObject() instanceof List) {
							vec.addAll(((List) main.getObject())
									.getPrivateMods());
						}
						INNER: for (int j = 0; j < vec.size(); j++) {
							Modifier check = vec.get(j);
							if (check.getXMLID().equals(id)) {
								mod = check;
								break INNER;
							}
						}
						if (mod != null) {
							for (int j = 0; j < main.getModifierPanels().size(); j++) {
								ModifierPanel p = main.getModifierPanels().get(
										j);
								if (p.getModifier().getXMLID().trim()
										.toUpperCase().equals(id)) {
									p.setSelected(false);
								}
							}
						}
					}

					addToParent();
					if (!modifier.isExclusive() && (childPanel == null)) {
						GridBagConstraints gbc = new GridBagConstraints();
						gbc.gridx = 0;
						gbc.gridy = 1;
						gbc.gridwidth = GridBagConstraints.REMAINDER;
						gbc.fill = GridBagConstraints.HORIZONTAL;
						gbc.anchor = GridBagConstraints.WEST;
						Modifier ad = modifier.clone();
						ad.resetID();
						childPanel = new ModifierPanel(parent, ad, main);
						childPanel.setSelected(false);
						add(childPanel, gbc);
					} else {
						if (childPanel != null) {
							childPanel.setVisible(true);
						}
					}
				} else {
					removeFromParent();
					if ((childPanel != null) && !childPanel.isSelected()) {
						childPanel.setVisible(false);
					}
				}
				if (!parent.verifyModifiers()) {
					main.resetMods();
				}
				revalidate();
				dispatch();
			}
		};
		checkbox.addActionListener(checkboxListener);
		combo = new JComboBox(modifier.getOptions().toArray());
		combo.setBackground(Color.white);
		if (modifier.getSelectedOption() != null) {
			combo.setSelectedItem(modifier.getSelectedOption());
		}
		combo.addItemListener(new ItemListener() {
			public void itemStateChanged(ItemEvent e) {
				if ((combo.getSelectedItem() == null)
						|| !(combo.getSelectedItem() instanceof Adder)) {
					return;
				}
				Adder opt = (Adder) combo.getSelectedItem();
				modifier.setSelectedOption(opt);
				updateValues();
				dispatch();
			}
		});
		if ((modifier.getSelectedOption() == null)
				&& (combo.getItemCount() > 0)) {
			modifier.setSelectedOption((Adder) combo.getItemAt(0));
		}
		combo.setEditable(true);
		if (modifier.getSelectedOption() != null) {
			((JTextField) combo.getEditor().getEditorComponent())
					.setText(modifier.getSelectedOption().getAlias());
		}
		((JTextField) combo.getEditor().getEditorComponent()).getDocument()
				.addDocumentListener(new DocumentListener() {
					public void changedUpdate(DocumentEvent e) {
						if (modifier.getSelectedOption() != null) {
							modifier.getSelectedOption().setAlias(
									((JTextField) combo.getEditor()
											.getEditorComponent()).getText());
						}
					}

					public void insertUpdate(DocumentEvent e) {
						if (modifier.getSelectedOption() != null) {
							modifier.getSelectedOption().setAlias(
									((JTextField) combo.getEditor()
											.getEditorComponent()).getText());
						}
					}

					public void removeUpdate(DocumentEvent e) {
						if (modifier.getSelectedOption() != null) {
							modifier.getSelectedOption().setAlias(
									((JTextField) combo.getEditor()
											.getEditorComponent()).getText());
						}
					}
				});
		levelTF = new LevelTF(modifier.getLevels(), 999, modifier
				.getMinimumLevel());
		levelTF.addPropertyChangeListener("Level",
				new PropertyChangeListener() {
					public void propertyChange(PropertyChangeEvent e) {
						modifier.setLevels(levelTF.getCurrent());
						updateValues();
						dispatch();
					}
				});
		helpBtn = new JButton(" ? ");
		helpBtn.setOpaque(false);
		helpBtn.setMargin(new Insets(0, 0, 0, 0));
		helpBtn.setBorderPainted(false);
		helpBtn.setFocusPainted(false);
		helpBtn.setContentAreaFilled(false);
		helpBtn.setForeground(Color.blue);
		if ((modifier.getDefinition() != null)
				&& (modifier.getDefinition().trim().length() > 0)) {
			helpBtn.setVisible(true);
		} else {
			helpBtn.setVisible(false);
		}
		helpBtn.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				if (modifier == null) {
					return;
				}
				if (modifier.getDefinition() == null) {
					return;
				}
				if (modifier.getDefinition().trim().length() == 0) {
					return;
				}
				PopupMessage popup = PopupMessage.getInstance(HeroDesigner
						.getAppFrame(), helpBtn, modifier.getDefinition(),
						false);
				popup.setVisible(true);
			}
		});
		valueLbl = new JLabel("("
				+ modifier.getFraction(modifier.getTotalValue()) + ")");
		valueLbl.setPreferredSize(new JLabel("(+9 1/2)").getPreferredSize());
		valueLbl.setHorizontalTextPosition(SwingConstants.RIGHT);
		valueLbl.setHorizontalAlignment(SwingConstants.RIGHT);
		if (!modifier.isFixedValue()) {
			fractionTF = new FractionTF(modifier.getTotalValue(), modifier
					.getMaxCost(), modifier.getMinimumCost(), modifier
					.useMultiplier());
			fractionTF.addPropertyChangeListener(new PropertyChangeListener() {
				public void propertyChange(PropertyChangeEvent e) {
					modifier.setBaseCost(fractionTF.getCurrent());
					main.updateValues();
				}
			});
		}
		editBtn = new JButton("Edit");
		editBtn.setOpaque(false);
		editBtn.setMargin(new Insets(0, 0, 0, 0));
		editBtn.setBorderPainted(false);
		editBtn.setFocusPainted(false);
		editBtn.setContentAreaFilled(false);
		editBtn.setForeground(Color.blue);
		editBtn.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				if (!modifier.noDisplayDialog()) {
					Modifier mod = modifier.clone();
					mod.setID(modifier.getID());
					ModifierDialog dialog = mod.getDialog(parent, false);
					dialog.setLocationRelativeTo(editBtn);
					dialog.setVisible(true);
					if (!dialog.okButtonClicked) {
						return;
					} else {
						ArrayList<Modifier> mods = parent
								.getAssignedModifiers();
						int index = mods.indexOf(modifier);
						if (index >= 0) {
							mods.set(index, mod);
						} else if (parent instanceof List) {
							List l = (List) parent;
							mods = l.getPrivateMods();
							index = mods.indexOf(modifier);
							if (index >= 0) {
								mods.set(index, mod);
							}
						}
						modifier = mod;
						main.updateValues();
					}
				}
			}
		});

		GridBagConstraints gbc = new GridBagConstraints();
		gbc.gridx = 0;
		gbc.gridy = 0;
		gbc.weightx = 0;
		gbc.weighty = 1;
		gbc.gridwidth = 1;
		gbc.gridheight = 1;
		gbc.fill = GridBagConstraints.NONE;
		gbc.anchor = GridBagConstraints.NORTHWEST;
		gbc.insets = new Insets(0, 5, 0, 3);
		add(checkbox, gbc);
		gbc.gridx++;
		gbc.insets = new Insets(0, 0, 0, 3);
		gbc.fill = GridBagConstraints.HORIZONTAL;
		gbc.weightx = 1;
		add(aliasTF, gbc);
		gbc.gridx++;
		gbc.weightx = 0;
		gbc.fill = GridBagConstraints.NONE;
		gbc.anchor = GridBagConstraints.EAST;
		if (!modifier.noDisplayDialog()) {
			add(editBtn, gbc);
		}
		gbc.gridx++;
		gbc.insets = new Insets(0, 5, 0, 10);
		if (modifier.getOptions().size() > 0) {
			add(combo, gbc);
			gbc.gridx++;
		}
		add(helpBtn, gbc);
		gbc.gridx++;
		if ((modifier.getLevelValue() != 0) && (modifier.getLevelCost() != 0)
				&& modifier.noDisplayDialog()) {
			add(levelTF, gbc);
			gbc.gridx++;
		}
		if (modifier.isFixedValue()) {
			add(valueLbl, gbc);
		} else {
			add(fractionTF, gbc);
		}
		addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				main.updateValues();
			}
		});
	}

	public void addActionListener(ActionListener listener) {
		listeners.add(listener);
	}

	private void addToParent() {
		if (!modifier.isPrivate() || !(parent instanceof List)) {
			if (!parent.getAssignedModifiers().contains(modifier)
					|| !modifier.isExclusive()) {
				parent.getAssignedModifiers().add(modifier);
			}
		} else {
			if (!((List) main.getObject()).getPrivateMods().contains(modifier)
					|| !modifier.isExclusive()) {
				((List) main.getObject()).getPrivateMods().add(modifier);
			}
		}
	}

	private void dispatch() {
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				for (int i = 0; i < listeners.size(); i++) {
					ActionListener listener = listeners.get(i);
					listener.actionPerformed(null);
				}
			}
		});
	}

	public Modifier getModifier() {
		return modifier;
	}

	public boolean isSelected() {
		return checkbox.isSelected();
	}

	private void removeFromParent() {
		if (!modifier.isPrivate() || !(parent instanceof List)) {
			parent.getAssignedModifiers().remove(modifier);
		} else {
			((List) parent).getPrivateMods().remove(modifier);
		}
	}

	@Override
	public void setEnabled(boolean enabled) {
		checkbox.setEnabled(enabled);
		valueLbl.setEnabled(enabled);
		aliasTF.setEnabled(enabled);
	}

	public void setSelected(boolean selected) {
		checkbox.setSelected(selected);
		if (selected) {
			addToParent();
		} else {
			removeFromParent();
		}
	}

	public void setSelectionLocked(boolean val) {
		selectionLocked = val;
	}

	public void updateValues() {
		checkbox.removeActionListener(checkboxListener);
		if (!modifier.isPrivate() || !(parent instanceof List)) {
			checkbox.setSelected(parent.getAssignedModifiers().contains(
					modifier));
		} else {
			checkbox.setSelected(((List) main.getObject()).getPrivateMods()
					.contains(modifier));
		}
		checkbox.addActionListener(checkboxListener);
		if (valueLbl != null) {
			valueLbl.setText("("
					+ modifier.getFraction(modifier.getTotalValue()) + ")");
		}
		if (fractionTF != null) {
			fractionTF.setCurrent(modifier.getTotalValue());
		}
		if (levelTF != null) {
			levelTF.setCurrent(modifier.getLevels());
		}
		aliasTF.setText(modifier.getAlias());
	}
}