package annotator.scanner;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.sun.source.tree.NewArrayTree;
import com.sun.source.tree.NewClassTree;
import com.sun.source.tree.Tree;
import com.sun.source.util.TreePath;

import com.sun.tools.javac.tree.JCTree;

import plume.Pair;

/**
 * NewScanner scans the source tree and determines the index of a given new,
 * where the i^th index corresponds to the i^th new, using 0-based indexing.
 */
public class NewScanner extends CommonScanner {
	private static boolean debug = false;

	static Map<Pair<TreePath,Tree>, Integer> cache = new HashMap<Pair<TreePath,Tree>, Integer>();

	/**
	 * Computes the index of the given new tree amongst all new trees
	 * inside its method, using 0-based indexing. The tree has to be
	 * either a NewClassTree or a NewArrayTree.  If the tree is not in
	 * a method, then the index is computed 
	 * 
	 * @param path
	 *            the path ending in the given cast tree
	 * @param tree
	 *            the cast tree to search for
	 * @return the index of the given cast tree
	 */
	public static int indexOfNewTree(TreePath origpath, Tree tree, String methodname) {
		debug("indexOfNewTree: " + origpath.getLeaf());

		Pair<TreePath,Tree> args = Pair.of(origpath, tree);
		if (cache.containsKey(args)) {
			return cache.get(args);
		}

		TreePath path = findCountingContext(origpath);
		if (path == null) {
			return -1;
		}
		Tree leaf = path.getLeaf();
		// Need better check for method decls, and also a check for
		// initializers.
		if (leaf instanceof JCTree.JCMethodDecl) {
			JCTree.JCMethodDecl md = (JCTree.JCMethodDecl) leaf;
			// Lazy (and wrong): just check the name, not the signature.
			String shortMethodname = methodname.substring(0, methodname.indexOf("("));
			if (! (md.name.toString().equals(shortMethodname))) {
				return -1;
			}
		}

		NewScanner lvts = new NewScanner(tree);
		lvts.scan(path, null);
		cache.put(args, lvts.index);
		return lvts.index;
	}
	
	private int index = -1;
	private boolean done = false;
	private Tree tree;

	private NewScanner(Tree tree) {
		this.index = -1;
		this.done = false;
		this.tree = tree;
	}

	@Override
	public Void visitNewClass(NewClassTree node, Void p) {
		if (!done) {
			index++;
		}
		if (tree == node) {
			done = true;
		}
		return super.visitNewClass(node, p);
	}

	@Override
	public Void visitNewArray(NewArrayTree node, Void p) {
		if (!done) {
			index++;
		}
		if (tree == node) {
			done = true;
		}
		return super.visitNewArray(node, p);
	}

	public static void debug(String s) {
		if (debug) {
			System.out.println(s);
		}
	}

	private static Map<String, List<Integer>> methodNameToNewOffsets =
		new HashMap<String, List<Integer>>();

	public static void addNewToMethod(String methodName, Integer offset) {
		debug("adding new to method: " + methodName + " offset: " + offset);
		List<Integer> offsetList = methodNameToNewOffsets.get(methodName);
		if (offsetList == null) {
			offsetList = new ArrayList<Integer>();
			methodNameToNewOffsets.put(methodName, offsetList);
		}
		offsetList.add(offset);
	}

	public static Integer getMethodNewIndex(String methodName, Integer offset) {
		List<Integer> offsetList = methodNameToNewOffsets.get(methodName);
		if (offsetList == null) {
			throw new RuntimeException("NewScanner.getMethodNewIndex() : "
					+ "did not find offsets for method: " + methodName);
		}

		Integer offsetIndex = offsetList.indexOf(offset);
		if (offsetIndex < 0) {
			throw new RuntimeException("NewScanner.getMethodNewIndex() : "
					+ "in method: " + methodName + " did not find offset: "
					+ offset);
		}

		return offsetIndex;
	}
}

@@ -273,17 +273,16 @@
 eePath;%0A
-%0A
 import c
@@ -926,22 +926,20 @@
 computed
- 
 %0A%09 *
- 
 %0A%09 * @pa
@@ -1176,33 +1176,20 @@
 tree
-, String methodname) %7B%0A%09%09
+) %7B%0A        
 debu
@@ -1444,443 +1444,8 @@
 %0A%09%09%7D
-%0A%09%09Tree leaf = path.getLeaf();%0A%09%09// Need better check for method decls, and also a check for%0A%09%09// initializers.%0A%09%09if (leaf instanceof JCTree.JCMethodDecl) %7B%0A%09%09%09JCTree.JCMethodDecl md = (JCTree.JCMethodDecl) leaf;%0A%09%09%09// Lazy (and wrong): just check the name, not the signature.%0A%09%09%09String shortMethodname = methodname.substring(0, methodname.indexOf(%22(%22));%0A%09%09%09if (! (md.name.toString().equals(shortMethodname))) %7B%0A%09%09%09%09return -1;%0A%09%09%09%7D%0A%09%09%7D
 %0A%0A%09%09
@@ -1540,16 +1540,17 @@
 index);%0A
+%0A
 %09%09return
@@ -1565,17 +1565,16 @@
 dex;%0A%09%7D%0A
-%09
 %0A%09privat

Remove method name hack.