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.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);
		}
	}

	protected ASTNode parent = null;
	protected String identifier = new String();
	protected 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;
	}

	@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 (child instanceof ASTNode) {
			return (ASTNode) child;
		}
		throw new ChildTypeUnmatchException(childDescriptor + " is not mapping to a ASTNode");
	}

	public void accept(ASTVisitor visitor) throws Exception {
		visitor.willVisit(this);
		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) {
						visitor.visit(child);
					}
				}
				else if(key instanceof ChildDescriptor) {
					visitor.visit(this.getChildByDescriptor((ChildDescriptor) key));
				}
			}
		}
		visitor.didVisit(this);
	}

	@Override
	public String toString() {
		return "<" + this.getClass().getSimpleName() + "> " + this.identifier;
	}

	public String toString(int level) {
		String str = "";
		for (int i = 0; i < level; i++) {
			str += "  ";
		}
		str += "<" + this.getClass().getSimpleName() + ">";
		if(this.identifier.length() > 0) str += " " + this.identifier;
		if (this.parent != null)
			str += " parent: " + this.parent.getClass().getSimpleName();
		str += "\n";
		return str;
	}
}

@@ -1729,16 +1729,86 @@
 (this);%0A
+%09%09logger.finer(%22Visiting %3C%22 + this.getClass().getSimpleName() + %22%3E%22);%0A
 %09%09if (vi
@@ -1828,16 +1828,16 @@
 his)) %7B%0A
-
 %09%09%09for (
@@ -1963,16 +1963,8 @@
 n = 
-%0A%09%09%09%09%09%09%09
 this
@@ -2061,27 +2061,28 @@
 %09%09%09%09
-visitor.visit(child
+child.accept(visitor
 );%0A%09
@@ -2144,30 +2144,16 @@
  %7B%0A%09%09%09%09%09
-visitor.visit(
 this.get
@@ -2192,16 +2192,31 @@
 or) key)
+.accept(visitor
 );%0A%09%09%09%09%7D
@@ -2296,22 +2296,41 @@
 g() %7B%0A%09%09
-return
+String str = %22%22;%0A%09%09str +=
  %22%3C%22 + t
@@ -2364,35 +2364,186 @@
 e() + %22%3E
- %22 + this.identifie
+%22;%0A%09%09if(this.identifier.length() %3E 0) str += %22 %22 + this.identifier;%0A%09%09if (this.parent != null)%0A%09%09%09str += %22 parent: %22 + this.parent.getClass().getSimpleName();%0A%09%09return st
 r;%0A%09%7D%0A%0A%09

Fix ASTNode.accept