package com.hero.ui;

import java.awt.Color;
import java.awt.Container;
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.util.ArrayList;

import javax.swing.BorderFactory;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
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.characteristics.Characteristic;
import com.hero.util.Rounder;

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

	private JLabel baseLbl;

	ArrayList<CharacteristicRow> characteristicRows;

	private JLabel charLbl;

	private JLabel charTotalLbl;

	protected long lastUpdateTime;

	private JLabel levelsLbl;

	JCheckBox ncmCheck;

	JComboBox ncmOptions;

	JTextField ncmTF;

	JLabel ncmValueLbl;

	private JLabel notesLbl;

	private JLabel pointsLbl;

	private JLabel rollLbl;

	private JLabel totalLbl;

	private JLabel totalValueLbl;

	public CharacteristicsPanel() {
		super(new GridBagLayout());
		initWidgets();
		initListeners();
		layoutComponent();
	}

	private void initListeners() {
		if (ncmCheck != null) {
			ncmTF.getDocument().addDocumentListener(new DocumentListener() {
				public void changedUpdate(DocumentEvent e) {
					HeroDesigner.getActiveHero().getFullNCMObject().setAlias(
							ncmTF.getText());
					if (GenericObject.findObjectByID(HeroDesigner
							.getActiveHero().getDisads(), "NCM") != null) {
						HeroDesigner.getActiveHero().getDisads().remove(
								HeroDesigner.getActiveHero().getNCMObject());
						if (HeroDesigner.getActiveHero().getAgeObject() != null) {
							HeroDesigner.getActiveHero().getDisads()
									.remove(
											HeroDesigner.getActiveHero()
													.getAgeObject());
						}
					}
					HeroDesigner.getActiveHero().getFullNCMObject().setAlias(
							ncmTF.getText());
					if (GenericObject.findObjectByID(HeroDesigner
							.getActiveHero().getDisads(), "NCM") == null) {
						HeroDesigner.getActiveHero().getDisads().add(
								HeroDesigner.getActiveHero().getNCMObject());
						if (HeroDesigner.getActiveHero().getAgeObject() != null) {
							HeroDesigner.getActiveHero().getDisads()
									.add(
											HeroDesigner.getActiveHero()
													.getAgeObject());
						}
					}
					HeroDesigner.getActiveHero().setDirty(true);
					updateTotal();
				}

				public void insertUpdate(DocumentEvent e) {
					if (GenericObject.findObjectByID(HeroDesigner
							.getActiveHero().getDisads(), "NCM") != null) {
						HeroDesigner.getActiveHero().getDisads().remove(
								HeroDesigner.getActiveHero().getNCMObject());
						if (HeroDesigner.getActiveHero().getAgeObject() != null) {
							HeroDesigner.getActiveHero().getDisads()
									.remove(
											HeroDesigner.getActiveHero()
													.getAgeObject());
						}
					}
					HeroDesigner.getActiveHero().getFullNCMObject().setAlias(
							ncmTF.getText());
					if (GenericObject.findObjectByID(HeroDesigner
							.getActiveHero().getDisads(), "NCM") == null) {
						HeroDesigner.getActiveHero().getDisads().add(
								HeroDesigner.getActiveHero().getNCMObject());
						if (HeroDesigner.getActiveHero().getAgeObject() != null) {
							HeroDesigner.getActiveHero().getDisads()
									.add(
											HeroDesigner.getActiveHero()
													.getAgeObject());
						}
					}
					HeroDesigner.getActiveHero().setDirty(true);
					updateTotal();
				}

				public void removeUpdate(DocumentEvent e) {
					if (GenericObject.findObjectByID(HeroDesigner
							.getActiveHero().getDisads(), "NCM") != null) {
						HeroDesigner.getActiveHero().getDisads().remove(
								HeroDesigner.getActiveHero().getNCMObject());
						if (HeroDesigner.getActiveHero().getAgeObject() != null) {
							HeroDesigner.getActiveHero().getDisads()
									.remove(
											HeroDesigner.getActiveHero()
													.getAgeObject());
						}
					}
					HeroDesigner.getActiveHero().getFullNCMObject().setAlias(
							ncmTF.getText());
					if (GenericObject.findObjectByID(HeroDesigner
							.getActiveHero().getDisads(), "NCM") == null) {
						HeroDesigner.getActiveHero().getDisads().add(
								HeroDesigner.getActiveHero().getNCMObject());
						if (HeroDesigner.getActiveHero().getAgeObject() != null) {
							HeroDesigner.getActiveHero().getDisads()
									.add(
											HeroDesigner.getActiveHero()
													.getAgeObject());
						}
					}
					HeroDesigner.getActiveHero().setDirty(true);
					updateTotal();
				}
			});
			ncmCheck.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					HeroDesigner.getActiveHero().getDisads().remove(
							HeroDesigner.getActiveHero().getNCMObject());
					if (HeroDesigner.getActiveHero().getAgeObject() != null) {
						HeroDesigner.getActiveHero().getDisads().remove(
								HeroDesigner.getActiveHero().getAgeObject());
					}
					HeroDesigner.getActiveHero().setNCMSelected(
							ncmCheck.isSelected());
					if (ncmCheck.isSelected()) {
						if (GenericObject.findObjectByID(HeroDesigner
								.getActiveHero().getDisads(), "NCM") == null) {
							HeroDesigner.getActiveHero().getDisads()
									.add(
											HeroDesigner.getActiveHero()
													.getNCMObject());
							if (HeroDesigner.getActiveHero().getAgeObject() != null) {
								HeroDesigner.getActiveHero().getDisads().add(
										HeroDesigner.getActiveHero()
												.getAgeObject());
							}
						}
					} else {

					}
					HeroDesigner.getActiveHero().setDirty(true);
					updateTotal();
				}
			});
		}
		if (ncmOptions != null) {
			ncmOptions.addItemListener(new ItemListener() {
				public void itemStateChanged(ItemEvent e) {
					if (GenericObject.findObjectByID(HeroDesigner
							.getActiveHero().getDisads(), "NCM") != null) {
						HeroDesigner.getActiveHero().getDisads().remove(
								HeroDesigner.getActiveHero().getNCMObject());
						if (HeroDesigner.getActiveHero().getAgeObject() != null) {
							HeroDesigner.getActiveHero().getDisads()
									.remove(
											HeroDesigner.getActiveHero()
													.getAgeObject());
						}
					}
					HeroDesigner.getActiveHero().getFullNCMObject()
							.setSelectedOption(
									(Adder) ncmOptions.getSelectedItem());
					ncmValueLbl.setText(Rounder.roundHalfUp(HeroDesigner
							.getActiveHero().getFullNCMObject().getBaseCost())
							+ " point"
							+ (HeroDesigner.getActiveHero().getFullNCMObject()
									.getBaseCost() != 1 ? "s" : ""));
					Adder ad = (Adder) ncmOptions.getSelectedItem();
					String holder = ad.getDisplay();
					((JTextField) ncmOptions.getEditor().getEditorComponent())
							.setText(holder);
					HeroDesigner.getActiveHero().getFullNCMObject()
							.getSelectedOption().setAlias(holder);
					if (GenericObject.findObjectByID(HeroDesigner
							.getActiveHero().getDisads(), "NCM") == null) {
						HeroDesigner.getActiveHero().getDisads().add(
								HeroDesigner.getActiveHero().getNCMObject());
						if (HeroDesigner.getActiveHero().getAgeObject() != null) {
							HeroDesigner.getActiveHero().getDisads()
									.add(
											HeroDesigner.getActiveHero()
													.getAgeObject());
						}
					}
					HeroDesigner.getActiveHero().setDirty(true);
					updateTotal();
				}
			});
			((JTextField) ncmOptions.getEditor().getEditorComponent())
					.getDocument().addDocumentListener(new DocumentListener() {
						public void changedUpdate(DocumentEvent e) {
							if (GenericObject.findObjectByID(HeroDesigner
									.getActiveHero().getDisads(), "NCM") != null) {
								HeroDesigner.getActiveHero().getDisads()
										.remove(
												HeroDesigner.getActiveHero()
														.getNCMObject());
								if (HeroDesigner.getActiveHero().getAgeObject() != null) {
									HeroDesigner.getActiveHero().getDisads()
											.remove(
													HeroDesigner
															.getActiveHero()
															.getAgeObject());
								}
							}
							HeroDesigner.getActiveHero().getFullNCMObject()
									.getSelectedOption().setAlias(
											((JTextField) ncmOptions
													.getEditor()
													.getEditorComponent())
													.getText());
							if (GenericObject.findObjectByID(HeroDesigner
									.getActiveHero().getDisads(), "NCM") == null) {
								HeroDesigner.getActiveHero().getDisads().add(
										HeroDesigner.getActiveHero()
												.getNCMObject());
								if (HeroDesigner.getActiveHero().getAgeObject() != null) {
									HeroDesigner.getActiveHero().getDisads()
											.add(
													HeroDesigner
															.getActiveHero()
															.getAgeObject());
								}
							}
							HeroDesigner.getActiveHero().setDirty(true);
						}

						public void insertUpdate(DocumentEvent e) {
							if (GenericObject.findObjectByID(HeroDesigner
									.getActiveHero().getDisads(), "NCM") != null) {
								HeroDesigner.getActiveHero().getDisads()
										.remove(
												HeroDesigner.getActiveHero()
														.getNCMObject());
								if (HeroDesigner.getActiveHero().getAgeObject() != null) {
									HeroDesigner.getActiveHero().getDisads()
											.remove(
													HeroDesigner
															.getActiveHero()
															.getAgeObject());
								}
							}
							HeroDesigner.getActiveHero().getFullNCMObject()
									.getSelectedOption().setAlias(
											((JTextField) ncmOptions
													.getEditor()
													.getEditorComponent())
													.getText());
							if (GenericObject.findObjectByID(HeroDesigner
									.getActiveHero().getDisads(), "NCM") == null) {
								HeroDesigner.getActiveHero().getDisads().add(
										HeroDesigner.getActiveHero()
												.getNCMObject());
								if (HeroDesigner.getActiveHero().getAgeObject() != null) {
									HeroDesigner.getActiveHero().getDisads()
											.add(
													HeroDesigner
															.getActiveHero()
															.getAgeObject());
								}
							}
							HeroDesigner.getActiveHero().setDirty(true);
						}

						public void removeUpdate(DocumentEvent e) {
							if (GenericObject.findObjectByID(HeroDesigner
									.getActiveHero().getDisads(), "NCM") != null) {
								HeroDesigner.getActiveHero().getDisads()
										.remove(
												HeroDesigner.getActiveHero()
														.getNCMObject());
								if (HeroDesigner.getActiveHero().getAgeObject() != null) {
									HeroDesigner.getActiveHero().getDisads()
											.remove(
													HeroDesigner
															.getActiveHero()
															.getAgeObject());
								}
							}
							HeroDesigner.getActiveHero().getFullNCMObject()
									.getSelectedOption().setAlias(
											((JTextField) ncmOptions
													.getEditor()
													.getEditorComponent())
													.getText());
							if (GenericObject.findObjectByID(HeroDesigner
									.getActiveHero().getDisads(), "NCM") == null) {
								HeroDesigner.getActiveHero().getDisads().add(
										HeroDesigner.getActiveHero()
												.getNCMObject());
								if (HeroDesigner.getActiveHero().getAgeObject() != null) {
									HeroDesigner.getActiveHero().getDisads()
											.add(
													HeroDesigner
															.getActiveHero()
															.getAgeObject());
								}
							}
							HeroDesigner.getActiveHero().setDirty(true);
						}
					});
		}
	}

	private void initWidgets() {
		characteristicRows = new ArrayList<CharacteristicRow>();
		charTotalLbl = new JLabel("Total");
		levelsLbl = new JLabel("Value");
		charLbl = new JLabel("Char");
		baseLbl = new JLabel("Base");
		pointsLbl = new JLabel("Cost");
		rollLbl = new JLabel("Roll");
		notesLbl = new JLabel("Notes");
		totalLbl = new JLabel("Total Characteristics Points:");
		totalValueLbl = new JLabel(""
				+ Rounder.roundUp(HeroDesigner.getActiveHero()
						.getCharacteristicsTotal()));
		for (int i = 0; i < HeroDesigner.getActiveHero().getCharacteristics()
				.size(); i++) {
			Characteristic ch = (Characteristic) HeroDesigner.getActiveHero()
					.getCharacteristics().get(i);
			CharacteristicRow row = new CharacteristicRow(this, ch,
					(GridBagLayout) getLayout(), i + 1);
			characteristicRows.add(row);
		}
		Adder ncm = HeroDesigner.getActiveHero().getFullNCMObject();
		if (ncm != null) {
			ncmCheck = new JCheckBox();
			ncmCheck.setSelected(HeroDesigner.getActiveHero().isNCMSelected());
			ncmCheck.setEnabled(HeroDesigner.getActiveHero().getRules()
					.isNCMUserChangeable());
			ncmTF = new JTextField(ncm.getAlias());
			ncmTF.setBorder(BorderFactory.createLineBorder(Color.black, 1));
			// ncmTF.setOpaque(false);
			ncmValueLbl = new JLabel(Rounder.roundHalfUp(ncm.getBaseCost())
					+ " point" + (ncm.getBaseCost() != 1 ? "s" : ""));
			if ((ncm.getOptions() != null) && (ncm.getOptions().size() > 0)) {
				ncmOptions = new JComboBox(ncm.getOptions().toArray());
				ncmOptions.setEditable(true);
				ncmOptions.setSelectedItem(ncm.getSelectedOption());
				((JTextField) ncmOptions.getEditor().getEditorComponent())
						.setText(ncm.getSelectedOption().getAlias());
			} else {
				ncmOptions = null;
			}
		} else {
			ncmCheck = null;
			ncmTF = null;
			ncmValueLbl = null;
			ncmOptions = null;
		}
	}

	private void layoutComponent() {
		GridBagConstraints gbc = new GridBagConstraints();
		gbc.gridx = 0;
		gbc.gridy = 0;
		gbc.gridwidth = 1;
		gbc.gridheight = 1;
		gbc.weightx = 0;
		gbc.weighty = 0;
		gbc.anchor = GridBagConstraints.CENTER;
		gbc.fill = GridBagConstraints.NONE;
		gbc.insets = new Insets(3, 5, 3, 5);
		add(levelsLbl, gbc);
		gbc.gridx++;
		add(charLbl, gbc);
		gbc.gridx++;
		add(baseLbl, gbc);
		gbc.gridx++;
		add(pointsLbl, gbc);
		gbc.gridx++;
		add(charTotalLbl, gbc);
		gbc.gridx++;
		add(rollLbl, gbc);
		gbc.gridx++;
		gbc.weightx = 1;
		gbc.anchor = GridBagConstraints.WEST;
		add(notesLbl, gbc);
		gbc.gridy += characteristicRows.size();
		gbc.gridy++;
		gbc.gridx = 0;
		gbc.anchor = GridBagConstraints.WEST;
		gbc.gridwidth = GridBagConstraints.REMAINDER;
		gbc.fill = GridBagConstraints.HORIZONTAL;
		if (ncmCheck != null) {
			GridBagConstraints gbc2 = new GridBagConstraints();
			gbc2.gridx = 0;
			gbc2.gridy = 0;
			gbc2.gridwidth = 1;
			gbc2.gridheight = 1;
			gbc2.weightx = 0;
			gbc2.weighty = 1;
			gbc2.anchor = GridBagConstraints.EAST;
			gbc2.fill = GridBagConstraints.VERTICAL;
			gbc2.insets = new Insets(3, 3, 3, 3);
			JPanel ncmPanel = new JPanel(new GridBagLayout());
			ncmPanel.add(ncmCheck, gbc2);
			gbc2.gridx++;
			gbc2.weightx = 1;
			gbc2.fill = GridBagConstraints.BOTH;
			gbc2.insets = new Insets(3, 3, 3, 0);
			ncmPanel.add(ncmTF, gbc2);
			gbc2.fill = GridBagConstraints.VERTICAL;
			if (ncmOptions != null) {
				gbc2.gridx++;
				gbc2.weightx = 0;
				gbc2.anchor = GridBagConstraints.WEST;
				gbc2.insets = new Insets(3, 0, 3, 3);
				ncmPanel.add(ncmOptions, gbc2);
			}
			gbc2.insets = new Insets(3, 3, 3, 3);
			gbc2.gridx++;
			gbc2.weightx = 1;
			gbc2.anchor = GridBagConstraints.WEST;
			ncmPanel.add(ncmValueLbl, gbc2);
			add(ncmPanel, gbc);
		}
		gbc.fill = GridBagConstraints.NONE;
		gbc.gridy++;
		gbc.gridwidth = 6;
		gbc.gridx = 0;
		gbc.weighty = 1;
		gbc.weightx = 0;
		gbc.anchor = GridBagConstraints.NORTHEAST;
		gbc.insets = new Insets(3, 0, 3, 0);
		add(totalLbl, gbc);
		gbc.gridx = 6;
		gbc.insets = new Insets(3, 0, 3, 0);
		gbc.gridwidth = GridBagConstraints.REMAINDER;
		gbc.anchor = GridBagConstraints.NORTHWEST;
		gbc.weightx = 1;
		add(totalValueLbl, gbc);
	}

	/**
	 * Removes all CharacteristicRows and reconstructs this panel entirely. This
	 * should be called when changing characters/templates.
	 */
	public void reset() {
		lastUpdateTime = 0;
		removeAll();
		initWidgets();
		initListeners();
		layoutComponent();
	}

	/**
	 * Updates the CharacteristicRows based on the Characteristic passed in.
	 * Only Characteristics that are equal to or affected by the passed in type
	 * will be updated.
	 * 
	 * @param type
	 */
	public void update(int type) {
		for (CharacteristicRow row : characteristicRows) {
			if (row.getCharacteristic().getType() == type) {
				row.update();
			}
		}
	}

	/**
	 * Updates the costs and totals displayed on this tab.
	 */
	public void updateCosts() {
		double avail = HeroDesigner.getActiveHero().getBasePoints()
				+ HeroDesigner.getActiveHero().getDisadPoints()
				+ HeroDesigner.getActiveHero().getExperience();
		if (HeroDesigner.getActiveTemplate().is6E()) {
			avail -= HeroDesigner.getActiveHero().getDisadPoints();
		}
		totalValueLbl.setText(""
				+ Rounder.roundUp(HeroDesigner.getActiveHero()
						.getCharacteristicsTotal()) + " (Total Spent: "
				+ Rounder.roundUp(HeroDesigner.getActiveHero().getSpentTotal())
				+ "/" + Rounder.roundUp(avail) + ")");
		if (ncmCheck != null) {
			ncmCheck.setSelected(HeroDesigner.getActiveHero().isNCMSelected());
		}
		if ((ncmValueLbl != null)
				&& (HeroDesigner.getActiveHero().getFullNCMObject() != null)) {
			ncmValueLbl.setText(Rounder.roundHalfUp(HeroDesigner
					.getActiveHero().getFullNCMObject().getBaseCost())
					+ " point"
					+ (HeroDesigner.getActiveHero().getFullNCMObject()
							.getBaseCost() != 1 ? "s" : ""));
		}
		JScrollPane s = null;
		Container parent = getParent();
		while (parent != null) {
			if (parent instanceof JScrollPane) {
				s = (JScrollPane) parent;
				break;
			}
			parent = parent.getParent();
		}
		if ((lastUpdateTime <= 0) || (lastUpdateTime < HeroDesigner.lastEdit)) {
			lastUpdateTime = System.currentTimeMillis();
			if (s != null) {
				HeroDesigner.getInstance().mainPanel.updateFrames(s);
			}
		}
	}

	/**
	 * Updates the total cost information displayed.
	 */
	public void updateTotal() {
		if ((lastUpdateTime <= 0) || (lastUpdateTime < HeroDesigner.lastEdit)) {
			updateCosts();
			for (CharacteristicRow row : characteristicRows) {
				row.update();
			}
			lastUpdateTime = System.currentTimeMillis();
		}
	}
}