/*******************************************************************************
 * 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 Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.jdt.internal.core.search.matching;

import java.io.IOException;

import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.core.search.SearchPattern;
import org.eclipse.jdt.internal.core.index.*;
import org.eclipse.jdt.internal.core.search.indexing.IIndexConstants;

public class MultiTypeDeclarationPattern extends JavaSearchPattern implements IIndexConstants {

public char[][] simpleNames;
public char[][] qualifications;

// set to CLASS_SUFFIX for only matching classes 
// set to INTERFACE_SUFFIX for only matching interfaces
// set to ENUM_SUFFIX for only matching enums
// set to ANNOTATION_TYPE_SUFFIX for only matching annotation types
// set to TYPE_SUFFIX for matching both classes and interfaces
public char typeSuffix;

protected static char[][] CATEGORIES = { TYPE_DECL };

public MultiTypeDeclarationPattern(
	char[][] qualifications,
	char[][] simpleNames,
	char typeSuffix,
	int matchRule) {

	this(matchRule);

	if (isCaseSensitive() || qualifications == null) {
		this.qualifications = qualifications;
	} else {
		int length = qualifications.length;
		this.qualifications = new char[length][];
		for (int i = 0; i < length; i++)
			this.qualifications[i] = CharOperation.toLowerCase(qualifications[i]);
	}
	if (simpleNames == null) {
		this.simpleNames = CharOperation.NO_CHAR_CHAR;
	} else if (isCaseSensitive()) {
		this.simpleNames = simpleNames;
	} else {
		int length = simpleNames.length;
		this.simpleNames = new char[length][];
		for (int i = 0; i < length; i++)
			this.simpleNames[i] = CharOperation.toLowerCase(simpleNames[i]);
	}
	this.typeSuffix = typeSuffix;

	((InternalSearchPattern)this).mustResolve = typeSuffix != TYPE_SUFFIX; // only used to report type declarations, not their positions
}
MultiTypeDeclarationPattern(int matchRule) {
	super(TYPE_DECL_PATTERN, matchRule);
}
public SearchPattern getBlankPattern() {
	return new QualifiedTypeDeclarationPattern(R_EXACT_MATCH | R_CASE_SENSITIVE);
}
public char[][] getIndexCategories() {
	return CATEGORIES;
}
public boolean matchesDecodedKey(SearchPattern decodedPattern) {
	QualifiedTypeDeclarationPattern pattern = (QualifiedTypeDeclarationPattern) decodedPattern;
	switch(this.typeSuffix) {
		case CLASS_SUFFIX :
			switch (pattern.typeSuffix) {
				case CLASS_SUFFIX :
				case CLASS_AND_INTERFACE_SUFFIX :
				case CLASS_AND_ENUM_SUFFIX :
					break;
				default:
					return false;
			}
			break;
		case INTERFACE_SUFFIX :
			switch (pattern.typeSuffix) {
				case INTERFACE_SUFFIX :
				case CLASS_AND_INTERFACE_SUFFIX :
					break;
				default:
					return false;
			}
			break;
		case ENUM_SUFFIX :
			switch (pattern.typeSuffix) {
				case ENUM_SUFFIX :
				case CLASS_AND_ENUM_SUFFIX :
					break;
				default:
					return false;
			}
			break;
		case ANNOTATION_TYPE_SUFFIX :
			if (this.typeSuffix != pattern.typeSuffix) return false;
			break;
		case CLASS_AND_INTERFACE_SUFFIX :
			switch (pattern.typeSuffix) {
				case CLASS_SUFFIX :
				case INTERFACE_SUFFIX :
				case CLASS_AND_INTERFACE_SUFFIX :
					break;
				default:
					return false;
			}
			break;
		case CLASS_AND_ENUM_SUFFIX :
			switch (pattern.typeSuffix) {
				case CLASS_SUFFIX :
				case ENUM_SUFFIX :
				case CLASS_AND_ENUM_SUFFIX :
					break;
				default:
					return false;
			}
			break;
	}

	if (this.qualifications != null) {
		int count = 0;
		int max = this.qualifications.length;
		for (; count < max; count++)
			if (matchesName(this.qualifications[count], pattern.qualification))
				break;
		if (count == max) return false;
	}

	int count = 0;
	int max = this.simpleNames.length;
	for (; count < max; count++)
		if (matchesName(this.simpleNames[count], pattern.simpleName))
			break;
	return count < max;
}
EntryResult[] queryIn(Index index) throws IOException {
	int count = -1;
	int numOfNames = this.simpleNames.length;
	EntryResult[][] allResults = numOfNames > 1 ? new EntryResult[numOfNames][] : null;
	for (int i = 0; i < numOfNames; i++) {
		char[] key = this.simpleNames[i];
		int matchRule = getMatchRule();

		switch(getMatchMode()) {
			case R_PREFIX_MATCH :
				// do a prefix query with the simpleName
				break;
			case R_EXACT_MATCH :
				matchRule = matchRule - R_EXACT_MATCH + R_PREFIX_MATCH;
				key = CharOperation.append(key, SEPARATOR);
				break; // do a prefix query with the simpleName
			case R_PATTERN_MATCH :
				if (key[key.length - 1] != '*')
					key = CharOperation.concat(key, ONE_STAR, SEPARATOR);
				break;
		}

		EntryResult[] entries = index.query(getIndexCategories(), key, matchRule); // match rule is irrelevant when the key is null
		if (entries != null) {
			if (allResults == null) return entries;
			allResults[++count] = entries;
		}
	}

	if (count == -1) return null;
	int total = 0;
	for (int i = 0; i <= count; i++)
		total += allResults[i].length;
	EntryResult[] allEntries = new EntryResult[total];
	int next = 0;
	for (int i = 0; i <= count; i++) {
		EntryResult[] entries = allResults[i];
		System.arraycopy(entries, 0, allEntries, next, entries.length);
		next += entries.length;
	}
	return allEntries;
}
protected StringBuffer print(StringBuffer output) {
	switch (this.typeSuffix){
		case CLASS_SUFFIX :
			output.append("MultiClassDeclarationPattern: "); //$NON-NLS-1$
			break;
		case CLASS_AND_INTERFACE_SUFFIX :
			output.append("MultiClassAndInterfaceDeclarationPattern: "); //$NON-NLS-1$
			break;
		case CLASS_AND_ENUM_SUFFIX :
			output.append("MultiClassAndEnumDeclarationPattern: "); //$NON-NLS-1$
			break;
		case INTERFACE_SUFFIX :
			output.append("MultiInterfaceDeclarationPattern: "); //$NON-NLS-1$
			break;
		case ENUM_SUFFIX :
			output.append("MultiEnumDeclarationPattern: "); //$NON-NLS-1$
			break;
		case ANNOTATION_TYPE_SUFFIX :
			output.append("MultiAnnotationTypeDeclarationPattern: "); //$NON-NLS-1$
			break;
		default :
			output.append("MultiTypeDeclarationPattern: "); //$NON-NLS-1$
			break;
	}
	if (qualifications != null) {
		output.append("qualifications: <"); //$NON-NLS-1$
		for (int i = 0; i < qualifications.length; i++){
			output.append(qualifications[i]);
			if (i < qualifications.length - 1)
				output.append(", "); //$NON-NLS-1$
		}
		output.append("> "); //$NON-NLS-1$
	}
	if (simpleNames != null) {
		output.append("simpleNames: <"); //$NON-NLS-1$
		for (int i = 0; i < simpleNames.length; i++){
			output.append(simpleNames[i]);
			if (i < simpleNames.length - 1)
				output.append(", "); //$NON-NLS-1$
		}
		output.append(">"); //$NON-NLS-1$
	}
	return super.print(output);
}
}
