/*******************************************************************************
* Copyright (c) 2005, 2015 Zend Technologies 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:
* Zend Technologies - initial API and implementation
*******************************************************************************/
package org.eclipse.php.refactoring.core.move;
import java.util.LinkedList;
import java.util.List;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.ltk.core.refactoring.TextEditChangeGroup;
import org.eclipse.ltk.core.refactoring.TextFileChange;
import org.eclipse.php.core.ast.nodes.Expression;
import org.eclipse.php.core.ast.nodes.Include;
import org.eclipse.php.core.ast.nodes.ParenthesisExpression;
import org.eclipse.php.core.ast.nodes.Scalar;
import org.eclipse.php.core.ast.visitor.AbstractVisitor;
import org.eclipse.php.refactoring.core.PhpRefactoringCoreMessages;
import org.eclipse.text.edits.ReplaceEdit;
import org.eclipse.text.edits.TextEdit;
import org.eclipse.text.edits.TextEditGroup;
public class ChangeIncludePath extends AbstractVisitor {
private IFile participateFile;
private boolean isIncluded;
/**
* {@link TextEditGroup}
*/
protected final List<TextEditGroup> groups = new LinkedList<TextEditGroup>();
private IFile file;
private IPath destinationPath;
private IResource[] selectedResource;
public ChangeIncludePath(IFile file, IFile participateFile,
IPath fMainDestinationPath, boolean isIncluded,
IResource[] selectedResources) {
this.file = file;
this.participateFile = participateFile;
this.isIncluded = isIncluded;
this.destinationPath = fMainDestinationPath;
this.selectedResource = selectedResources;
}
public boolean visit(Include include) {
Scalar scalar = null;
if (include.getExpression() instanceof ParenthesisExpression) {
ParenthesisExpression exp = (ParenthesisExpression) include
.getExpression();
Expression expression = exp.getExpression();
if (expression instanceof Scalar) {
scalar = (Scalar) expression;
}
}
if (include.getExpression() instanceof Scalar) {
scalar = (Scalar) include.getExpression();
}
if (scalar != null) {
String stringValue = scalar.getStringValue();
if (isScalarNeedChange(scalar, stringValue)) {
addChange(scalar, stringValue,
PhpRefactoringCoreMessages
.getString("RenameIncludeAndClassName.1")); //$NON-NLS-1$
}
}
return false;
}
private boolean isScalarNeedChange(Scalar scalar, final String stringValue) {
String value = getUnQuotedString(stringValue);
IPath includePath = new Path(value);
if (includePath.toString().startsWith("..")) { //$NON-NLS-1$
includePath = participateFile.getParent().getFullPath()
.append(includePath)
.makeRelativeTo(file.getProject().getFullPath());
}
IPath fileDirectory = file.getParent().getProjectRelativePath();
if (isIncluded) {
return true;
}
if (fileDirectory.isPrefixOf(includePath)) {
return includePath.equals(file.getProjectRelativePath());
} else {
IPath fullPath = participateFile.getParent()
.getProjectRelativePath().append(includePath);
return fullPath.equals(file.getProjectRelativePath());
}
}
private void addChange(Scalar scalar, String oldString, String description) {
final char charAt = scalar.getStringValue().charAt(0);
final int isQuotedOffset = charAt == '"' || charAt == '\'' ? 1 : 0;
addChange(scalar.getStart() + isQuotedOffset, oldString, description);
}
/**
* Adds the scalar to the list
*
* @param scalar
*/
protected void addChange(int start, String oldString, String description) {
final TextEditGroup textEditGroup = new TextEditGroup(description);
String value = getUnQuotedString(oldString);
String newValue = getNewPath(value);
if (!value.equals(newValue)) {
final ReplaceEdit replaceEdit = new ReplaceEdit(start,
value.length(), newValue);
textEditGroup.addTextEdit(replaceEdit);
groups.add(textEditGroup);
}
}
private String getUnQuotedString(String oldString) {
String value = oldString;
if (oldString.charAt(0) == '"'
&& oldString.charAt(oldString.length() - 1) == '"') {
value = oldString.substring(1, oldString.length() - 1);
}
if (oldString.charAt(0) == '\''
&& oldString.charAt(oldString.length() - 1) == '\'') {
value = oldString.substring(1, oldString.length() - 1);
}
return value;
}
private String getNewPath(String value) {
if (!isIncluded) {
return MoveUtils.getMovedIncludingString(file, destinationPath,
participateFile, value, selectedResource);
} else {
return MoveUtils.getMovedIncludedString(file, destinationPath,
value, selectedResource);
}
}
public boolean hasChanges() {
return groups.size() != 0;
}
public void updateChange(TextFileChange change) {
// check for empty changes
if (!hasChanges()) {
return;
}
addGroups(change, groups);
}
/**
* Adds the edit groups to an existing change
*
* @param change
* - the change that will be used as a container
* @param groups
* - the groups to add
*/
private final static void addGroups(TextFileChange change,
List<TextEditGroup> groups) {
assert change != null && groups != null;
TextEditChangeGroup[] textEditChangeGroups = change
.getTextEditChangeGroups();
OUTER: for (TextEditGroup editGroup : groups) {
TextEditChangeGroup textEditChangeGroup = new TextEditChangeGroup(
change, editGroup);
final TextEdit textEdit = editGroup.getTextEdits()[0];
for (TextEditChangeGroup existingTextEditChangeGroup : textEditChangeGroups) {
TextEdit existingTextEdit = existingTextEditChangeGroup
.getTextEdits()[0];
// avoid overlapping edits
if (existingTextEdit.getOffset() == textEdit.getOffset()) {
continue OUTER;
}
}
change.addTextEditChangeGroup(textEditChangeGroup);
change.addEdit(textEdit);
}
}
}