/*******************************************************************************
 * Copyright (c) 2000, 2004 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.wst.jsdt.internal.compiler.ast;

import org.eclipse.wst.jsdt.internal.compiler.ASTVisitor;
import org.eclipse.wst.jsdt.internal.compiler.codegen.*;
import org.eclipse.wst.jsdt.internal.compiler.flow.*;
import org.eclipse.wst.jsdt.internal.compiler.lookup.*;

public class Block extends Statement {
	
	public Statement[] statements;
	public int explicitDeclarations;
	// the number of explicit declaration , used to create scope
	public BlockScope scope;
	
	public Block(int explicitDeclarations) {
		this.explicitDeclarations = explicitDeclarations;
	}
	
	public FlowInfo analyseCode(
		BlockScope currentScope,
		FlowContext flowContext,
		FlowInfo flowInfo) {

		// empty block
		if (statements == null)	return flowInfo;
		boolean didAlreadyComplain = false;
		for (int i = 0, max = statements.length; i < max; i++) {
			Statement stat = statements[i];
			if (!stat.complainIfUnreachable(flowInfo, scope, didAlreadyComplain)) {
				flowInfo = stat.analyseCode(scope, flowContext, flowInfo);
			} else {
				didAlreadyComplain = true;
			}
		}
		return flowInfo;
	}
	/**
	 * Code generation for a block
	 */
	public void generateCode(BlockScope currentScope, CodeStream codeStream) {

		if ((bits & IsReachableMASK) == 0) {
			return;
		}
		int pc = codeStream.position;
		if (statements != null) {
			for (int i = 0, max = statements.length; i < max; i++) {
				statements[i].generateCode(scope, codeStream);
			}
		} // for local variable debug attributes
		if (scope != currentScope) { // was really associated with its own scope
			codeStream.exitUserScope(scope);
		}
		codeStream.recordPositionsFrom(pc, this.sourceStart);
	}

	public boolean isEmptyBlock() {

		return statements == null;
	}

	public StringBuffer printBody(int indent, StringBuffer output) {

		if (this.statements == null) return output;
		for (int i = 0; i < statements.length; i++) {
			statements[i].printStatement(indent + 1, output);
			output.append('\n'); 
		}
		return output;
	}

	public StringBuffer printStatement(int indent, StringBuffer output) {

		printIndent(indent, output);
		output.append("{\n"); //$NON-NLS-1$
		printBody(indent, output);
		return printIndent(indent, output).append('}');
	}

	public void resolve(BlockScope upperScope) {

		if ((this.bits & UndocumentedEmptyBlockMASK) != 0) {
			upperScope.problemReporter().undocumentedEmptyBlock(this.sourceStart, this.sourceEnd);
		}
		if (statements != null) {
			scope =
				explicitDeclarations == 0
					? upperScope
					: new BlockScope(upperScope, explicitDeclarations);
			for (int i = 0, length = statements.length; i < length; i++) {
				statements[i].resolve(scope);
			}
		}
	}

	public void resolveUsing(BlockScope givenScope) {

		if ((this.bits & UndocumentedEmptyBlockMASK) != 0) {
			givenScope.problemReporter().undocumentedEmptyBlock(this.sourceStart, this.sourceEnd);
		}
		// this optimized resolve(...) is sent only on none empty blocks
		scope = givenScope;
		if (statements != null) {
			for (int i = 0, length = statements.length; i < length; i++) {
				statements[i].resolve(scope);
			}
		}
	}

	public void traverse(
		ASTVisitor visitor,
		BlockScope blockScope) {

		if (visitor.visit(this, blockScope)) {
			if (statements != null) {
				for (int i = 0, length = statements.length; i < length; i++)
					statements[i].traverse(visitor, scope);
			}
		}
		visitor.endVisit(this, blockScope);
	}
	
	/**
	 * Dispatch the call on its last statement.
	 */
	public void branchChainTo(Label label) {
		 if (this.statements != null) {
		 	this.statements[statements.length - 1].branchChainTo(label);
		 }
	}
	
}
