package com.hero.ui;

import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

import javax.swing.JComponent;
import javax.swing.JLabel;

import com.hero.HeroDesigner;
import com.hero.objects.GenericObject;
import com.hero.objects.characteristics.Characteristic;
import com.hero.objects.powers.Automaton;
import com.hero.ui.widgets.LevelTF;
import com.hero.ui.widgets.PopupMessage;
import com.hero.util.Constants;
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 CharacteristicRow extends JComponent {

	private static final long serialVersionUID = 757343676469212364L;

	Characteristic characteristic;

	private CharacteristicsPanel main;

	private int row;

	LevelTF level;

	private JLabel charDisplay;

	private JLabel base;

	private JLabel cost;

	private JLabel roll;

	private JLabel total;

	private JLabel notes;

	// private DocumentListener listener;

	protected long lastUpdateTime;

	public CharacteristicRow(CharacteristicsPanel main, Characteristic ch,
			GridBagLayout layoutManager, int row) {
		super();
		setLayout(layoutManager);
		characteristic = ch;
		this.main = main;
		this.row = row;
		initWidgets();
		initListeners();
		layoutComponent();
	}

	boolean checkFigured() {
		if (!HeroDesigner.getActiveHero().getRules().onlySellOneFigured()) {
			return true;
		}
		if (characteristic.isFigured()) {
			for (int i = 0; i < HeroDesigner.getActiveHero()
					.getCharacteristics().size(); i++) {
				Characteristic ch = (Characteristic) HeroDesigner
						.getActiveHero().getCharacteristics().get(i);
				if (ch.isFigured()
						&& !(ch.getType() == characteristic.getType())
						&& (ch.getLevels() < 0)) {
					return false;
				}
			}
			return true;
		} else {
			return true;
		}
	}

	/**
	 * Returns the Characteristic that this CharacteristicRow is tracking.
	 * 
	 * @return
	 */
	public Characteristic getCharacteristic() {
		return characteristic;
	}

	private void initListeners() {
		level.addPropertyChangeListener("Level", new PropertyChangeListener() {
			public void propertyChange(PropertyChangeEvent e) {
				if (!e.getOldValue().equals(e.getNewValue())) {
					valueChanged();
				}
			}
		});
	}

	private void initWidgets() {
		total = new JLabel(characteristic.getValueDisplay());
		level = new LevelTF((int) Rounder.roundHalfUp(characteristic
				.getCharacteristicValue()), characteristic.getMaxVal(),
				characteristic.getMinimumLevel());
		charDisplay = new JLabel(characteristic.getDisplay());
		base = new JLabel(characteristic.getCharacteristicBase());
		cost = new JLabel("" + Rounder.roundUp(characteristic.getRealCost()));
		roll = new JLabel(characteristic.getRoll());
		notes = new JLabel(characteristic.getDisplayNotes());
	}

	private void layoutComponent() {
		GridBagConstraints gbc = new GridBagConstraints();
		gbc.gridx = 0;
		gbc.gridy = row;
		gbc.gridwidth = 1;
		gbc.gridheight = 1;
		gbc.weightx = 0;
		gbc.weighty = 0;
		gbc.anchor = GridBagConstraints.NORTH;
		gbc.fill = GridBagConstraints.NONE;
		gbc.insets = new Insets(2, 5, 2, 5);
		main.add(level, gbc);
		gbc.gridx++;
		main.add(charDisplay, gbc);
		gbc.gridx++;
		main.add(base, gbc);
		gbc.gridx++;
		main.add(cost, gbc);
		gbc.gridx++;
		main.add(total, gbc);
		gbc.gridx++;
		if (characteristic.showRoll()) main.add(roll, gbc);
		gbc.gridx++;
		gbc.weightx = 1;
		gbc.anchor = GridBagConstraints.NORTHWEST;
		main.add(notes, gbc);
	}

	/**
	 * Toggles the visibility of this Characteristic Row (useful on Automatons,
	 * where the STUN Characteristic may need to be hidden)
	 */
	@Override
	public void setVisible(boolean visible) {
		level.setVisible(visible);
		charDisplay.setVisible(visible);
		base.setVisible(visible);
		cost.setVisible(visible);
		if (characteristic.showRoll()) roll.setVisible(visible);
		total.setVisible(visible);
		notes.setVisible(visible);
	}

	/**
	 * Updates the values on this CharacteristicRow based on the valued
	 * contained in its Characteristic.
	 */
	public synchronized void update() {
		if (characteristic.getType() == Constants.STUN) {
			if (GenericObject.findObjectByID(HeroDesigner.getActiveHero()
					.getPowers(), "AUTOMATON") != null) {
				Automaton auto = (Automaton) GenericObject.findObjectByID(
						HeroDesigner.getActiveHero().getPowers(), "AUTOMATON");
				if (auto.getSelectedOption().getXMLID().toUpperCase()
						.startsWith("NOSTUN")) {
					characteristic.setLevels(0);
					level.setCurrent((int) Rounder.roundHalfUp(characteristic
							.getCharacteristicValue()));
					level.setMin((int) Rounder.roundHalfUp(characteristic
							.getCharacteristicValue()));
					level.setMax((int) Rounder.roundHalfUp(characteristic
							.getCharacteristicValue()));
					setVisible(false);
				} else {
					level.setCurrent((int) Rounder.roundHalfUp(characteristic
							.getCharacteristicValue()));
					level.setMin(characteristic.getMinimumLevel());
					level.setMax(characteristic.getMaxLevel());
					setVisible(true);
				}
			} else {
				level.setCurrent((int) Rounder.roundHalfUp(characteristic
						.getCharacteristicValue()));
				level.setMin(characteristic.getMinimumLevel());
				level.setMax(characteristic.getMaxLevel());
				setVisible(true);
				for (int i = 0; i < HeroDesigner.getActiveHero()
						.getCharacteristics().size(); i++) {
					Characteristic c = (Characteristic) HeroDesigner
							.getActiveHero().getCharacteristics().get(i);
					if (c.getType() == characteristic.getType()) {
						continue;
					} else if (characteristic.getIncrease(c.getType()) != 0) {
						main.update(c.getType());
					}
				}
			}
		}
		level.setMin(characteristic.getMinimumLevel());
		double current = Rounder.roundHalfUp(characteristic
				.getCharacteristicValue());
		if (current != level.getCurrent()) {
			level.setCurrent((int) Rounder.roundHalfUp(characteristic
					.getCharacteristicValue()));
		}
		total.setText(characteristic.getValueDisplay());
		if (characteristic.showRoll()) roll.setText(characteristic.getRoll());
		notes.setText(characteristic.getDisplayNotes());
		cost.setText("" + Rounder.roundUp(characteristic.getRealCost() - .005));
		base.setText(characteristic.getCharacteristicBase());
		for (int i = 0; i < HeroDesigner.getActiveHero().getCharacteristics()
				.size(); i++) {
			Characteristic c = (Characteristic) HeroDesigner.getActiveHero()
					.getCharacteristics().get(i);
			if (c.getType() == characteristic.getType()) {
				continue;
			} else if (characteristic.getIncrease(c.getType()) != 0) {
				main.update(c.getType());
			} else if ((c.getType() == Constants.DEX)
					&& ((characteristic.getOcvIncrease() != 0) || (characteristic
							.getDcvIncrease() != 0))) {
				main.update(c.getType());
			}
		}
		lastUpdateTime = System.currentTimeMillis();
	}

	synchronized void updateValues() {
		// if (lastUpdateTime > 0 && lastUpdateTime >= HeroDesigner.lastEdit) {
		// return;
		// }
		update();
		main.updateCosts();
	}

	private synchronized void valueChanged() {
		// locked = true;
		try {
			double oldVal = characteristic.getCharacteristicValue();

			int old = characteristic.getLevels();
			characteristic.setValue(level.getCurrent());
			int newVal = characteristic.getLevels();
			if ((newVal != old) && ((newVal >= 0) || checkFigured())) {
				HeroDesigner.getActiveHero().setDirty(true);
			} else {
				if (!checkFigured() && (newVal < 0) && (old != newVal)) {
					PopupMessage popup = PopupMessage
							.getInstance(
									HeroDesigner.getAppFrame(),
									level,
									"You may only sell off one figured characteristic.",
									true);
					if (level.isShowing()) {
						popup.setVisible(true);
					}
				}
				if (newVal != old) {
					characteristic.setValue(oldVal);
				}
			}
			updateValues();
		} catch (Exception exp) {

		} finally {
			// locked = false;
		}
	}
}
