/*
* Copyright 2015 Nokia Solutions and Networks
* Licensed under the Apache License, Version 2.0,
* see license.txt file for details.
*/
package org.robotframework.ide.eclipse.main.plugin.model.cmd.variables;
import static com.google.common.collect.Iterables.filter;
import java.util.List;
import java.util.Optional;
import org.rf.ide.core.testdata.model.table.VariableTable;
import org.rf.ide.core.testdata.model.table.variables.AVariable;
import org.rf.ide.core.testdata.model.table.variables.AVariable.VariableType;
import org.rf.ide.core.testdata.model.table.variables.DictionaryVariable;
import org.rf.ide.core.testdata.model.table.variables.DictionaryVariable.DictionaryKeyValuePair;
import org.rf.ide.core.testdata.model.table.variables.ListVariable;
import org.rf.ide.core.testdata.model.table.variables.ScalarVariable;
import org.rf.ide.core.testdata.model.table.variables.UnknownVariable;
import org.rf.ide.core.testdata.text.read.IRobotTokenType;
import org.rf.ide.core.testdata.text.read.recognizer.RobotToken;
import org.rf.ide.core.testdata.text.read.recognizer.RobotTokenType;
import org.robotframework.ide.eclipse.main.plugin.model.RobotModelEvents;
import org.robotframework.ide.eclipse.main.plugin.model.RobotVariable;
import org.robotframework.ide.eclipse.main.plugin.model.RobotVariablesSection;
import org.robotframework.ide.eclipse.main.plugin.tableeditor.EditorCommand;
import com.google.common.base.Predicate;
public class SetVariableNameCommand extends EditorCommand {
private final RobotVariable variable;
private final String newName;
private String previousName;
public SetVariableNameCommand(final RobotVariable variable, final String newName) {
this.variable = variable;
this.newName = newName == null || newName.isEmpty() ? "${}" : newName;
}
@Override
public void execute() throws CommandExecutionException {
final Optional<RobotToken> modifiedToken = modifyToken();
if (!modifiedToken.isPresent()) {
return;
}
final boolean typeHasChanged = typeChangeIsRequired();
if (typeHasChanged) {
final RobotVariablesSection section = variable.getParent();
final VariableTable table = section.getLinkedElement();
final AVariable newHolder = createProjectedVariable(modifiedToken);
final int index = table.getVariables().indexOf(variable.getLinkedElement());
table.removeVariable(variable.getLinkedElement());
table.addVariable(index, newHolder);
variable.setLinkedElement(newHolder);
}
variable.getLinkedElement().getType(); // in order to fix scalar to scalar as list
variable.getLinkedElement().setName(getNewHolderName());
if (typeHasChanged) {
eventBroker.send(RobotModelEvents.ROBOT_VARIABLE_TYPE_CHANGE, variable);
}
eventBroker.send(RobotModelEvents.ROBOT_VARIABLE_NAME_CHANGE, variable);
}
private AVariable createProjectedVariable(final Optional<RobotToken> modifiedToken) {
final List<RobotToken> elementTokens = variable.getLinkedElement().getElementTokens();
final Iterable<RobotToken> valueTokens = filter(elementTokens,
containingOneOf(RobotTokenType.VARIABLES_VARIABLE_VALUE));
final AVariable newHolder;
switch (getProjectedType()) {
case SCALAR:
newHolder = createScalarHolder(modifiedToken, valueTokens);
break;
case LIST:
newHolder = createListHolder(modifiedToken, valueTokens);
break;
case DICTIONARY:
newHolder = createDictHolder(modifiedToken, valueTokens);
break;
default:
newHolder = createUnknownHolder(modifiedToken, valueTokens);
break;
}
final Iterable<RobotToken> commentTokens = filter(elementTokens, containingOneOf(
RobotTokenType.START_HASH_COMMENT, RobotTokenType.COMMENT_CONTINUE));
for (final RobotToken commentToken : commentTokens) {
newHolder.addCommentPart(commentToken);
}
return newHolder;
}
private ScalarVariable createScalarHolder(final Optional<RobotToken> modifiedToken,
final Iterable<RobotToken> valueTokens) {
final ScalarVariable scalarHolder = new ScalarVariable(getNewHolderName(), modifiedToken.get(),
variable.getLinkedElement().getScope());
for (final RobotToken valueToken : valueTokens) {
scalarHolder.addValue(valueToken);
}
return scalarHolder;
}
private ListVariable createListHolder(final Optional<RobotToken> modifiedToken,
final Iterable<RobotToken> valueTokens) {
final ListVariable listHolder = new ListVariable(getNewHolderName(), modifiedToken.get(),
variable.getLinkedElement().getScope());
for (final RobotToken valueToken : valueTokens) {
listHolder.addItem(valueToken);
}
return listHolder;
}
private DictionaryVariable createDictHolder(final Optional<RobotToken> modifiedToken,
final Iterable<RobotToken> valueTokens) {
final DictionaryVariable dictHolder = new DictionaryVariable(getNewHolderName(), modifiedToken.get(),
variable.getLinkedElement().getScope());
for (final RobotToken valueToken : valueTokens) {
final DictionaryKeyValuePair keyValuePair = DictionaryKeyValuePair.createFromRaw(valueToken.getText());
dictHolder.put(keyValuePair.getRaw(), keyValuePair.getKey(), keyValuePair.getValue());
}
return dictHolder;
}
private UnknownVariable createUnknownHolder(final Optional<RobotToken> modifiedToken,
final Iterable<RobotToken> valueTokens) {
final UnknownVariable unknownHolder = new UnknownVariable(getNewHolderName(), modifiedToken.get(),
variable.getLinkedElement().getScope());
for (final RobotToken valueToken : valueTokens) {
unknownHolder.addItem(valueToken);
}
return unknownHolder;
}
private static Predicate<RobotToken> containingOneOf(final RobotTokenType... types) {
return new Predicate<RobotToken>() {
@Override
public boolean apply(final RobotToken token) {
for (final RobotTokenType type : types) {
if (token.getTypes().contains(type)) {
return true;
}
}
return false;
}
};
}
private Optional<RobotToken> modifyToken() {
final RobotToken declaringToken = variable.getLinkedElement().getDeclaration();
previousName = declaringToken.getText();
if (previousName.equals(newName)) {
return Optional.empty();
}
declaringToken.setRaw(newName);
declaringToken.setText(newName);
declaringToken.setType(getDeclaringTokenType());
return Optional.of(declaringToken);
}
private IRobotTokenType getDeclaringTokenType() {
if (newName.startsWith(VariableType.SCALAR.getIdentificator() + "{") && newName.endsWith("}")) {
return RobotTokenType.VARIABLES_SCALAR_DECLARATION;
} else if (newName.startsWith(VariableType.LIST.getIdentificator() + "{") && newName.endsWith("}")) {
return RobotTokenType.VARIABLES_LIST_DECLARATION;
} else if (newName.startsWith(VariableType.DICTIONARY.getIdentificator() + "{") && newName.endsWith("}")) {
return RobotTokenType.VARIABLES_DICTIONARY_DECLARATION;
}
return RobotTokenType.VARIABLES_UNKNOWN_DECLARATION;
}
private boolean typeChangeIsRequired() {
final VariableType projectedType = getProjectedType();
return variable.getType() != projectedType
&& !(variable.getType() == VariableType.SCALAR_AS_LIST && projectedType == VariableType.SCALAR);
}
private VariableType getProjectedType() {
if (newName.isEmpty()) {
return VariableType.INVALID;
}
final VariableType projectedType = VariableType.getTypeByChar(newName.charAt(0));
return projectedType == null || !newName.endsWith("}") ? VariableType.INVALID : projectedType;
}
private String getNewHolderName() {
return getProjectedType() == VariableType.INVALID ? newName : newName.substring(2, newName.length() - 1);
}
@Override
public List<EditorCommand> getUndoCommands() {
return newUndoCommands(new SetVariableNameCommand(variable, previousName));
}
}