/*******************************************************************************
 * 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 net.sourceforge.phpdt.internal.compiler.ast;

import net.sourceforge.phpdt.internal.compiler.ASTVisitor;
import net.sourceforge.phpdt.internal.compiler.flow.FlowContext;
import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo;
import net.sourceforge.phpdt.internal.compiler.impl.Constant;
import net.sourceforge.phpdt.internal.compiler.lookup.ArrayBinding;
import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope;
import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;

public class ArrayReference extends Reference {

	public Expression receiver;

	public Expression position;

	public ArrayReference(Expression rec, Expression pos) {
		this.receiver = rec;
		this.position = pos;
		sourceStart = rec.sourceStart;
	}

	public FlowInfo analyseAssignment(BlockScope currentScope,
			FlowContext flowContext, FlowInfo flowInfo, Assignment assignment,
			boolean compoundAssignment) {

		if (assignment.expression == null) {
			return analyseCode(currentScope, flowContext, flowInfo)
					.unconditionalInits();
		} else {
			return assignment.expression.analyseCode(
					currentScope,
					flowContext,
					analyseCode(currentScope, flowContext, flowInfo)
							.unconditionalInits()).unconditionalInits();
		}
	}

	public FlowInfo analyseCode(BlockScope currentScope,
			FlowContext flowContext, FlowInfo flowInfo) {

		return position.analyseCode(currentScope, flowContext, receiver
				.analyseCode(currentScope, flowContext, flowInfo));
	}

	// public void generateAssignment(
	// BlockScope currentScope,
	// CodeStream codeStream,
	// Assignment assignment,
	// boolean valueRequired) {
	//
	// receiver.generateCode(currentScope, codeStream, true);
	// position.generateCode(currentScope, codeStream, true);
	// assignment.expression.generateCode(currentScope, codeStream, true);
	// codeStream.arrayAtPut(this.resolvedType.id, valueRequired);
	// if (valueRequired) {
	// codeStream.generateImplicitConversion(assignment.implicitConversion);
	// }
	// }

	/**
	 * Code generation for a array reference
	 */
	// public void generateCode(
	// BlockScope currentScope,
	// CodeStream codeStream,
	// boolean valueRequired) {
	//
	// int pc = codeStream.position;
	// receiver.generateCode(currentScope, codeStream, true);
	// position.generateCode(currentScope, codeStream, true);
	// codeStream.arrayAt(this.resolvedType.id);
	// // Generating code for the potential runtime type checking
	// if (valueRequired) {
	// codeStream.generateImplicitConversion(implicitConversion);
	// } else {
	// if (this.resolvedType == LongBinding
	// || this.resolvedType == DoubleBinding) {
	// codeStream.pop2();
	// } else {
	// codeStream.pop();
	// }
	// }
	// codeStream.recordPositionsFrom(pc, this.sourceStart);
	// }
	//
	// public void generateCompoundAssignment(
	// BlockScope currentScope,
	// CodeStream codeStream,
	// Expression expression,
	// int operator,
	// int assignmentImplicitConversion,
	// boolean valueRequired) {
	//
	// receiver.generateCode(currentScope, codeStream, true);
	// position.generateCode(currentScope, codeStream, true);
	// codeStream.dup2();
	// codeStream.arrayAt(this.resolvedType.id);
	// int operationTypeID;
	// if ((operationTypeID = implicitConversion >> 4) == T_String) {
	// codeStream.generateStringAppend(currentScope, null, expression);
	// } else {
	// // promote the array reference to the suitable operation type
	// codeStream.generateImplicitConversion(implicitConversion);
	// // generate the increment value (will by itself be promoted to the
	// operation value)
	// if (expression == IntLiteral.One) { // prefix operation
	// codeStream.generateConstant(expression.constant, implicitConversion);
	// } else {
	// expression.generateCode(currentScope, codeStream, true);
	// }
	// // perform the operation
	// codeStream.sendOperator(operator, operationTypeID);
	// // cast the value back to the array reference type
	// codeStream.generateImplicitConversion(assignmentImplicitConversion);
	// }
	// codeStream.arrayAtPut(this.resolvedType.id, valueRequired);
	// }
	//
	// public void generatePostIncrement(
	// BlockScope currentScope,
	// CodeStream codeStream,
	// CompoundAssignment postIncrement,
	// boolean valueRequired) {
	//
	// receiver.generateCode(currentScope, codeStream, true);
	// position.generateCode(currentScope, codeStream, true);
	// codeStream.dup2();
	// codeStream.arrayAt(this.resolvedType.id);
	// if (valueRequired) {
	// if ((this.resolvedType == LongBinding)
	// || (this.resolvedType == DoubleBinding)) {
	// codeStream.dup2_x2();
	// } else {
	// codeStream.dup_x2();
	// }
	// }
	// codeStream.generateConstant(
	// postIncrement.expression.constant,
	// implicitConversion);
	// codeStream.sendOperator(postIncrement.operator, this.resolvedType.id);
	// codeStream.generateImplicitConversion(
	// postIncrement.assignmentImplicitConversion);
	// codeStream.arrayAtPut(this.resolvedType.id, false);
	// }
	public StringBuffer printExpression(int indent, StringBuffer output) {

		receiver.printExpression(0, output).append('[');
		return position.printExpression(0, output).append(']');
	}

	public TypeBinding resolveType(BlockScope scope) {

		constant = Constant.NotAConstant;
		TypeBinding arrayType = receiver.resolveType(scope);
		if (arrayType != null) {
			if (arrayType.isArrayType()) {
				this.resolvedType = ((ArrayBinding) arrayType)
						.elementsType(scope);
			} else {
				scope.problemReporter().referenceMustBeArrayTypeAt(arrayType,
						this);
			}
		}
		TypeBinding positionType = position.resolveTypeExpecting(scope,
				IntBinding);
		if (positionType != null) {
			position.implicitWidening(IntBinding, positionType);
		}
		return this.resolvedType;
	}

	public String toStringExpression() {

		return receiver.toStringExpression() + "[" //$NON-NLS-1$
				+ position.toStringExpression() + "]"; //$NON-NLS-1$
	}

	public void traverse(ASTVisitor visitor, BlockScope scope) {

		if (visitor.visit(this, scope)) {
			receiver.traverse(visitor, scope);
			position.traverse(visitor, scope);
		}
		visitor.endVisit(this, scope);
	}
}
