package ca.uwaterloo.joos.ast;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;

import ca.uwaterloo.joos.Main;
import ca.uwaterloo.joos.ast.AST.ASTConstructException;
import ca.uwaterloo.joos.ast.descriptor.ChildDescriptor;
import ca.uwaterloo.joos.ast.descriptor.ChildListDescriptor;
import ca.uwaterloo.joos.ast.descriptor.Descriptor;
import ca.uwaterloo.joos.ast.visitor.ASTVisitor;

public abstract class ASTNode {
	protected static final Logger logger = Main.getLogger(ASTNode.class);

	@SuppressWarnings("serial")
	public static class ChildTypeUnmatchException extends ASTConstructException {
		public ChildTypeUnmatchException(String msg) {
			super(msg);
		}
	}

	private ASTNode parent = null;
	private String identifier = new String();
	private Map<Descriptor, Object> childrenList = new HashMap<Descriptor, Object>();

	public ASTNode(ASTNode parent) {
		this.parent = parent;
	}

	/**
	 * @return the parent
	 */
	public ASTNode getParent() {
		return parent;
	}

	/**
	 * @return the identifier
	 */
	public String getIdentifier() {
		return identifier;
	}
	
	protected void setIdentifier(String identifier) {
		this.identifier = identifier;
	}
	
	protected void addChild(Descriptor descriptor, Object value) {
		this.childrenList.put(descriptor, value);
	}

	@SuppressWarnings("unchecked")
	public List<ASTNode> getChildByDescriptor(ChildListDescriptor listDescriptor) throws ChildTypeUnmatchException {
		Object child = childrenList.get(listDescriptor);
		if (child == null || child instanceof List) {
			return (List<ASTNode>) child;
		}
		throw new ChildTypeUnmatchException(listDescriptor + " is not mapping to a List");
	}

	public ASTNode getChildByDescriptor(ChildDescriptor childDescriptor) throws ChildTypeUnmatchException {
		Object child = childrenList.get(childDescriptor);
		if (childDescriptor.getElementClass().isAssignableFrom(child.getClass())) {
			return (ASTNode) child;
		}
		throw new ChildTypeUnmatchException(childDescriptor + " is not mapping to a " + childDescriptor.getElementClass().getSimpleName());
	}

	public void accept(ASTVisitor visitor) throws Exception {
		visitor.willVisit(this);
		logger.finer("Visiting <" + this.getClass().getSimpleName() + ">");
		if (visitor.visit(this)) {
			for (Descriptor key : this.childrenList.keySet()) {
				if (key instanceof ChildListDescriptor) {
					List<ASTNode> children = this.getChildByDescriptor((ChildListDescriptor) key);
					for (ASTNode child : children) {
						child.accept(visitor);
					}
				}
				else if(key instanceof ChildDescriptor) {
					this.getChildByDescriptor((ChildDescriptor) key).accept(visitor);
				}
			}
		}
		visitor.didVisit(this);
	}

	@Override
	public String toString() {
		String str = "";
		str += "<" + this.getClass().getSimpleName() + ">";
		if(this.identifier.length() > 0) str += " " + this.identifier;
		if (this.parent != null)
			str += " parent: " + this.parent.getClass().getSimpleName();
		return str;
	}
}

@@ -379,32 +379,152 @@
 tor.Descriptor;%0A
+import ca.uwaterloo.joos.ast.descriptor.SimpleDescriptor;%0Aimport ca.uwaterloo.joos.ast.descriptor.SimpleListDescriptor;%0A
 import ca.uwater
@@ -2211,24 +2211,799 @@
 eName());%0A%09%7D
+%0A%09%0A%09@SuppressWarnings(%22unchecked%22)%0A%09public List%3CObject%3E getChildByDescriptor(SimpleListDescriptor listDescriptor) throws ChildTypeUnmatchException %7B%0A%09%09Object child = childrenList.get(listDescriptor);%0A%09%09if (child == null %7C%7C child instanceof List) %7B%0A%09%09%09return (List%3CObject%3E) child;%0A%09%09%7D%0A%09%09throw new ChildTypeUnmatchException(listDescriptor + %22 is not mapping to a List%22);%0A%09%7D%0A%09%0A%09public Object getChildByDescriptor(SimpleDescriptor childDescriptor) throws ChildTypeUnmatchException %7B%0A%09%09Object child = childrenList.get(childDescriptor);%0A%09%09if (childDescriptor.getElementClass().isAssignableFrom(child.getClass())) %7B%0A%09%09%09return (Object) child;%0A%09%09%7D%0A%09%09throw new ChildTypeUnmatchException(childDescriptor + %22 is not mapping to a %22 + childDescriptor.getElementClass().getSimpleName());%0A%09%7D
 %0A%0A%09public vo

Add getChildByDescriptor for Simple/SimpleList Descriptor