/*
 * $Id: TreeViewItem.java,v 1.15 2007/10/30 12:24:09 marbobo Exp $
 *
 * Copyright (c) Siemens AG 2008 
 *           (c) Universität Paderborn 2008 
 * Licensed under EUPL 1.1. 
 *
 * $Log: TreeViewItem.java,v $
 * Revision 1.15  2007/10/30 12:24:09  marbobo
 * + removed unnecessary statements
 *
 * Revision 1.14  2006/10/02 00:25:54  marbobo
 * + Explorer Fehlerbeseitigt (Hoffe endgültig)
 *
 * Revision 1.13  2005/06/23 01:04:08  aram
 * + Anpassungen bzgl. Cluster-Moduls
 *
 * Revision 1.12  2005/02/11 15:07:53  marbobo
 * + getShortText() auf Unicode-Zeichen angepasst
 *
 * Revision 1.11  2004/03/07 20:05:58  bigmac
 * einige Methoden aus der VKCDataBase in die entsprechenden 
 * Serializer verschoben, ein paar Refactorings durchgeführt und 
 * tote Code-Teile entfernt
 *
 * Revision 1.10  2003/11/14 02:27:21  koppy
 * Features + Refactoring
 *
 * Revision 1.9  2003/11/12 01:11:11  koppy
 * Navigatorverhalten optimiert
 *
 * Revision 1.8  2003/11/11 02:39:09  koppy
 * Redesign/ Refactoring
 *
 * Revision 1.7  2003/11/05 00:27:15  koppy
 * bugfix + Verbesserungen
 *
 * Revision 1.6  2003/09/16 21:25:48  koppy
 * update des treeview bei copy&move Operationen
 *
 * Revision 1.5  2003/09/16 00:22:34  koppy
 * +deleteChildByName(...)
 *
 * Revision 1.4  2003/08/07 20:05:32  bigmac
 * *** empty log message ***
 *
 * Revision 1.3  2003/05/05 15:08:01  koppy
 * ...
 *
 * Revision 1.2  2003/04/30 01:12:04  koppy
 * Optional filter embedded
 *
 * Revision 1.1  2003/04/29 11:08:25  koppy
 * Initiale Version
 *
 */
package vkc.util.treeview;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import vkc.util.VKCStringUtils;
import vkc.util.sort.CaseIndependentComparator;

/**
 * This class represents a node in a tree
 * 
 * @author koppy
 * @see TreeView
 */
public class TreeViewItem implements Serializable {
	private String id;
	private String image;
	private String text;
	private String link;
	private String target;

	private boolean observed = false;
	private boolean locked = false;
	private boolean expanded = false;
	private boolean checked = false;
	private boolean drawCheckBox = false;
	private boolean draw = true;

	private TreeViewItem parent = null;

	private int depth = 0;
	private int pos = 0;
	private int virtualChildSize = 0;

	private List children = new ArrayList();

	private TreeViewItem() {
	}

	/**
	 * Constructor
	 * 
	 * @param id
	 *            a unique name for this item (for internal usage)
	 * @param image
	 *            name of the image to be used for this item, e.g. "page.gif"
	 * @param text
	 *            the name to be displayed, e.g. "Contact"
	 * @param link
	 *            a link, e.g. "contact.html"
	 */
	public TreeViewItem(String id, String image, String text, String link) {
		this();
	    this.id = id;
		this.image = image;
		this.text = text;
		this.link = link;
	}

	/**
	 * Constructor
	 * 
	 * @param id
	 *            a unique name for this item (for internal usage)
	 * @param image
	 *            name of the image to be used for this item, e.g. "page.gif"
	 * @param text
	 *            the name to be displayed, e.g. "Contact"
	 * @param link
	 *            a link, e.g. "contact.html"
	 */
	public TreeViewItem(String id, String image, String text, String link, String target) {
        this();
		this.id = id;
		this.image = image;
		this.text = text;
		this.link = link;
		this.target = target;
	}

	/**
	 * Adds a child to this treenode
	 * 
	 * @param child
	 *            the child to be added
	 */
	public void addChild(TreeViewItem child) {
		children.add(child);
		child.setParent(this);
		virtualChildSize++;
		
		sortChildren();
		// and updates the depth level
		updateDepthAndPos(false, true);
	}

	/**
	 * Sorts all children by a caseindependent comparator
	 * 
	 */
	private void sortChildren() {
		Collections.sort(children, new CaseIndependentComparator());
	}

	private void updateDepthAndPos(boolean updateThisItem, boolean traverseEntireTree) {
		if (updateThisItem) {
			this.depth = parent.getDepth() + 1;
		}

		if (children.isEmpty())
			return;

		int i = 0;
		for (Iterator it = children.iterator(); it.hasNext(); i++) {
			TreeViewItem tItem = (TreeViewItem) it.next();
			
			if (traverseEntireTree) {
				tItem.updateDepthAndPos(true, true);
			}
			
			// Update the Position in the first level only
			// The other has not been touched!
			if (!updateThisItem) {
				tItem.setPos(i);
			}
		}
	}

	/**
	 * Deletes a child
	 * 
	 * @param item
	 *            the name of the child to be deleted
	 */
	public void deleteChildById(String id) {
		boolean removed = false;

		for (Iterator it = children.iterator(); it.hasNext();) {
			TreeViewItem cItem = (TreeViewItem) it.next();
			
			if (removed) {
				cItem.decPos();
				continue;
			}

			if (cItem.getId().equals(id)) {
				it.remove();
				removed = true;
				virtualChildSize--;
			}

		}

	}

	/**
	 * Decreases the Depth by 1
	 */
	private void decPos() {
		this.pos--;
	}

	public boolean isLeaf() {
		return virtualChildSize == 0;
	}

	public String getImage() {
		return image;
	}

	public String getLink() {
		return link;
	}

	public String getId() {
		return id;
	}

	public String getShortText() {
		String s = VKCStringUtils.decodeXmlEntities(text);

		if (s.length() > 15) {
			return VKCStringUtils.encodeXmlEntities(s.substring(0, 14)) + "...";
		}

		return VKCStringUtils.encodeXmlEntities(s);
	}

	public String getText() {
		return text;
	}

	public void setImage(String string) {
		image = string;
	}

	public void setLink(String string) {
		link = string;
	}

	public void setId(String string) {
		id = string;
	}

	public void setText(String string) {
		text = string;

		if (parent == null) {
			// Root node --> nothing to do
			return;
		}
		
		// Text changed, so we have to rearange the children
		parent.sortChildren();
		parent.updateDepthAndPos(false, false);
	}

	public List getChildren() {
		return children;
	}

	public int getDepth() {
		return depth;
	}

	public boolean isExpanded() {
		return expanded;
	}

	public TreeViewItem getParent() {
		return parent;
	}

	public int getPos() {
		return pos;
	}

	public void setDepth(int i) {
		depth = i;
	}

	public void setExpanded(boolean b) {
		expanded = b;
	}

	public void setParent(TreeViewItem item) {
		parent = item;
	}

	public void setPos(int i) {
		pos = i;
	}

	/**
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	public boolean equals(Object obj) {
		if (!(obj instanceof TreeViewItem)) {
			return false;
		}
		
		return this.id.equals(((TreeViewItem) obj).getId());
	}

	/**
	 * @see java.lang.Object#hashCode()
	 */
	public int hashCode() {
		return this.id.hashCode();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Object#toString()
	 */
	public String toString() {
		return this.text;
	}

	/**
	 * @return
	 */
	public boolean isLocked() {
		return locked;
	}

	/**
	 * @param b
	 */
	public void setLocked(boolean locked) {
		this.locked = locked;

		if (locked) {
			this.image = "folder-closed-locked.gif";
		} else {
			this.image = null;
		}

		observed = true;
	}

	/**
	 * @return
	 */
	public boolean isObserved() {
		return observed;
	}

	/**
	 * @param b
	 */
	public void setObserved(boolean b) {
		observed = b;
	}

	/**
	 * Removes this Item from its parent children
	 */
	public void remove() {
		if (getParent() == null) {
			return;
		}
		
		getParent().deleteChildById(this.id);
	}

	/**
	 * @return Returns the target.
	 */
	public String getTarget() {
		return target;
	}

	/**
	 * @param target
	 *            The target to set.
	 */
	public void setTarget(String target) {
		this.target = target;
	}

	public boolean isChecked() {
		return checked;
	}

	public void setChecked(boolean checked) {
		this.checked = checked;
	}

	public boolean isDrawCheckBox() {
		return drawCheckBox;
	}

	public void setDrawCheckBox(boolean drawCheckBox) {
		this.drawCheckBox = drawCheckBox;
	}

	public int getVirtualChildSize() {
		return virtualChildSize;
	}

	public void setVirtualChildSize(int virtualChildSize) {
		this.virtualChildSize = virtualChildSize;
	}

	public boolean isDraw() {
		return draw;
	}

	public void setDraw(boolean draw) {
		this.draw = draw;
	}
}