content: package ts.eclipse.ide.jsdt.internal.ui.refactoring;
  
  import java.util.ArrayList;
  import java.util.List;
  import java.util.concurrent.TimeUnit;
  
  import org.eclipse.core.resources.IFile;
  import org.eclipse.core.runtime.Assert;
  import org.eclipse.core.runtime.CoreException;
  import org.eclipse.core.runtime.IProgressMonitor;
  import org.eclipse.core.runtime.IStatus;
  import org.eclipse.core.runtime.OperationCanceledException;
  import org.eclipse.core.runtime.Status;
  import org.eclipse.jface.text.Position;
  import org.eclipse.ltk.core.refactoring.Change;
  import org.eclipse.ltk.core.refactoring.CompositeChange;
  import org.eclipse.ltk.core.refactoring.RefactoringStatus;
  import org.eclipse.ltk.core.refactoring.TextFileChange;
  import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext;
  import org.eclipse.ltk.core.refactoring.participants.RefactoringParticipant;
  import org.eclipse.ltk.core.refactoring.participants.RenameProcessor;
  import org.eclipse.ltk.core.refactoring.participants.SharableParticipants;
  import org.eclipse.text.edits.MultiTextEdit;
  import org.eclipse.text.edits.ReplaceEdit;
  
  import ts.client.TextSpan;
  import ts.client.rename.RenameInfo;
  import ts.client.rename.RenameResponseBody;
  import ts.client.rename.SpanGroup;
  import ts.eclipse.ide.core.utils.WorkbenchResourceUtil;
  import ts.eclipse.ide.jsdt.core.JSDTTypeScriptCorePlugin;
  import ts.eclipse.ide.ui.utils.EditorUtils;
  import ts.resources.ITypeScriptFile;
  
  public class TypeScriptRenameProcessor extends RenameProcessor {
  
  	private static final String TEXT_TYPE = "ts";
  
  	private static final String ID = "ts.eclipse.ide.core.refactoring.rename";
  
  	private final ITypeScriptFile tsFile;
  	private final int offset;
  	private final String oldName;
  
  	private String newName;
  	private boolean findInComments;
  	private boolean findInStrings;
  
  	private RenameResponseBody rename;
  
  	public TypeScriptRenameProcessor(ITypeScriptFile tsFile, int offset, String oldName) {
  		this.tsFile = tsFile;
  		this.offset = offset;
  		this.oldName = oldName;
  	}
  
  	@Override
  	public Object[] getElements() {
  		return null;
  	}
  
  	@Override
  	public String getIdentifier() {
  		return ID;
  	}
  
  	@Override
  	public String getProcessorName() {
  		return RefactoringMessages.TypeScriptRenameProcessor_name;
  	}
  
  	@Override
  	public boolean isApplicable() throws CoreException {
  		return true;
  	}
  
  	@Override
  	public RefactoringStatus checkInitialConditions(IProgressMonitor pm)
  			throws CoreException, OperationCanceledException {
  		rename = null;
  		return new RefactoringStatus();
  	}
  
  	@Override
  	public RefactoringStatus checkFinalConditions(IProgressMonitor pm, CheckConditionsContext context)
  			throws CoreException, OperationCanceledException {
  		RefactoringStatus status = new RefactoringStatus();
  		// Consume "rename" tsserver command.
  		try {
  			rename = tsFile.rename(offset, isFindInComments(), isFindInStrings()).get(1000, TimeUnit.MILLISECONDS);
  			RenameInfo info = rename.getInfo();
  			if (!info.isCanRename()) {
  				// Refactoring cannot be done.
  				status.addError(info.getLocalizedErrorMessage());
  			}
  		} catch (Exception e) {
  			status.addError(e.getMessage());
  		}
  		return status;
  	}
  
  	@Override
  	public Change createChange(IProgressMonitor pm) throws CoreException, OperationCanceledException {
  		try {
  			if (rename == null) {
  				throw new CoreException(new Status(IStatus.ERROR, JSDTTypeScriptCorePlugin.PLUGIN_ID,
  						"TypeScript rename cannot be null"));
  			}
  
  			// Convert TypeScript changes to Eclipse changes.
  			List<SpanGroup> locs = rename.getLocs();
  			List<Change> fileChanges = new ArrayList<>();
  			for (SpanGroup loc : locs) {
  				IFile file = WorkbenchResourceUtil.findFileFromWorkspace(loc.getFile());
  				TextFileChange change = new TextFileChange(file.getName(), file);
  				change.setEdit(new MultiTextEdit());
  				change.setTextType(TEXT_TYPE);
  
  				List<TextSpan> spans = loc.getLocs();
  				for (TextSpan textSpan : spans) {
  					Position position = EditorUtils.getPosition(file, textSpan);
  					ReplaceEdit edit = new ReplaceEdit(position.offset, position.length, this.newName);
  					change.addEdit(edit);
  				}
  				fileChanges.add(change);
  			}
  			return new CompositeChange(RefactoringMessages.TypeScriptRenameProcessor_change_name,
  					fileChanges.toArray(new Change[fileChanges.size()]));
  		} catch (CoreException | OperationCanceledException e) {
  			throw e;
  		} catch (Exception e) {
  			throw new CoreException(
  					new Status(IStatus.ERROR, JSDTTypeScriptCorePlugin.PLUGIN_ID, "Error while rename", e));
  		}
  	}
  
  	@Override
  	public RefactoringParticipant[] loadParticipants(RefactoringStatus status, SharableParticipants sharedParticipants)
  			throws CoreException {
  		return null;
  	}
  
  	public String getOldName() {
  		return this.oldName;
  	}
  
  	public void setNewName(String newName) {
  		Assert.isNotNull(newName);
  		this.newName = newName;
  	}
  
  	public int getSaveMode() {
  		return RefactoringSaveHelper.SAVE_ALL_ALWAYS_ASK;
  	}
  
  	public boolean isFindInComments() {
  		return findInComments;
  	}
  
  	public void setFindInComments(boolean findInComments) {
  		this.findInComments = findInComments;
  	}
  
  	public boolean isFindInStrings() {
  		return findInStrings;
  	}
  
  	public void setFindInStrings(boolean findInStrings) {
  		this.findInStrings = findInStrings;
  	}
  
  }
  