/*
Copyright (C) 2013 Raquel Pau and Albert Coroleu.
Walkmod is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Walkmod is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with Walkmod. If not, see <http://www.gnu.org/licenses/>.*/
package org.walkmod.javalang.actions;
import java.io.File;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import org.walkmod.javalang.util.FileUtils;
public class ActionsApplier {
private String text;
private List<Action> actions;
private StringBuffer modifiedText;
private Character indentationChar = null;
private boolean annotationsInNewLines = false;
public boolean isAnnotationsInNewLines() {
return annotationsInNewLines;
}
public void setAnnotationsInNewLines(boolean annotationsInNewLines) {
this.annotationsInNewLines = annotationsInNewLines;
}
public void setText(String text) {
this.text = text;
}
public void setText(File file) {
try {
this.text = FileUtils.fileToString(file.getAbsolutePath());
} catch (Exception e) {
throw new RuntimeException("Error reading the file " + file.getAbsolutePath());
}
}
public void setActionList(List<Action> actions) {
this.actions = actions;
}
public String getModifiedText() {
return modifiedText.toString();
}
public Character getIndentationChar() {
return indentationChar;
}
public void inferIndentationChar(char[] contents) {
if (indentationChar == null) {
indentationChar = getIndentationChar(contents, '\n');
if (indentationChar == null) {
indentationChar = getIndentationChar(contents, '{');
if (indentationChar == null) {
indentationChar = '\0';
}
}
}
}
private Character getIndentationChar(char[] contents, char separator) {
int spaces = 0;
int tabs = 0;
boolean containsSeparator = false;
for (int i = 0; i < contents.length; i++) {
if (contents[i] == separator) {
containsSeparator = true;
if (i + 1 < contents.length) {
if (contents[i + 1] == ' ') {
spaces++;
} else if (contents[i + 1] == '\t') {
tabs++;
}
}
}
}
if (tabs > spaces) {
return '\t';
} else {
if (!containsSeparator) {
return null;
} else if (spaces == 0 && spaces == tabs) {
return '\0';
}
return ' ';
}
}
public void execute() {
modifiedText = new StringBuffer();
if (actions != null && text != null) {
Iterator<Action> it = actions.iterator();
char[] contents = text.toCharArray();
int index = 0;
int line = 0;
int actionColumn = 0;
Action previousAction = null;
StringBuffer accum = null;
StringBuffer indentation = new StringBuffer();
while (it.hasNext()) {
Action next = it.next();
int actionLine = next.getBeginLine() - 1;
if (previousAction != null && previousAction.getType().equals(ActionType.REMOVE)
&& next.getType().equals(ActionType.APPEND)) {
accum = modifiedText;
modifiedText = new StringBuffer();
}
// the cursor is moved to the line
for (int i = line; i < actionLine; i++) {
boolean endLine = false;
while (index < contents.length && !endLine) {
endLine = contents[index] == '\n';
modifiedText.append(contents[index]);
index++;
if (endLine) {
line++;
actionColumn = 0;
if(indentation.length() != 0){
indentation = new StringBuffer();
}
}
}
}
// the cursor is moved to the column
if (index < contents.length) {
int incr = next.getBeginColumn() - 1 - actionColumn;
boolean stop = false;
if (incr > 0) {
for (int i = index; i < index + incr; i++) {
if(!stop && (contents[i] == ' ' || contents[i] == '\t')){
indentation.append(contents[i]);
}
else{
stop = true;
}
modifiedText.append(contents[i]);
actionColumn++;
}
index = index + incr;
}
if (previousAction != null && previousAction.getType().equals(ActionType.REMOVE)
&& next.getType().equals(ActionType.APPEND)) {
if (modifiedText.toString().trim().length() != 0) {
accum.append(modifiedText);
}
modifiedText = accum;
}
if (next.getType().equals(ActionType.REMOVE)) {
RemoveAction remove = (RemoveAction) next;
int lastLine = modifiedText.lastIndexOf("\n");
String aux = modifiedText.substring(lastLine + 1);
for (; (actionLine < (remove.getEndLine() - 1) || (actionLine == (remove.getEndLine() - 1)
&& actionColumn < remove.getEndColumn())); index++) {
if (contents[index] == '\r') {
actionColumn++;
} else if (contents[index] != '\n') {
actionColumn++;
} else {
actionLine++;
line++;
actionColumn = 0;
}
}
if (index < contents.length && contents[index] == '\r') {
index++;
actionColumn++;
}
boolean nextIsNewLine = (index < contents.length && contents[index] == '\n');
if (nextIsNewLine) {
index++;
line++;
actionColumn = 0;
if (remove.getBeginColumn() > 1) {
List<Character> chars = new LinkedList<Character>();
while (index < contents.length && (contents[index] == ' ' || contents[index] == '\t')) {
chars.add(contents[index]);
actionColumn++;
index++;
}
if (actionColumn + 1 > 1 && actionColumn + 1 < remove.getBeginColumn()) {
if (aux.matches("\\s+") || aux.equals("")) {
if (!"".equals(aux)) {
modifiedText = modifiedText.delete(lastLine + 1, modifiedText.length());
}
} else {
modifiedText.append('\n');
}
for (int k = 0; k < actionColumn; k++) {
modifiedText.append(chars.get(k));
}
} else if (actionColumn + 1 > remove.getBeginColumn()) {
for (int k = remove.getBeginColumn(); k < actionColumn + 1; k++) {
modifiedText.append(chars.get(k - remove.getBeginColumn()));
}
}
else if(actionColumn == 0 && (aux.matches("\\s+") || "".equals(aux))){
modifiedText = modifiedText.delete(lastLine + 1, modifiedText.length());
}
}
}
} else if (next.getType().equals(ActionType.APPEND)) {
inferIndentationChar(contents);
AppendAction append = (AppendAction) next;
char indent = indentationChar;
if(indentation.length() > 1){
indent = indentation.charAt(indentation.length()-1);
}
String code = append.getText(indentation.toString(), indent);
modifiedText.append(code);
} else if (next.getType().equals(ActionType.REPLACE)) {
inferIndentationChar(contents);
char indent = indentationChar;
if(indentation.length() > 1){
indent = indentation.charAt(indentation.length()-1);
}
ReplaceAction replace = (ReplaceAction) next;
String code = replace.getText(indentation.toString(), indent);
modifiedText.append(code);
int futureLine = replace.getOldEndLine() - 1;
// we need to update the index cursor according the old
// value
for (; actionLine < futureLine && index < contents.length; index++) {
if (contents[index] == '\r' || contents[index] != '\n') {
actionColumn++;
} else {
actionLine++;
actionColumn = 0;
}
}
line = futureLine;
index += (replace.getOldEndColumn() - actionColumn);
actionColumn = replace.getOldEndColumn();
}
}
previousAction = next;
}
for (int i = index; i < contents.length; i++) {
modifiedText.append(contents[i]);
}
}
}
}