package com.hero.ui.widgets;

import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.util.Hashtable;
import java.util.Vector;

import javax.swing.JToolTip;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;

import com.hero.HeroDesigner;
import com.hero.objects.GenericObject;

/**
 * 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 TipTree extends JTree {

	private static final long serialVersionUID = 1176303450230758065L;

	public static String normalizeText(String message) {
		int index = 0;
		message = message.trim();
		if (message.startsWith("(") && (message.indexOf(")") > 0)) {
			index = message.indexOf(")") + 1;
		}
		if (index <= 0) {
			return "<html>" + message + "</html>";
		}
		String ret = "<html><b>" + message.substring(0, index) + "</b><br><br>";
		message = message.substring(index, message.length());
		ret += message + "</html>";
		return ret;
	}

	public static String removeTabs(String message) {
		while (message.indexOf("\t") >= 0) {
			if (message.indexOf("\t") == 0) {
				message = message.substring(1, message.length());
			} else if (message.indexOf("\t") < message.length() - 1) {
				String part1 = message.substring(0, message.indexOf("\t"));
				String part2 = message.substring(message.indexOf("\t") + 1,
						message.length());
				message = part1 + part2;
			} else {
				message = message.substring(0, message.length() - 1);
			}
		}
		return message;
	}

	public TipTree() {
		super();
	}

	public TipTree(Hashtable<?, ?> pValue) {
		super(pValue);
	}

	public TipTree(Object[] pValue) {
		super(pValue);
	}

	public TipTree(TreeModel pNewModel) {
		super(pNewModel);
	}

	public TipTree(TreeNode pRoot) {
		super(pRoot);
	}

	public TipTree(TreeNode pRoot, boolean pAsksAllowsChildren) {
		super(pRoot, pAsksAllowsChildren);
	}

	public TipTree(Vector<?> pValue) {
		super(pValue);
	}

	@Override
	public JToolTip createToolTip() {
		JToolTip tip = super.createToolTip();
		tip.setPreferredSize(getToolTipSize(getToolTipText()));
		tip.setMinimumSize(getToolTipSize(getToolTipText()));
		return tip;
	}

	@Override
	public Point getToolTipLocation(MouseEvent pEvent) {
		String text = getToolTipText(pEvent);
		Dimension size = getToolTipSize(text);
		Point ret = pEvent.getPoint();
		if (ret.getY() + size.height > HeroDesigner.getAppFrame().getLocation()
				.getY()
				+ HeroDesigner.getAppFrame().getSize().height) {
			ret = new Point(ret.x, ret.y - size.height);
			return ret;
		}
		return super.getToolTipLocation(pEvent);
	}

	private Dimension getToolTipSize(String text) {
		if (text == null) {
			return new Dimension(0, 0);
		}
		FontMetrics fm = getFontMetrics(getFont());
		int overallWidth = fm.stringWidth(text);
		int width = overallWidth;
		int lineHeight = fm.getHeight();
		int height = lineHeight;
		int numLines = 1;
		while ((width > 100) && (height * 3 < width)) {
			numLines++;
			int requiredLines = 2;
			int checkWidth = overallWidth / numLines;
			int lastSpace = 0;
			int lastLine = 0;
			for (int i = 0; i < text.length(); i++) {
				String test = text.substring(lastLine, i);
				if (test.length() > 0) {
					char last = test.charAt(test.length() - 1);
					if ((last == ' ') || (last == '\n') || (last == '\r')
							|| (last == '\t')) {
						lastSpace = i;
					}
				}

				if (fm.stringWidth(test) > checkWidth) {
					requiredLines++;
					if (lastSpace == lastLine) {
						lastLine = i;
						lastSpace = i;
					} else {
						lastLine = lastSpace;
						i = lastSpace;
					}
				} else if ((test.length() > 0)
						&& ((test.charAt(test.length() - 1) == '\n') || (test
								.charAt(test.length() - 1) == '\r'))) {
					requiredLines++;
					lastLine = i;
					lastSpace = i;
				}
			}
			int checkHeight = lineHeight * requiredLines;
			if (checkWidth / checkHeight < 2) {
				break;
			}
			width = checkWidth;
			height = checkHeight;
		}
		return new Dimension(width, height);
	}

	@Override
	public String getToolTipText(MouseEvent pEvent) {
		if (!HeroDesigner.getInstance().getPrefs().showPopupDefinitions()) {
			setToolTipText("");
			return "";
		}
		TreePath path = getClosestPathForLocation(pEvent.getX(), pEvent.getY());
		DefaultMutableTreeNode node = (DefaultMutableTreeNode) path
				.getLastPathComponent();
		GenericObject o = (GenericObject) node.getUserObject();
		if ((o.getDefinition() != null)
				&& (o.getDefinition().trim().length() > 0)) {
			String text = TipTree.normalizeText(TipTree.removeTabs(o
					.getDefinition()));
			setToolTipText(text);
			return text;
		} else {
			setToolTipText("");
			return "";
		}
	}

}