package uk.co.badgersinfoil.metaas.impl;

import java.util.Iterator;
import java.util.List;

import uk.co.badgersinfoil.metaas.dom.ASBlock;
import uk.co.badgersinfoil.metaas.dom.ASBreakStatement;
import uk.co.badgersinfoil.metaas.dom.ASCatchClause;
import uk.co.badgersinfoil.metaas.dom.ASContinueStatement;
import uk.co.badgersinfoil.metaas.dom.ASDeclarationStatement;
import uk.co.badgersinfoil.metaas.dom.ASDefaultXMLNamespaceStatement;
import uk.co.badgersinfoil.metaas.dom.ASDoWhileStatement;
import uk.co.badgersinfoil.metaas.dom.ASExpressionStatement;
import uk.co.badgersinfoil.metaas.dom.ASFinallyClause;
import uk.co.badgersinfoil.metaas.dom.ASForEachInStatement;
import uk.co.badgersinfoil.metaas.dom.ASForInStatement;
import uk.co.badgersinfoil.metaas.dom.ASForStatement;
import uk.co.badgersinfoil.metaas.dom.ASIfStatement;
import uk.co.badgersinfoil.metaas.dom.ASMethod;
import uk.co.badgersinfoil.metaas.dom.ASReturnStatement;
import uk.co.badgersinfoil.metaas.dom.ASSuperStatement;
import uk.co.badgersinfoil.metaas.dom.ASSwitchCase;
import uk.co.badgersinfoil.metaas.dom.ASSwitchDefault;
import uk.co.badgersinfoil.metaas.dom.ASSwitchStatement;
import uk.co.badgersinfoil.metaas.dom.ASThrowStatement;
import uk.co.badgersinfoil.metaas.dom.ASTryStatement;
import uk.co.badgersinfoil.metaas.dom.ASVarDeclarationFragment;
import uk.co.badgersinfoil.metaas.dom.ASWhileStatement;
import uk.co.badgersinfoil.metaas.dom.ASWithStatement;
import uk.co.badgersinfoil.metaas.dom.Statement;
import uk.co.badgersinfoil.metaas.dom.SwitchLabel;

/**
 * @author rflament
 * 
 */
public final class ASMethodWalker {

	private ASMethodVisitor methodVisitor;

	public ASMethodWalker(ASMethodVisitor visitor) {
		methodVisitor = visitor;
	}

	public void walk(ASMethod method) throws Exception {
		methodVisitor.visit(method);

		List list = method.getStatementList();
		walk(list);

	}

	private void walk(List statements) throws Exception {
		for (Iterator iterator = statements.iterator(); iterator.hasNext();) {
			Statement statement = (Statement) iterator.next();
			walk(statement);
		}
	}

	public void walk(ASReturnStatement returnStatement) {
		methodVisitor.visit(returnStatement);
	}

	public void walk(ASIfStatement ifStatement) throws Exception {
		methodVisitor.visit(ifStatement);

		if (ifStatement.getThenStatement() != null) {
			walk(ifStatement.getThenStatement());
		}
		if (ifStatement.getElseStatement() != null) {
			walk(ifStatement.getElseStatement());
		}
	}

	public void walk(ASForStatement forStatement) throws Exception {
		methodVisitor.visit(forStatement);

		walk(forStatement.getStatementList());

	}

	public void walk(ASDeclarationStatement declarationStatement) {
		methodVisitor.visit(declarationStatement);
		List vars = declarationStatement.getVars();
		
		for (Iterator iterator = vars.iterator(); iterator.hasNext();) {
			ASVarDeclarationFragment declarationFragment = (ASVarDeclarationFragment) iterator.next();
			methodVisitor.visit(declarationFragment);
		}
		
	}

	public void walk(ASExpressionStatement expressionStatement) {
		methodVisitor.visit(expressionStatement);
	}

	public void walk(ASBlock block) throws Exception {
		methodVisitor.visit(block);
		walk(block.getStatementList());

	}

	public void walk(ASBreakStatement breakStatement) {
		methodVisitor.visit(breakStatement);
	}

	public void walk(ASContinueStatement continueStatement) {
		methodVisitor.visit(continueStatement);
	}

	public void walk(ASDefaultXMLNamespaceStatement defaultXMLNamespaceStatement) {
		methodVisitor.visit(defaultXMLNamespaceStatement);
	}

	public void walk(ASSuperStatement superStatement) {
		methodVisitor.visit(superStatement);
	}

	public void walk(ASThrowStatement throwStatement) {
		methodVisitor.visit(throwStatement);
	}

	public void walk(ASWithStatement withStatement) throws Exception {
		methodVisitor.visit(withStatement);
		walk(withStatement.getStatementList());
	}

	public void walk(ASWhileStatement whileStatement) throws Exception {
		methodVisitor.visit(whileStatement);

		walk(whileStatement.getStatementList());
	}

	public void walk(ASTryStatement tryStatement) throws Exception {
		methodVisitor.visit(tryStatement);

		walk(tryStatement.getStatementList());

		List catchClauses = tryStatement.getCatchClauses();
		for (Iterator iterator = catchClauses.iterator(); iterator.hasNext();) {
			ASCatchClause catchClause = (ASCatchClause) iterator.next();
			methodVisitor.visit(catchClause);
			walk(catchClause.getStatementList());
		}

		if (tryStatement.getFinallyClause() != null) {
			ASFinallyClause finallyClause = (ASFinallyClause) tryStatement.getFinallyClause();
			methodVisitor.visit(finallyClause);
			walk(finallyClause.getStatementList());
		}

	}

	public void walk(ASDoWhileStatement doWhileStatement) throws Exception {
		methodVisitor.visit(doWhileStatement);

		walk(doWhileStatement.getStatementList());
	}

	public void walk(ASForEachInStatement forEachInStatement) throws Exception {
		methodVisitor.visit(forEachInStatement);

		walk(forEachInStatement.getStatementList());
	}

	public void walk(ASForInStatement forInStatement) throws Exception {
		methodVisitor.visit(forInStatement);

		walk(forInStatement.getStatementList());
	}

	public void walk(ASSwitchStatement switchStatement) throws Exception {
		methodVisitor.visit(switchStatement);

		List labels = switchStatement.getLabels();
		for (Iterator iterator = labels.iterator(); iterator.hasNext();) {
			SwitchLabel switchLabel = (SwitchLabel) iterator.next();

			if (switchLabel instanceof ASSwitchDefault) {
				ASSwitchDefault switchDefault = (ASSwitchDefault) switchLabel;
				methodVisitor.visit(switchDefault);

			} else if (switchLabel instanceof ASSwitchCase) {
				ASSwitchCase switchCase = (ASSwitchCase) switchLabel;
				methodVisitor.visit(switchCase);
			}
			walk(switchLabel.getStatementList());
		}

	}

	public void walk(Statement statement) throws Exception {
		if (statement instanceof ASIfStatement) {
			walk((ASIfStatement) statement);
		} else if (statement instanceof ASReturnStatement) {
			walk((ASReturnStatement) statement);
		} else if (statement instanceof ASForStatement) {
			walk((ASForStatement) statement);
		} else if (statement instanceof ASDeclarationStatement) {
			walk((ASDeclarationStatement) statement);
		} else if (statement instanceof ASExpressionStatement) {
			walk((ASExpressionStatement) statement);
		} else if (statement instanceof ASBlock) {
			walk((ASBlock) statement);
		} else if (statement instanceof ASBreakStatement) {
			walk((ASBreakStatement) statement);
		} else if (statement instanceof ASContinueStatement) {
			walk((ASContinueStatement) statement);
		} else if (statement instanceof ASDefaultXMLNamespaceStatement) {
			walk((ASDefaultXMLNamespaceStatement) statement);
		} else if (statement instanceof ASDoWhileStatement) {
			walk((ASDoWhileStatement) statement);
		} else if (statement instanceof ASForEachInStatement) {
			walk((ASForEachInStatement) statement);
		} else if (statement instanceof ASForInStatement) {
			walk((ASForInStatement) statement);
		} else if (statement instanceof ASSuperStatement) {
			walk((ASSuperStatement) statement);
		} else if (statement instanceof ASSwitchStatement) {
			walk((ASSwitchStatement) statement);
		} else if (statement instanceof ASThrowStatement) {
			walk((ASThrowStatement) statement);
		} else if (statement instanceof ASTryStatement) {
			walk((ASTryStatement) statement);
		} else if (statement instanceof ASWhileStatement) {
			walk((ASWhileStatement) statement);
		} else if (statement instanceof ASWithStatement) {
			walk((ASWithStatement) statement);
		} else
			throw new Exception("Unknown statement : " + statement.getClass());

	}

}
