package xs.party;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.WeakHashMap;

import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;

import as.party.Organization;
import as.party.Party;
import as.party.Person;
import as.relation.AggregationType;

import wicket.Component;
import wicket.ResourceReference;
import wicket.markup.html.PackageResourceReference;
import wicket.markup.html.image.Image;
import xs.school.School;

public class Tree extends wicket.markup.html.tree.Tree {

	private final ResourceReference organizaton = 
		new PackageResourceReference(
				Application.get(),
				Tree.class, 
				"organization.gif");
	private final ResourceReference school = 
		new PackageResourceReference(
				Application.get(),
				Tree.class, 
				"school.gif");
	private final ResourceReference person = 
		new PackageResourceReference(
				Application.get(),
				Tree.class, 
				"person.gif");	
	
	public Tree(String id, TreeModel model) {
		super(id, model);
	}
	
	public Tree(String id, Party party, AggregationType aggregationType) {
		super(id, new TreeModel(party, aggregationType));
	}
	
	/* (non-Javadoc)
	 * @see wicket.markup.html.tree.Tree#newNodePanel(java.lang.String, javax.swing.tree.DefaultMutableTreeNode)
	 */
	protected Component newNodePanel(String panelId, DefaultMutableTreeNode node) {
		// TODO Auto-generated method stub
		return super.newNodePanel(panelId, node);
	}

	/* (non-Javadoc)
	 * @see wicket.markup.html.tree.Tree#getNodeImage(javax.swing.tree.DefaultMutableTreeNode)
	 */
	protected Image getNodeImage(final DefaultMutableTreeNode node)	{
		Party party = (Party) node.getUserObject();
		if (party instanceof Person)
			return new Image(NODE_IMAGE_NAME, person); 
		if (party instanceof School)
			return new Image(NODE_IMAGE_NAME, school);
		
		return new Image(NODE_IMAGE_NAME, organizaton);
	}

	
	public static class TreeModel extends DefaultTreeModel implements Serializable {
		
		private AggregationType aggregationType;
		
		private transient WeakHashMap childrens = new WeakHashMap();
		
		private transient Comparator comparator = new Comparator() {
			public int compare(Object o1, Object o2) {
				Party p1 = (Party) (((DefaultMutableTreeNode)o1).getUserObject());
				Party p2 = (Party) (((DefaultMutableTreeNode)o2).getUserObject());
				
				return p1.getName().compareTo(p2.getName());
			}
		};
		
		public TreeModel(Party party, AggregationType aggregationType) {
			super(new DefaultMutableTreeNode(party));
			this.aggregationType = aggregationType;
		}
		
		public void setComparator(Comparator comparator) {
			this.comparator = comparator;
		}
		
		private List childrenOf(Party p) {
			List children = (List) this.childrens.get(p);
			if (children == null) {
				children = toDefaultMutableNodeList(p.getChildren(aggregationType));
				this.childrens.put(p, children);
			}
			
			return children;
		}
		
		private List toDefaultMutableNodeList(Set parties) {
			List result = new ArrayList();
			for (Iterator iterator = parties.iterator(); iterator.hasNext(); ) {
				DefaultMutableTreeNode n = new DefaultMutableTreeNode(iterator.next());
				int index = -Collections.binarySearch(result, n, this.comparator) - 1;
				result.add(index, n);
			}
			
			return result;
		}

		public Object getChild(Object parent, int index) {
			return childrenOf(
						(Party) (((DefaultMutableTreeNode)parent).getUserObject()))
					.get(index);
		}

		public int getChildCount(Object parent) {
			return childrenOf(
					(Party) (((DefaultMutableTreeNode)parent).getUserObject()))
				.size();
		}

		public int getIndexOfChild(Object parent, Object child) {
			return childrenOf(
					(Party) (((DefaultMutableTreeNode)parent).getUserObject()))
				.indexOf(((DefaultMutableTreeNode)child).getUserObject());
		}

		public boolean isLeaf(Object node) {
			Party p = (Party) (((DefaultMutableTreeNode)node).getUserObject());
			return !(p instanceof Organization);
		}
	
	}
	
}
