package de.dass_it.vanhelsing.gui;

//import org.apache.log4j.Logger;
import java.lang.reflect.Method;
import java.util.Enumeration;

import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.DefaultMutableTreeNode;
import de.dass_it.vanhelsing.gui.items.*;
import de.dass_it.www.vanhelsing.*;
import de.dass_it.www.vanhelsing.VanHelsingCallbackHandler.*;
import de.dass_it.www.vanhelsing.VanHelsingStub.*;

/**
 * Helper class to encapsulate all procedures 
 * to work with the tree structure.
 * @author tgoecke
 */
public class TreeNavigation extends BeanUtil {
	private DefaultTreeModel tree;
	//private Logger logger = Logger.getLogger(this.getClass());
	/**
	 * @param root	root node of the tree to be created
	 * @param nodes		list of names (resource types) used to create header nodes
	 * @param title		argument currently not used.
	 * @return tree		returns a data tree to be used by a view bean
	 */
	public DefaultTreeModel createTree(DefaultMutableTreeNode root, 
			String[] nodes, String title){
		
		DefaultMutableTreeNode node;
		DefaultMutableTreeNode myNode;
		tree = new DefaultTreeModel(root);
		UserObjectItemType item = new UserObjectItemType(root);
		item.setLeaf(false);
		item.setExpanded(true);
		UserObjectItem uoi = new TreeItem("Configuration");
		uoi.setResType("Tree");
		item.setUserObject(uoi);
		root.setUserObject(item);
		
		for(int i = 0; i< nodes.length; i++){
			//root.add(addNode(root, "Tree", nodes[i]));
			myNode = null;
			myNode = addNode(root, nodes[i], nodes[i]);
			if (myNode != null){
				root.add(myNode);
			}
		}
		return tree;
	}
	/**
	 * adds a node to the given parent node, of resource type string and label value title
	 * @param parent	parent node of the created node
	 * @param type		resource type of the created node
	 * @param title		label value of the created type
	 * @return	node	the created node
	 */
	public DefaultMutableTreeNode addNode(DefaultMutableTreeNode parent, String type, String title){
		DefaultMutableTreeNode node = new DefaultMutableTreeNode();
		Class subClass;
		Class myClass;
		Method[] methods;
		Object o;
		UserObjectItemType userObject = new UserObjectItemType(node);
		userObject.setLeaf(false);
		String type2 = "de.dass_it.vanhelsing.gui.items." + type + "Item";
		
		try {
			subClass = Class.forName(type2);
			o = subClass.newInstance();
			UserObjectItem item = (UserObjectItem) o;
			item.setResType(type);
			myClass = item.getClass().asSubclass(subClass);		
			methods = myClass.getMethods();
			for (Method m : methods){
				//System.err.println(m.getName());
				if(m.getName().contains("setValue")){
					m.invoke(item, title);
				}
			}
			//ItemObjekt erzeugen und an das UserObjekt referenzieren
			userObject.setUserObject((UserObjectItem)o);
			//Eine Referenz auf das UserObjekt wird an das Nodeobjekt übergeben
			node.setUserObject(userObject);
			return node;
		} catch (ClassNotFoundException e1){
			System.err.println("Itemclass "+ type2 +" must be in the classpath");
		} catch (InstantiationException e2){
			System.err.println("Class "+type2+" must be a concrete class, not an interface or an abstract class");
		} catch (IllegalAccessException e3){
			System.err.println("Class " + type2 + " lacks a no-argument constructor");
		} catch (Exception e){
			System.err.println("addHeader: " + e.toString());
		}
		
		return null;
	}
	/**
	 * adds a node to the given parent node of resourcetype type which contains the values of the ResourceInfo() object
	 * @param parent	parent node of the created node
	 * @param type	resource type of the created node
	 * @param ri	the data object which is used to update the node UserObject
	 * @return node		the created node
	 */
  	public DefaultMutableTreeNode addNode(DefaultMutableTreeNode parent, String type, ResourceInfo ri){
		DefaultMutableTreeNode node = new DefaultMutableTreeNode();
		Class subClass;
		Class myClass;
		Method[] riMethods;
		Method[] methods;
		Object o;
		UserObjectItemType userObject = new UserObjectItemType(node);
		String type2 = "de.dass_it.vanhelsing.gui.items." + type + "Item";
		
		try {
			subClass = Class.forName(type2);
			o = subClass.newInstance();
			UserObjectItem item = (UserObjectItem) o;
			item.setResType(type);
			myClass = item.getClass().asSubclass(subClass);		
			methods = myClass.getMethods();
			;
			/*for (Method m : methods){
				if(m.getName().contains("set" + p)){
					m.invoke(item, title);
				}
			}*/
			for (Method n : ri.getClass().getDeclaredMethods()){
				if (n.getName().startsWith("get") 
						&& !(n.getName().contains("OMElement") || n.getName().contains("PullParser"))){
						
					//System.err.println("Name: " + n.getName() +" Feld: "+ n.getName().substring(3));
					for (Method m : methods){
						if (m.getName().equals("set"+n.getName().substring(3))){
							m.invoke(item, n.invoke(ri, (Object[])null));
							break;
						}
					}
					
				
				}
				
			}
			//Value-Wert für die TreeView übertragen
			((ItemType)o).setValue(((ItemType)o).getResName());
			//ItemObjekt erzeugen und an das UserObjekt referenzieren
			userObject.setUserObject((UserObjectItem)o);
			//Eine Referenz auf das UserObjekt wird an das Nodeobjekt übergeben
			node.setUserObject(userObject);
			return node;
		} catch (ClassNotFoundException e1){
			System.err.println("Itemclass "+ type2 +" must be in the classpath");
		} catch (InstantiationException e2){
			System.err.println("Class "+type2+" must be a concrete class, not an interface or an abstract class");
		} catch (IllegalAccessException e3){
			System.err.println("Class " + type2 + " lacks a no-argument constructor");
		} catch (Exception e){
			System.err.println("RI: " + e.toString());
		}
		
		return null;
	}
  	/**
  	 * adds a node to the given parent node of resourcetype type which contains the values of the ResourceAttributeType[]
  	 * @param parent	parent node of the created node
  	 * @param type	resource type of the created node
  	 * @param ra	a list of key value pairs returned by the web service access methods
  	 * @return node		the updated parent node
  	 */
  	public DefaultMutableTreeNode addNode(DefaultMutableTreeNode parent, String type, ResourceAttributeType[] ra){

  		//DefaultMutableTreeNode node = new DefaultMutableTreeNode();
		Class subClass;
		Class myClass;
		Method[] raMethods;
		Method[] methods;
		Object o;
		//UserObjectItemType userObject = new UserObjectItemType(node);
		String type2 = "de.dass_it.vanhelsing.gui.items." + type + "Item";
		String key = null, value = null;
		try {
			subClass = Class.forName(type2);
			o = subClass.newInstance();
			UserObjectItem item = ((UserObjectItemType)parent.getUserObject()).getUserObject();
			//item.setResType(type);
			myClass = item.getClass().asSubclass(subClass);		
			methods = myClass.getMethods();
			Method m;
			Method n;
			Class[] args = new Class[1];
			args[0] = String.class;
			for(ResourceAttributeType rat : ra){
				/*for (Method n : rat.getClass().getDeclaredMethods()){
					if (n.getName().equals("getKey")) {
						key = (String)(n.invoke(rat, (Object[])null));
					}
					if (n.getName().equals("getValue")){
						value = (String)(n.invoke(rat, (Object[])null));
						
					}
	
				}*/
				n = (rat.getClass().getMethod("getKey", (Class[])null));
				key = (String)n.invoke(rat, (Object[])null);
				n = (rat.getClass().getMethod("getValue", (Class[])null));
				value = (String)n.invoke(rat, (Object[])null);
				
				if(!(key.isEmpty() && value.isEmpty())){
					key = key.replaceAll(" ", "");
					key = key.toLowerCase();
					key = key.replaceFirst(new Character(key.charAt(0)).toString(),
							new Character(Character.toUpperCase(key.charAt(0))).toString());
					m = myClass.getMethod(("set"+key), args);
					m.invoke(item, value);
					/*if(m.getName().equals("getName") || m.getName().equals("setName")){
						((ItemType)o).setValue(key + ": " + value);
					}*/
	
				}
			}
			//Value-Wert aus Key: Value zusammenbauen 
			
			//ItemObjekt erzeugen und an das UserObjekt referenzieren
			//userObject.setUserObjectItem((UserObjectItem)o);
			//Eine Referenz auf das UserObjekt wird an das Nodeobjekt übergeben
			//node.setUserObject(userObject);
			//System.out.println(((ItemType)((UserObjectItem)(node.getUserObject()))).getResId());
			return parent;
		} catch (ClassNotFoundException e1){
			System.err.println("Itemclass "+ type2 +" must be in the classpath");
		} catch (InstantiationException e2){
			System.err.println("Class "+type2+" must be a concrete class, not an interface or an abstract class");
		} catch (IllegalAccessException e3){
			System.err.println("Class " + type2 + " lacks a no-argument constructor");
		} catch (Exception e){
			System.err.println("Leaf: " + e.toString());
		}
		
		return null;
	}
  	/**
  	 * returns the first node whose UserObject attribute resId matches the given id or null if no node is found
  	 * @param id	resId value of the node
  	 * @param tree	tree object which contains the node
  	 * @return	matching node or null if no mathcing node is found
  	 */
  	public DefaultMutableTreeNode getNode(String id, DefaultTreeModel tree){
  		DefaultMutableTreeNode root;
  		DefaultMutableTreeNode node;
  		int resId = new Integer(id);
  		root = (DefaultMutableTreeNode)tree.getRoot();
  		Enumeration<DefaultMutableTreeNode> e = root.depthFirstEnumeration();
  		
  		while (e.hasMoreElements()){
  			node = e.nextElement();
  			if (resId ==((ItemType)(((UserObjectItemType)node.getUserObject()).getUserObject())).getResId()) {
  				return node;
  			}


  		}
  		return null;
  	}
  	
  	public DefaultMutableTreeNode getNodeByName(String value, DefaultTreeModel tree){
  		DefaultMutableTreeNode root;
  		DefaultMutableTreeNode node;
  		
  		root = (DefaultMutableTreeNode)tree.getRoot();
  		Enumeration<DefaultMutableTreeNode> e = root.depthFirstEnumeration();
  		
  		while (e.hasMoreElements()){
  			node = e.nextElement();
  			if (value.equals( ((ItemType)(((UserObjectItemType)node.getUserObject()).getUserObject())).getValue() )){
  				return node;
  			}
  		}
  		return null;
  	}
  	
  	/**
  	 * returns the UserObject of a node whose resId attribute matches id
  	 */
  	public UserObjectItem getNodeObject(String id, DefaultTreeModel tree){
  		DefaultMutableTreeNode node = getNode(id, tree);
  		return (UserObjectItem)((UserObjectItem)(node.getUserObject()));
  	}
}
