/*******************************************************************************
 * Copyright (c) 2008, 2009 IBM Wind River Systems, Inc. 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:
 *    Markus Schorn - Initial API and implementation
 *******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.c;

import org.eclipse.cdt.core.dom.ast.ASTVisitor;
import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.IProblemBinding;
import org.eclipse.cdt.core.dom.ast.IScope;
import org.eclipse.cdt.internal.core.dom.parser.ASTAmbiguousNode;
import org.eclipse.cdt.internal.core.dom.parser.IASTAmbiguityParent;
import org.eclipse.cdt.internal.core.dom.parser.IASTAmbiguousSimpleDeclaration;
import org.eclipse.cdt.internal.core.dom.parser.IASTInternalScope;

/**
 * Handles ambiguities for parameter declarations.
 * <br>
 * void function(const D*); // is D a type?
 * @since 5.0.1
 */
public class CASTAmbiguousSimpleDeclaration extends ASTAmbiguousNode implements IASTAmbiguousSimpleDeclaration {

    private IASTSimpleDeclaration fSimpleDecl;
    private IASTDeclSpecifier fAltDeclSpec;
    private IASTDeclarator fAltDtor;
    
    public CASTAmbiguousSimpleDeclaration(IASTSimpleDeclaration decl, IASTDeclSpecifier declSpec, IASTDeclarator dtor) {
    	fSimpleDecl= decl;
    	fAltDeclSpec= declSpec;
    	fAltDtor= dtor;
	}

	@Override
	protected void beforeResolution() {
		// populate containing scope, so that it will not be affected by the alternative branches.
		IScope scope= CVisitor.getContainingScope(this);
		if (scope instanceof IASTInternalScope) {
			((IASTInternalScope) scope).populateCache();
		}
	}

    @Override
	public IASTNode[] getNodes() {
        return new IASTNode[] {fSimpleDecl, fAltDeclSpec, fAltDtor};
    }

	public IASTSimpleDeclaration copy() {
		throw new UnsupportedOperationException();
	}

	public void addDeclarator(IASTDeclarator declarator) {
		fSimpleDecl.addDeclarator(declarator);
	}

	public IASTDeclSpecifier getDeclSpecifier() {
		return fSimpleDecl.getDeclSpecifier();
	}

	public IASTDeclarator[] getDeclarators() {
		return fSimpleDecl.getDeclarators();
	}

	public void setDeclSpecifier(IASTDeclSpecifier declSpec) {
		fSimpleDecl.setDeclSpecifier(declSpec);
	}
	
	@Override
	public final IASTNode resolveAmbiguity(ASTVisitor visitor) {
		final IASTAmbiguityParent owner= (IASTAmbiguityParent) getParent();
		IASTNode nodeToReplace= this;

		// handle nested ambiguities first
		owner.replace(nodeToReplace, fSimpleDecl);
		IASTDeclSpecifier declSpec= fSimpleDecl.getDeclSpecifier();
		declSpec.accept(visitor);
		

		// find nested names
		final NameCollector nameCollector= new NameCollector();
		declSpec.accept(nameCollector);
		final IASTName[] names= nameCollector.getNames();

		// resolve names 
		boolean hasIssue= false;
		for (IASTName name : names) {
			try {
				IBinding b = name.resolveBinding();
				if (b instanceof IProblemBinding) {
					hasIssue= true;
					break;
				}
			} catch (Exception t) {
				hasIssue= true;
				break;
			}
		}
		if (hasIssue) {
			// use the alternate version
			final IASTAmbiguityParent parent = (IASTAmbiguityParent) fSimpleDecl;
			parent.replace(declSpec, fAltDeclSpec);
			parent.replace(fSimpleDecl.getDeclarators()[0], fAltDtor);
		}
			
		// resolve further nested ambiguities
		fSimpleDecl.accept(visitor);
		return fSimpleDecl;
	}
}
