/*******************************************************************************
 * 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.jdt.internal.compiler.problem;

import org.eclipse.jdt.core.compiler.IProblem;
import org.eclipse.jdt.internal.compiler.CompilationResult;
import org.eclipse.jdt.internal.compiler.IErrorHandlingPolicy;
import org.eclipse.jdt.internal.compiler.IProblemFactory;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.compiler.impl.ReferenceContext;

/*
 * Compiler error handler, responsible to determine whether
 * a problem is actually a warning or an error; also will
 * decide whether the compilation task can be processed further or not.
 *
 * Behavior : will request its current policy if need to stop on
 *	first error, and if should proceed (persist) with problems.
 */

public class ProblemHandler implements ProblemSeverities {

	public final static String[] NoArgument = new String[0];
	
	final public IErrorHandlingPolicy policy;
	public final IProblemFactory problemFactory;
	public final CompilerOptions options;
/*
 * Problem handler can be supplied with a policy to specify
 * its behavior in error handling. Also see static methods for
 * built-in policies.
 *
 */
public ProblemHandler(IErrorHandlingPolicy policy, CompilerOptions options, IProblemFactory problemFactory) {
	this.policy = policy;
	this.problemFactory = problemFactory;
	this.options = options;
}
/*
 * Given the current configuration, answers which category the problem
 * falls into:
 *		Error | Warning | Ignore
 */
public int computeSeverity(int problemId){
	
	return Error; // by default all problems are errors
}
public IProblem createProblem(
	char[] fileName, 
	int problemId, 
	String[] problemArguments, 
	String[] messageArguments,
	int severity, 
	int problemStartPosition, 
	int problemEndPosition, 
	int lineNumber) {

	return this.problemFactory.createProblem(
		fileName, 
		problemId, 
		problemArguments, 
		messageArguments,
		severity, 
		problemStartPosition, 
		problemEndPosition, 
		lineNumber); 
}
public void handle(
	int problemId, 
	String[] problemArguments, 
	String[] messageArguments,
	int severity, 
	int problemStartPosition, 
	int problemEndPosition, 
	ReferenceContext referenceContext, 
	CompilationResult unitResult) {

	if (severity == Ignore)
		return;

	// if no reference context, we need to abort from the current compilation process
	if (referenceContext == null) {
		if ((severity & Error) != 0) { // non reportable error is fatal
			IProblem problem = this.createProblem(null, 	problemId, 	problemArguments, messageArguments, severity, 0, 0, 0);			
			throw new AbortCompilation(null, problem);
		} else {
			return; // ignore non reportable warning
		}
	}

	IProblem problem = 
		this.createProblem(
			unitResult.getFileName(), 
			problemId, 
			problemArguments, 
			messageArguments,
			severity, 
			problemStartPosition, 
			problemEndPosition, 
			problemStartPosition >= 0
				? searchLineNumber(unitResult.lineSeparatorPositions, problemStartPosition)
				: 0);
	if (problem == null) return; // problem couldn't be created, ignore
	
	switch (severity & Error) {
		case Error :
			this.record(problem, unitResult, referenceContext);
			referenceContext.tagAsHavingErrors();

			// should abort ?
			int abortLevel;
			if ((abortLevel = 
				(this.policy.stopOnFirstError() ? AbortCompilation : severity & Abort)) != 0) {

				referenceContext.abort(abortLevel, problem);
			}
			break;
		case Warning :
			this.record(problem, unitResult, referenceContext);
			break;
	}
}
/**
 * Standard problem handling API, the actual severity (warning/error/ignore) is deducted
 * from the problem ID and the current compiler options.
 */
public void handle(
	int problemId, 
	String[] problemArguments, 
	String[] messageArguments,
	int problemStartPosition, 
	int problemEndPosition, 
	ReferenceContext referenceContext, 
	CompilationResult unitResult) {

	this.handle(
		problemId,
		problemArguments,
		messageArguments,
		this.computeSeverity(problemId), // severity inferred using the ID
		problemStartPosition,
		problemEndPosition,
		referenceContext,
		unitResult);
}
public void record(IProblem problem, CompilationResult unitResult, ReferenceContext referenceContext) {
	unitResult.record(problem, referenceContext);
}
/**
 * Search the line number corresponding to a specific position
 */
public static final int searchLineNumber(int[] startLineIndexes, int position) {
	if (startLineIndexes == null)
		return 1;
	int length = startLineIndexes.length;
	if (length == 0)
		return 1;
	int g = 0, d = length - 1;
	int m = 0;
	while (g <= d) {
		m = (g + d) /2;
		if (position < startLineIndexes[m]) {
			d = m-1;
		} else if (position > startLineIndexes[m]) {
			g = m+1;
		} else {
			return m + 1;
		}
	}
	if (position < startLineIndexes[m]) {
		return m+1;
	}
	return m+2;
}
}
