content: /*******************************************************************************
   * Copyright (c) 2000, 2008 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.wst.jsdt.internal.corext.refactoring.util;
  
  import java.util.HashSet;
  import java.util.Set;
  import java.util.StringTokenizer;
  import java.util.regex.Pattern;
  
  import org.eclipse.core.filebuffers.FileBuffers;
  import org.eclipse.core.resources.IFile;
  import org.eclipse.core.resources.IProject;
  import org.eclipse.core.resources.IResource;
  import org.eclipse.core.runtime.Assert;
  import org.eclipse.core.runtime.CoreException;
  import org.eclipse.core.runtime.IPath;
  import org.eclipse.core.runtime.IProgressMonitor;
  import org.eclipse.core.runtime.NullProgressMonitor;
  import org.eclipse.ltk.core.refactoring.GroupCategory;
  import org.eclipse.ltk.core.refactoring.GroupCategorySet;
  import org.eclipse.ltk.core.refactoring.TextChange;
  import org.eclipse.search.core.text.TextSearchEngine;
  import org.eclipse.search.core.text.TextSearchMatchAccess;
  import org.eclipse.search.core.text.TextSearchRequestor;
  import org.eclipse.search.core.text.TextSearchScope;
  import org.eclipse.text.edits.ReplaceEdit;
  import org.eclipse.wst.jsdt.core.IJavaScriptElement;
  import org.eclipse.wst.jsdt.core.JavaScriptCore;
  import org.eclipse.wst.jsdt.internal.corext.refactoring.RefactoringCoreMessages;
  import org.eclipse.wst.jsdt.internal.corext.refactoring.changes.TextChangeCompatibility;
  import org.eclipse.wst.jsdt.internal.ui.util.PatternConstructor;
  
  public class QualifiedNameFinder {
  
  	private static final GroupCategorySet QUALIFIED_NAMES= new GroupCategorySet(
  		new GroupCategory("org.eclipse.wst.jsdt.internal.corext.qualifiedNames", //$NON-NLS-1$
  			RefactoringCoreMessages.QualifiedNameFinder_qualifiedNames_name, 
  			RefactoringCoreMessages.QualifiedNameFinder_qualifiedNames_description));
  	
  	private static class ResultCollector extends TextSearchRequestor {
  		
  		private String fNewValue;
  		private QualifiedNameSearchResult fResult;
  		
  		public ResultCollector(QualifiedNameSearchResult result, String newValue) {
  			fResult= result;
  			fNewValue= newValue;
  		}
  		
  		public boolean acceptFile(IFile file) throws CoreException {			
  			IJavaScriptElement element= JavaScriptCore.create(file);
  			if ((element != null && element.exists()))
  				return false;
  			
  			// Only touch text files (see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=114153 ):
  			if (! FileBuffers.getTextFileBufferManager().isTextFileLocation(file.getFullPath(), false))
  				return false;
  			
  			IPath path= file.getProjectRelativePath();
  			String segment= path.segment(0);
  			if (segment != null && (segment.startsWith(".refactorings") || segment.startsWith(".deprecations"))) //$NON-NLS-1$ //$NON-NLS-2$
  				return false;
  
  			return true;
  		}
  		
  		public boolean acceptPatternMatch(TextSearchMatchAccess matchAccess) throws CoreException {
  			int start= matchAccess.getMatchOffset();
  			int length= matchAccess.getMatchLength();
  			
  			// skip embedded FQNs (bug 130764):
  			if (start > 0) {
  				char before= matchAccess.getFileContentChar(start - 1);
  				if (before == '.' || Character.isJavaIdentifierPart(before))
  					return true;
  			}
  			int fileContentLength= matchAccess.getFileContentLength();
  			int end= start + length;
  			if (end < fileContentLength) {
  				char after= matchAccess.getFileContentChar(end);
  				if (Character.isJavaIdentifierPart(after))
  					return true;
  			}
  			
  			IFile file= matchAccess.getFile();
  			TextChange change= fResult.getChange(file);
  			TextChangeCompatibility.addTextEdit(
  				change, 
  				RefactoringCoreMessages.QualifiedNameFinder_update_name,  
  				new ReplaceEdit(start, length, fNewValue), QUALIFIED_NAMES);
  			
  			return true;
  		}
  	}
  		
  	public QualifiedNameFinder() {
  	}
  	
  	public static void process(QualifiedNameSearchResult result, String pattern, String newValue, String filePatterns, IProject root, IProgressMonitor monitor) {
  		Assert.isNotNull(pattern);
  		Assert.isNotNull(newValue);
  		Assert.isNotNull(root);
  		
  		if (monitor == null)
  			monitor= new NullProgressMonitor();
  		
  		if (filePatterns == null || filePatterns.length() == 0) {
  			// Eat progress.
  			monitor.beginTask("", 1); //$NON-NLS-1$
  			monitor.worked(1);
  			return;
  		}
  
  		ResultCollector collector= new ResultCollector(result, newValue);
  		TextSearchEngine engine= TextSearchEngine.create();
  		Pattern searchPattern= PatternConstructor.createPattern(pattern, true, false);
  		
  		engine.search(createScope(filePatterns, root), collector, searchPattern, monitor);
  	}
  	
  	private static TextSearchScope createScope(String filePatterns, IProject root) {
  		HashSet res= new HashSet();
  		res.add(root);
  		addReferencingProjects(root, res);
  		IResource[] resArr= (IResource[]) res.toArray(new IResource[res.size()]);
  		Pattern filePattern= getFilePattern(filePatterns);
  		
  		return TextSearchScope.newSearchScope(resArr, filePattern, false);
  	}
  	
  	private static Pattern getFilePattern(String filePatterns) {
  		StringTokenizer tokenizer= new StringTokenizer(filePatterns, ","); //$NON-NLS-1$
  		String[] filePatternArray= new String[tokenizer.countTokens()];
  		int i= 0;
  		while (tokenizer.hasMoreTokens()) {
  			filePatternArray[i++]= tokenizer.nextToken().trim();
  		}
  		return PatternConstructor.createPattern(filePatternArray, true, false);
  	}
  	
  	private static void addReferencingProjects(IProject root, Set res) {
  		IProject[] projects= root.getReferencingProjects();
  		for (int i= 0; i < projects.length; i++) {
  			IProject project= projects[i];
  			if (res.add(project)) {
  				addReferencingProjects(project, res);
  			}
  		}
  	}
  }
  