/*******************************************************************************
 * Copyright (c) 2005, 2007 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.corext.refactoring.util;

import java.util.HashSet;
import java.util.Iterator;
import java.util.List;

import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor;
import org.eclipse.jdt.core.dom.rewrite.TargetSourceRangeComputer;

public class TightSourceRangeComputer extends TargetSourceRangeComputer {
	private HashSet/*<ASTNode>*/ fTightSourceRangeNodes= new HashSet();
	
	public void addTightSourceNode(ASTNode reference) {
		fTightSourceRangeNodes.add(reference);
		
	    List properties= reference.structuralPropertiesForType();
	    for (Iterator iterator= properties.iterator(); iterator.hasNext();) {
	        StructuralPropertyDescriptor descriptor= (StructuralPropertyDescriptor)iterator.next();
	        if (descriptor.isChildProperty()) {
	        	ASTNode child= (ASTNode)reference.getStructuralProperty(descriptor);
	        	if (isExtending(child, reference)) {
	        		addTightSourceNode(child);
	        	}
	        } else if (descriptor.isChildListProperty()) {
	        	List childs= (List)reference.getStructuralProperty(descriptor);
	        	for (Iterator iterator2= childs.iterator(); iterator2.hasNext();) {
	                ASTNode child= (ASTNode)iterator2.next();
	                if (isExtending(child, reference)) {
		        		addTightSourceNode(child);
		        	}	                
                }
	        }
        }
    }

	public SourceRange computeSourceRange(ASTNode node) {
		if (fTightSourceRangeNodes.contains(node)) {
			return new TargetSourceRangeComputer.SourceRange(node.getStartPosition(), node.getLength());
		} else {
			return super.computeSourceRange(node); // see bug 85850
		}
	}
	
	private boolean isExtending(ASTNode child, ASTNode parent) {
	    SourceRange extendedRange= super.computeSourceRange(child);
	    
	    int parentStart= parent.getStartPosition();
		int extendedStart= extendedRange.getStartPosition();
		if (parentStart > extendedStart)
			return true;
		
		int parentEnd= parentStart + parent.getLength();
		int extendedEnd= extendedStart + extendedRange.getLength();
		if (parentEnd < extendedEnd)
			return true;

	    return false;
    }
}
