/*******************************************************************************
 * Copyright (c) 2004, 2022 IBM Corporation and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.jdt.core.tests.model;

import java.util.Arrays;
import java.util.Comparator;
import java.util.function.Predicate;

import org.eclipse.jdt.core.CompletionContext;
import org.eclipse.jdt.core.CompletionProposal;
import org.eclipse.jdt.core.CompletionRequestor;
import org.eclipse.jdt.core.Flags;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.Signature;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.core.compiler.IProblem;
import org.eclipse.jdt.internal.codeassist.InternalCompletionContext;
import org.eclipse.jdt.internal.codeassist.impl.RestrictedIdentifiers;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.util.ObjectVector;
import org.eclipse.jdt.internal.core.JavaElement;

@SuppressWarnings({"rawtypes", "unchecked"})
public class CompletionTestsRequestor2 extends CompletionRequestor {
	private final char[] NULL_LITERAL = "null".toCharArray();//$NON-NLS-1$

	private CompletionContext context;
	public int proposalsPtr = -1;
	private final static int PROPOSALS_INCREMENT = 10;
	private CompletionProposal[] proposals = new CompletionProposal[PROPOSALS_INCREMENT];
	private IProblem problem;

	private final boolean showParameterNames;
	private final boolean showUniqueKeys;
	private final boolean showPositions;
	private final boolean showTokenPositions;
	private final boolean shortContext;
	private final boolean showMissingTypes;
	private final boolean showModifiers;

	private boolean computeVisibleElements;
	private boolean computeEnclosingElement;
	private String assignableType;

	public boolean debug = false;

	private Predicate<CompletionProposal> proposalFilter = x -> true;
	private Predicate<String> typeProposalFilter = x -> false;

	public CompletionTestsRequestor2() {
		this(false, false);
	}
	public CompletionTestsRequestor2(boolean showParamNames) {
		this(showParamNames, false, false);
	}
	public CompletionTestsRequestor2(boolean showParamNames, boolean showUniqueKeys) {
		this(showParamNames, showUniqueKeys, false);
	}
	public CompletionTestsRequestor2(boolean showParamNames, boolean showUniqueKeys, boolean showPositions) {
		this(showParamNames, showUniqueKeys, showPositions, true, false);
	}

	public CompletionTestsRequestor2(boolean showParamNames, boolean showUniqueKeys, boolean showPositions, boolean shortContext) {
		this(showParamNames, showUniqueKeys, showPositions, shortContext, false);
	}
	public CompletionTestsRequestor2(boolean showParamNames, boolean showUniqueKeys, boolean showPositions, boolean shortContext, boolean showMissingTypes) {
		this(showParamNames, showUniqueKeys, showPositions, shortContext, showMissingTypes, false);
	}
	public CompletionTestsRequestor2(boolean showParamNames, boolean showUniqueKeys, boolean showPositions, boolean shortContext, boolean showMissingTypes, boolean showTokenPositions) {
		this(false, showParamNames, showUniqueKeys, showPositions, shortContext, showMissingTypes, showTokenPositions, false);
	}
	public CompletionTestsRequestor2(
			boolean ignoreAll,
			boolean showParamNames,
			boolean showUniqueKeys,
			boolean showPositions,
			boolean shortContext,
			boolean showMissingTypes,
			boolean showTokenPositions,
			boolean showModifiers) {
		super(ignoreAll);
		this.showParameterNames = showParamNames;
		this.showUniqueKeys = showUniqueKeys;
		this.showPositions = showPositions;
		this.showTokenPositions =  showTokenPositions;
		this.shortContext = shortContext;
		this.showMissingTypes = showMissingTypes;
		this.showModifiers = showModifiers;
	}
	public void acceptContext(CompletionContext cc) {
		this.context = cc;
	}
	public void accept(CompletionProposal proposal) {
		if (!this.proposalFilter.test(proposal))
			return;

		int length = this.proposals.length;
		if (++this.proposalsPtr== length) {
			System.arraycopy(this.proposals, 0, this.proposals = new CompletionProposal[length+PROPOSALS_INCREMENT], 0, length);
		}
		this.proposals[this.proposalsPtr] = proposal;
	}

	@Override
	public boolean isIgnored(char[] typeName) {
		if (this.typeProposalFilter != null) {
			return this.typeProposalFilter.test(new String(typeName));
		}

		return super.isIgnored(typeName);
	}

	public void allowAllRequiredProposals() {
		for (int i = CompletionProposal.ANONYMOUS_CLASS_DECLARATION; i <= CompletionProposal.ANONYMOUS_CLASS_CONSTRUCTOR_INVOCATION; i++) {
			for (int j = CompletionProposal.ANONYMOUS_CLASS_DECLARATION; j <= CompletionProposal.ANONYMOUS_CLASS_CONSTRUCTOR_INVOCATION; j++) {
				setAllowsRequiredProposals(i, j, true);
			}
		}
	}

	public void completionFailure(IProblem p) {
		this.problem = p;
	}

	public String getContext() {
		if(this.context == null) return "";

		StringBuilder buffer = new StringBuilder();

		if(!this.shortContext) {
			buffer.append("completion offset=");
			buffer.append(this.context.getOffset());
			buffer.append('\n');

			buffer.append("completion range=[");
			buffer.append(this.context.getTokenStart());
			buffer.append(", ");
			buffer.append(this.context.getTokenEnd());
			buffer.append("]\n");

			char[] token = this.context.getToken();
			buffer.append("completion token=");
			if(token == null) {
				buffer.append("null");
			} else {
				buffer.append('\"');
				buffer.append(token);
				buffer.append('\"');
			}
			buffer.append('\n');

			buffer.append("completion token kind=");
			int tokenKind = this.context.getTokenKind();
			if(tokenKind == CompletionContext.TOKEN_KIND_STRING_LITERAL) {
				buffer.append("TOKEN_KIND_STRING_LITERAL");
			} else if(tokenKind == CompletionContext.TOKEN_KIND_NAME) {
				buffer.append("TOKEN_KIND_NAME");
			} else {
				buffer.append("TOKEN_KIND_UNKNOWN");
			}
			buffer.append('\n');
		}
		char[][] expectedTypesSignatures = this.context.getExpectedTypesSignatures();
		buffer.append("expectedTypesSignatures=");
		if(expectedTypesSignatures == null) {
			buffer.append(this.NULL_LITERAL);
		} else {
			buffer.append('{');
			for (int i = 0; i < expectedTypesSignatures.length; i++) {
				if(i > 0) buffer.append(',');
				buffer.append(expectedTypesSignatures[i]);

			}
			buffer.append('}');
		}
		buffer.append('\n');

		char[][] expectedTypesKeys = this.context.getExpectedTypesKeys();
		buffer.append("expectedTypesKeys=");
		if(expectedTypesSignatures == null) {
			buffer.append(this.NULL_LITERAL);
		} else {
			buffer.append('{');
			for (int i = 0; i < expectedTypesKeys.length; i++) {
				if(i > 0) buffer.append(',');
				buffer.append(expectedTypesKeys[i]);

			}
			buffer.append('}');
		}

		if(!this.shortContext) {
			buffer.append('\n');

			int locationType = this.context.getTokenLocation();
			if (locationType == 0) {
				buffer.append("completion token location=UNKNOWN"); //$NON-NLS-1$
			} else {
				buffer.append("completion token location={"); //$NON-NLS-1$
				boolean first = true;
				if ((locationType & CompletionContext.TL_MEMBER_START) != 0) {
					if (!first) buffer.append(',');
					buffer.append("MEMBER_START"); //$NON-NLS-1$
					first = false;
				}
				if ((locationType & CompletionContext.TL_STATEMENT_START) != 0) {
					if (!first) buffer.append(',');
					buffer.append("STATEMENT_START"); //$NON-NLS-1$
					first = false;
				}
				if ((locationType & CompletionContext.TL_CONSTRUCTOR_START) != 0) {
					if (!first) buffer.append(',');
					buffer.append("CONSTRUCTOR_START"); //$NON-NLS-1$
					first = false;
				}
				if ((locationType & CompletionContext.TL_IN_IMPORT) != 0) {
					if (!first) buffer.append(',');
					buffer.append("IN_IMPORT"); //$NON-NLS-1$
					first = false;
				}
				buffer.append('}');
			}
		}

		if (this.computeEnclosingElement) {
			buffer.append('\n');
			buffer.append("enclosingElement="); //$NON-NLS-1$
			JavaElement enclosingElement = (JavaElement)this.context.getEnclosingElement();
			if (enclosingElement == null) {
				buffer.append("null"); //$NON-NLS-1$
			} else {
				buffer.append(enclosingElement.toStringWithAncestors(true /*show resolved info*/));
			}
		}

		if (this.computeVisibleElements) {
			buffer.append('\n');

			IJavaElement[] visibleElements = this.context.getVisibleElements(this.assignableType);
			buffer.append("visibleElements="); //$NON-NLS-1$
			if (visibleElements == null) {
				buffer.append("null"); //$NON-NLS-1$
			} else if (visibleElements.length == 0) {
				buffer.append("{}"); //$NON-NLS-1$
			} else {
				buffer.append('{');
				buffer.append('\n');
				for (int i = 0; i < visibleElements.length; i++) {
					JavaElement element = (JavaElement) visibleElements[i];
					buffer.append('\t');
					buffer.append(element.toStringWithAncestors(true /*show resolved info*/));
					buffer.append(",\n"); //$NON-NLS-1$
				}
				buffer.append('}');
			}
		}

		//buffer.append('\n');


		return buffer.toString();
	}
	public String getProblem() {
		return this.problem == null ? "" : this.problem.getMessage();
	}

	public CompletionProposal[] getProposals() {
		return this.proposals;
	}
	/*
	 * Get sorted results in ascending order
	 */
	public String getResults() {
		if(this.proposalsPtr < 0) return "";
		quickSort(this.proposals, 0, this.proposalsPtr);
		return getResultsWithoutSorting();
	}

	/*
	 * Get sorted results in ascending order
	 */
	public String getReversedResults() {
		if(this.proposalsPtr < 0) return "";
		Arrays.sort(this.proposals, new Comparator() {
			@Override
			public int compare(Object o1, Object o2) {
				if (o1 == o2)
					return 0;
				if (o1 == null)
					return 1;
				if (o2 == null)
					return -1;
				CompletionProposal p1 = (CompletionProposal) o1;
				CompletionProposal p2 = (CompletionProposal) o2;
				int relDif = p2.getRelevance() - p1.getRelevance();
				if(relDif != 0) return relDif;
				String name1 = getElementName(p1);
				String name2 = getElementName(p2);
				return name1.compareTo(name2);
			}
		});
		return getResultsWithoutSorting();
	}

	/*
	 * Get unsorted results (ie. same order as they were accepted by requestor)
	 */
	public String getResultsWithoutSorting() {
		if(this.proposalsPtr < 0) return "";
		StringBuffer buffer = printProposal(this.proposals[0]);
		for(int i = 1; i <=this.proposalsPtr; i++) {
			if(i > 0) buffer.append('\n');
			buffer.append(printProposal(this.proposals[i]));
		}
		return buffer.toString();
	}
	public String[] getStringsResult() {
		if(this.proposalsPtr < 0) {
			return new String[0];
		}
		String[] strings = new String[this.proposalsPtr+1];
		for (int i=0; i<=this.proposalsPtr; i++) {
			strings[i] =  printProposal(this.proposals[i]).toString();
		}
		return strings;
	}

	protected StringBuffer printProposal(CompletionProposal proposal) {
		StringBuffer buffer = new StringBuffer();
		return printProposal(proposal, 0, buffer);
	}

	protected StringBuffer printProposal(CompletionProposal proposal, int tab, StringBuffer buffer) {
		for (int i = 0; i < tab; i++) {
			buffer.append("   "); //$NON-NLS-1$
		}
		buffer.append(getElementName(proposal));
		buffer.append('[');
		switch(proposal.getKind()) {
			case CompletionProposal.ANONYMOUS_CLASS_DECLARATION :
				buffer.append("ANONYMOUS_CLASS_DECLARATION"); //$NON-NLS-1$
				break;
			case CompletionProposal.FIELD_REF :
				buffer.append("FIELD_REF"); //$NON-NLS-1$
				break;
			case CompletionProposal.FIELD_REF_WITH_CASTED_RECEIVER :
				buffer.append("FIELD_REF_WITH_CASTED_RECEIVER"); //$NON-NLS-1$
				break;
			case CompletionProposal.KEYWORD :{
				if(isRestrictedIdentifier(proposal.getCompletion()))
						buffer.append("RESTRICTED_IDENTIFIER");
					else
						buffer.append("KEYWORD"); //$NON-NLS-1$
			}
				break;
			case CompletionProposal.LABEL_REF :
				buffer.append("LABEL_REF"); //$NON-NLS-1$
				break;
			case CompletionProposal.LOCAL_VARIABLE_REF :
				buffer.append("LOCAL_VARIABLE_REF"); //$NON-NLS-1$
				break;
			case CompletionProposal.METHOD_DECLARATION :
				buffer.append("METHOD_DECLARATION"); //$NON-NLS-1$
				if(proposal.isConstructor()) {
					buffer.append("<CONSTRUCTOR>"); //$NON-NLS-1$
				}
				break;
			case CompletionProposal.METHOD_REF :
				buffer.append("METHOD_REF"); //$NON-NLS-1$
				if(proposal.isConstructor()) {
					buffer.append("<CONSTRUCTOR>"); //$NON-NLS-1$
				}
				break;
			case CompletionProposal.METHOD_REF_WITH_CASTED_RECEIVER :
				buffer.append("METHOD_REF_WITH_CASTED_RECEIVER"); //$NON-NLS-1$
				if(proposal.isConstructor()) {
					buffer.append("<CONSTRUCTOR>"); //$NON-NLS-1$
				}
				break;
			case CompletionProposal.MODULE_DECLARATION :
				buffer.append("MODULE_DECLARATION"); //$NON-NLS-1$
				break;
			case CompletionProposal.MODULE_REF :
				buffer.append("MODULE_REF"); //$NON-NLS-1$
				break;
			case CompletionProposal.PACKAGE_REF :
				buffer.append("PACKAGE_REF"); //$NON-NLS-1$
				break;
			case CompletionProposal.TYPE_REF :
				buffer.append("TYPE_REF"); //$NON-NLS-1$
				if (proposal.getArrayDimensions() > 0) {
					buffer.append("<ARRAY>"); //$NON-NLS-1$
				}
				break;
			case CompletionProposal.VARIABLE_DECLARATION :
				buffer.append("VARIABLE_DECLARATION"); //$NON-NLS-1$
				break;
			case CompletionProposal.POTENTIAL_METHOD_DECLARATION :
				buffer.append("POTENTIAL_METHOD_DECLARATION"); //$NON-NLS-1$
				break;
			case CompletionProposal.METHOD_NAME_REFERENCE :
				buffer.append("METHOD_NAME_REFERENCE"); //$NON-NLS-1$
				break;
			case CompletionProposal.ANNOTATION_ATTRIBUTE_REF :
				buffer.append("ANNOTATION_ATTRIBUTE_REF"); //$NON-NLS-1$
				break;
			case CompletionProposal.JAVADOC_BLOCK_TAG :
				buffer.append("JAVADOC_BLOCK_TAG"); //$NON-NLS-1$
				break;
			case CompletionProposal.JAVADOC_INLINE_TAG :
				buffer.append("JAVADOC_INLINE_TAG"); //$NON-NLS-1$
				break;
			case CompletionProposal.JAVADOC_FIELD_REF:
				buffer.append("JAVADOC_FIELD_REF"); //$NON-NLS-1$
				break;
			case CompletionProposal.JAVADOC_METHOD_REF :
				buffer.append("JAVADOC_METHOD_REF"); //$NON-NLS-1$
				break;
			case CompletionProposal.JAVADOC_TYPE_REF :
				buffer.append("JAVADOC_TYPE_REF"); //$NON-NLS-1$
				break;
			case CompletionProposal.JAVADOC_PARAM_REF :
				buffer.append("JAVADOC_PARAM_REF"); //$NON-NLS-1$
				break;
			case CompletionProposal.JAVADOC_VALUE_REF :
				buffer.append("JAVADOC_VALUE_REF"); //$NON-NLS-1$
				break;
			case CompletionProposal.FIELD_IMPORT :
				buffer.append("FIELD_IMPORT"); //$NON-NLS-1$
				break;
			case CompletionProposal.METHOD_IMPORT :
				buffer.append("METHOD_IMPORT"); //$NON-NLS-1$
				break;
			case CompletionProposal.TYPE_IMPORT :
				buffer.append("TYPE_IMPORT"); //$NON-NLS-1$
				break;
			case CompletionProposal.CONSTRUCTOR_INVOCATION :
				buffer.append("CONSTRUCTOR_INVOCATION"); //$NON-NLS-1$
				break;
			case CompletionProposal.ANONYMOUS_CLASS_CONSTRUCTOR_INVOCATION :
				buffer.append("ANONYMOUS_CLASS_CONSTRUCTOR_INVOCATION"); //$NON-NLS-1$
				break;
			case CompletionProposal.LAMBDA_EXPRESSION :
				buffer.append("LAMBDA_EXPRESSION"); //$NON-NLS-1$
				break;
			default :
				buffer.append("PROPOSAL"); //$NON-NLS-1$
				break;

		}
		buffer.append("]{");
		buffer.append(proposal.getCompletion() == null ? this.NULL_LITERAL : proposal.getCompletion());
		buffer.append(", ");
		buffer.append(proposal.getDeclarationSignature() == null ? this.NULL_LITERAL : proposal.getDeclarationSignature());
		buffer.append(", ");
		buffer.append(proposal.getSignature() == null ? this.NULL_LITERAL : proposal.getSignature());

		char[] receiverSignature = proposal.getReceiverSignature();
		if (receiverSignature != null) {
			buffer.append(", ");
			buffer.append(receiverSignature);
		}

		if(this.showUniqueKeys) {
			buffer.append(", ");
			buffer.append(proposal.getDeclarationKey() == null ? this.NULL_LITERAL : proposal.getDeclarationKey());
			buffer.append(", ");
			buffer.append(proposal.getKey() == null ? this.NULL_LITERAL : proposal.getKey());
		}
		buffer.append(", ");
		buffer.append(proposal.getName() == null ? this.NULL_LITERAL : proposal.getName());
		if(this.showParameterNames) {
			char[][] parameterNames = proposal.findParameterNames(null);
			buffer.append(", ");
			if(parameterNames == null || parameterNames.length <= 0) {
				buffer.append(this.NULL_LITERAL);
			} else {
				buffer.append("(");
				for (int i = 0; i < parameterNames.length; i++) {
					if(i > 0) buffer.append(", ");
					buffer.append(parameterNames[i]);
				}
				buffer.append(")");
			}
		}

		if(this.showPositions) {
			buffer.append(", ");
			if(this.showTokenPositions || receiverSignature != null) buffer.append("replace");
			buffer.append("[");
			buffer.append(proposal.getReplaceStart());
			buffer.append(", ");
			buffer.append(proposal.getReplaceEnd());
			buffer.append("]");
		}
		if(this.showTokenPositions) {
			buffer.append(", token[");
			buffer.append(proposal.getTokenStart());
			buffer.append(", ");
			buffer.append(proposal.getTokenEnd());
			buffer.append("]");
		}
		if(this.showPositions && receiverSignature != null) {
			buffer.append(", receiver[");
			buffer.append(proposal.getReceiverStart());
			buffer.append(", ");
			buffer.append(proposal.getReceiverEnd());
			buffer.append("]");
		}
		if(this.showModifiers) {
			int flags = proposal.getFlags();
			buffer.append(", ");
			buffer.append(Flags.toString(flags));
			if (Flags.isDeprecated(flags)) {
				buffer.append(" deprecated"); //$NON-NLS-1$
			}
		}
		buffer.append(", ");
		buffer.append(proposal.getRelevance());
		buffer.append('}');
		if(this.showMissingTypes) {
			CompletionProposal[] requiredProposals = proposal.getRequiredProposals();
			if (requiredProposals != null) {
				int length = requiredProposals.length;
				System.arraycopy(requiredProposals, 0, requiredProposals = new CompletionProposal[length], 0, length);
				quickSort(requiredProposals, 0, length - 1);
				for (int i = 0; i < length; i++) {
					buffer.append('\n');
					printProposal(requiredProposals[i], tab + 1, buffer);
				}
			}
		}
		return buffer;
	}

	private boolean isRestrictedIdentifier(char[] completion) {
		if(CharOperation.equals(completion, RestrictedIdentifiers.RECORD))
			return true;
		if(CharOperation.equals(completion, RestrictedIdentifiers.SEALED))
			return true;
		if(CharOperation.equals(completion, RestrictedIdentifiers.NON_SEALED))
			return true;
		if(CharOperation.equals(completion, RestrictedIdentifiers.PERMITS))
			return true;

		return false;
	}
	protected CompletionProposal[] quickSort(CompletionProposal[] collection, int left, int right) {
		int original_left = left;
		int original_right = right;
		CompletionProposal mid = collection[left + ((right - left)/2)];
		do {
			while (compare(mid, collection[left]) > 0)
				// s[left] >= mid
				left++;
			while (compare(mid, collection[right]) < 0)
				// s[right] <= mid
				right--;
			if (left <= right) {
				CompletionProposal tmp = collection[left];
				collection[left] = collection[right];
				collection[right] = tmp;
				left++;
				right--;
			}
		} while (left <= right);
		if (original_left < right)
			collection = quickSort(collection, original_left, right);
		if (left < original_right)
			collection = quickSort(collection, left, original_right);
		return collection;
	}

	protected int compare(CompletionProposal proposal1, CompletionProposal proposal2) {
		int relDif = proposal1.getRelevance() - proposal2.getRelevance();
		if(relDif != 0) return relDif;
		String name1 = getElementName(proposal1);
		String name2 = getElementName(proposal2);
		int nameDif = name1.compareTo(name2);
		if(nameDif != 0) return nameDif;
		int kindDif = proposal1.getKind() - proposal2.getKind();
		if(kindDif != 0) return kindDif;
		String completion1 = new String(proposal1.getCompletion());
		String completion2 = new String(proposal2.getCompletion());
		int completionDif = completion1.compareTo(completion2);
		if(completionDif != 0) return completionDif;
		char[] temp = proposal1.getSignature();
		String signature1 = temp == null ? null: new String(temp);
		temp = proposal2.getSignature();
		String signature2 = temp == null ? null: new String(temp);
		int signatureDif = 0;
		if(signature1 != null && signature2 != null) {
			signatureDif = signature1.compareTo(signature2);
		}
		if(signatureDif != 0) return signatureDif;
		temp = proposal1.getDeclarationSignature();
		String declarationSignature1 = temp == null ? null: new String(temp);
		temp = proposal2.getDeclarationSignature();
		String declarationSignature2 = temp == null ? null: new String(temp);
		int declarationSignatureDif = 0;
		if(declarationSignature1 != null && declarationSignature2 != null) {
			declarationSignatureDif = declarationSignature1.compareTo(declarationSignature2);
		}
		if(declarationSignatureDif != 0) return declarationSignatureDif;
		return 0;
	}

	protected String getElementName(CompletionProposal proposal) {
		switch(proposal.getKind()) {
			case CompletionProposal.ANONYMOUS_CLASS_DECLARATION :
				return new String(Signature.getSignatureSimpleName(proposal.getDeclarationSignature()));
			case CompletionProposal.TYPE_REF :
			case CompletionProposal.TYPE_IMPORT :
			case CompletionProposal.JAVADOC_TYPE_REF :
				return new String(Signature.getSignatureSimpleName(proposal.getSignature()));
			case CompletionProposal.FIELD_REF :
			case CompletionProposal.FIELD_REF_WITH_CASTED_RECEIVER :
			case CompletionProposal.KEYWORD:
			case CompletionProposal.LABEL_REF:
			case CompletionProposal.LOCAL_VARIABLE_REF:
			case CompletionProposal.METHOD_REF:
			case CompletionProposal.METHOD_REF_WITH_CASTED_RECEIVER:
			case CompletionProposal.METHOD_DECLARATION:
			case CompletionProposal.VARIABLE_DECLARATION:
			case CompletionProposal.POTENTIAL_METHOD_DECLARATION:
			case CompletionProposal.METHOD_NAME_REFERENCE:
			case CompletionProposal.ANNOTATION_ATTRIBUTE_REF:
			case CompletionProposal.JAVADOC_BLOCK_TAG :
			case CompletionProposal.JAVADOC_INLINE_TAG :
			case CompletionProposal.JAVADOC_FIELD_REF:
			case CompletionProposal.JAVADOC_METHOD_REF :
			case CompletionProposal.JAVADOC_PARAM_REF :
			case CompletionProposal.JAVADOC_VALUE_REF :
			case CompletionProposal.FIELD_IMPORT :
			case CompletionProposal.METHOD_IMPORT :
			case CompletionProposal.CONSTRUCTOR_INVOCATION :
			case CompletionProposal.ANONYMOUS_CLASS_CONSTRUCTOR_INVOCATION :
				return new String(proposal.getName());
			case CompletionProposal.PACKAGE_REF:
			case CompletionProposal.MODULE_DECLARATION:
				return new String(proposal.getDeclarationSignature());
		}
		return "";
	}
	public String toString() {
		return getResults();
	}
	public void setComputeVisibleElements(boolean computeVisibleElements) {
		this.computeVisibleElements = computeVisibleElements;
	}
	public void setAssignableType(String typeSignature) {
		this.assignableType = typeSignature;
	}
	public void setComputeEnclosingElement(boolean computeEnclosingElement) {
		this.computeEnclosingElement = computeEnclosingElement;
	}
	public void setProposalFilter(Predicate<CompletionProposal> proposalFilter) {
		this.proposalFilter = proposalFilter;
	}

	public void setTypeProposalFilter(Predicate<String> typeProposalFilter) {
		this.typeProposalFilter = typeProposalFilter;
	}
	public boolean canUseDiamond(int proposalNo) {
		if (proposalNo < this.proposals.length && this.proposals[proposalNo] != null) {
			return this.proposals[proposalNo].canUseDiamond(this.context);
		}
		return false;
	}

	public String getCompletionNode() {
		if (this.context instanceof InternalCompletionContext) {
			InternalCompletionContext internalCompletionContext = (InternalCompletionContext) this.context;
			ASTNode astNode = internalCompletionContext.getCompletionNode();
			if (astNode != null) return astNode.toString();

		}
		return null;
	}

	public String getCompletionNodeParent() {
		if (this.context instanceof InternalCompletionContext) {
			InternalCompletionContext internalCompletionContext = (InternalCompletionContext) this.context;
			ASTNode astNode = internalCompletionContext.getCompletionNodeParent();
			if (astNode != null) return astNode.toString();

		}
		return null;
	}

	public String getVisibleLocalVariables() {
		if (this.context instanceof InternalCompletionContext) {
			InternalCompletionContext internalCompletionContext = (InternalCompletionContext) this.context;
			ObjectVector locals = internalCompletionContext.getVisibleLocalVariables();
			if (locals != null) return locals.toString();

		}
		return null;
	}

	public String getVisibleFields() {
		if (this.context instanceof InternalCompletionContext) {
			InternalCompletionContext internalCompletionContext = (InternalCompletionContext) this.context;
			ObjectVector fields = internalCompletionContext.getVisibleFields();
			if (fields != null) return fields.toString();

		}
		return null;
	}

	public String getVisibleMethods() {
		if (this.context instanceof InternalCompletionContext) {
			InternalCompletionContext internalCompletionContext = (InternalCompletionContext) this.context;
			ObjectVector methods = internalCompletionContext.getVisibleMethods();
			if (methods != null) return methods.toString();

		}
		return null;
	}

	public char[][] getExpectedTypesSignatures() {
		return this.context.getExpectedTypesSignatures();
	}
}
