/*******************************************************************************
 * Copyright (c) 2000, 2003 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials 
 * are made available under the terms of the Common Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/cpl-v10.html
 * 
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.jdt.internal.debug.core.hcr;

 
import java.util.Stack;

import org.eclipse.jdt.internal.compiler.SourceElementRequestorAdapter;
import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;

class JavaParseTreeBuilder extends SourceElementRequestorAdapter implements ICompilationUnit {
	
	private static final boolean SHOW_COMPILATIONUNIT= true;

	private char[] fBuffer;
	private JavaNode fImportContainer;
	private Stack fStack= new Stack();
	
	/**
	 * Parsing is performed on the given buffer and the resulting tree
	 * (if any) hangs below the given root.
	 */
	JavaParseTreeBuilder(JavaNode root, char[] buffer) {
		fImportContainer= null;
		fStack.clear();
		fStack.push(root);
		fBuffer= buffer;
	}
			
	//---- ICompilationUnit
	/* (non Java doc)
	 * @see ICompilationUnit#getContents
	 */
	public char[] getContents() {
		return fBuffer;
	}
	
	/* (non Java doc)
	 * @see ICompilationUnit#getFileName
	 */
	public char[] getFileName() {
		return new char[0];
	}
	
	/* (non Java doc)
	 * @see ICompilationUnit#getMainTypeName
	 */
	public char[] getMainTypeName() {
		return new char[0];
	}
	
	/* (non Java doc)
	 * @see ICompilationUnit#getMainTypeName
	 */
	public char[][] getPackageName() {
		return null;
	}
	
	//---- ISourceElementRequestor
	
	public void enterCompilationUnit() {
		if (SHOW_COMPILATIONUNIT)
			push(JavaNode.CU, null, 0);
	}
	
	public void exitCompilationUnit(int declarationEnd) {
		if (SHOW_COMPILATIONUNIT)
			pop(declarationEnd);
	}
	
	public void acceptPackage(int declarationStart, int declarationEnd, char[] p3) {
		push(JavaNode.PACKAGE, null, declarationStart);
		pop(declarationEnd);
	}
	
	public void acceptImport(int declarationStart, int declarationEnd, char[] name, boolean onDemand, int modifiers) {
		int length= declarationEnd-declarationStart+1;
		if (fImportContainer == null)
			fImportContainer= new JavaNode(getCurrentContainer(), JavaNode.IMPORT_CONTAINER, null, declarationStart, length);
		String nm= new String(name);
		if (onDemand)
			nm+= ".*"; //$NON-NLS-1$
		new JavaNode(fImportContainer, JavaNode.IMPORT, nm, declarationStart, length);
		fImportContainer.setLength(declarationEnd-fImportContainer.getStart()+1);
	}
	
	public void enterClass(int declarationStart, int p2, char[] name, int p4, int p5, char[] p6, char[][] p7) {
		push(JavaNode.CLASS, new String(name), declarationStart);
	}
	
	public void exitClass(int declarationEnd) {
		pop(declarationEnd);
	}

	public void enterInterface(int declarationStart, int p2, char[] name, int p4, int p5, char[][] p6) {
		push(JavaNode.INTERFACE, new String(name), declarationStart);
	}
	
	public void exitInterface(int declarationEnd) {
		pop(declarationEnd);
	}
	
	public void enterInitializer(int declarationSourceStart, int modifiers) {
		push(JavaNode.INIT, getCurrentContainer().getInitializerCount(), declarationSourceStart);
	}
	
	public void enterConstructor(int declarationStart, int p2, char[] name, int p4, int p5, char[][] parameterTypes, char[][] p7, char[][] p8) {
		push(JavaNode.CONSTRUCTOR, getSignature(name, parameterTypes), declarationStart);
	}
	
	public void exitConstructor(int declarationEnd) {
		pop(declarationEnd);
	}
	
	public void enterMethod(int declarationStart, int p2, char[] p3, char[] name, int p5, int p6, char[][] parameterTypes, char[][] p8, char[][] p9){
		push(JavaNode.METHOD, getSignature(name, parameterTypes), declarationStart);
	}
	
	public void exitMethod(int declarationEnd) {
		pop(declarationEnd);
	}
	
	public void enterField(int declarationStart, int p2, char[] p3, char[] name, int p5, int p6) {
		push(JavaNode.FIELD, new String(name), declarationStart);
	}
	
	public void exitField(int initializationStart, int declarationEnd, int declarationSourceEnd) {
		pop(declarationEnd);
	}

	private JavaNode getCurrentContainer() {
		return (JavaNode) fStack.peek();
	}
	
	/**
	 * Adds a new JavaNode with the given type and name to the current container.
	 */
	private void push(int type, String name, int declarationStart) {
						
		while (declarationStart > 0) {
			char c= fBuffer[declarationStart-1];
			if (c != ' ' && c != '\t')
				break;
			declarationStart--;
		}
					
		fStack.push(new JavaNode(getCurrentContainer(), type, name, declarationStart, 0));
	}
	
	/**
	 * Closes the current Java node by setting its end position
	 * and pops it off the stack.
	 */
	private void pop(int declarationEnd) {
		JavaNode current= getCurrentContainer();
		current.setLength(declarationEnd - current.getStart() + 1);
		fStack.pop();
	}
	
	/**
	 * Builds a signature string from the given name and parameter types.
	 */
	public String getSignature(char[] name, char[][] parameterTypes) {
		StringBuffer buffer= new StringBuffer();
		buffer.append(name);
		buffer.append('(');
		if (parameterTypes != null) {
			for (int p= 0; p < parameterTypes.length; p++) {
				String parameterType= new String(parameterTypes[p]);
				
				// PR 1GF9WH7: ITPJUI:WINNT - Cannot replace main from local history
				// we only use the last component of a type name
				int pos= parameterType.lastIndexOf('.');
				if (pos >= 0)
					parameterType= parameterType.substring(pos+1);
				// end fix
				
				buffer.append(parameterType);
				if (p < parameterTypes.length-1)
					buffer.append(", "); //$NON-NLS-1$
			}
		}
		buffer.append(')');
		return buffer.toString();
	}
	
	/**
	 * @see org.eclipse.jdt.internal.compiler.ISourceElementRequestor#exitInitializer(int)
	 */
	public void exitInitializer(int declarationEnd) {
		pop(declarationEnd);
	}

}
