package com.openfarmanager.android.model;
import com.openfarmanager.android.App;
import com.openfarmanager.android.filesystem.actions.RootTask;
import com.openfarmanager.android.utils.FileUtilsExt;
import org.apache.commons.io.IOCase;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.concurrent.Callable;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Holder for <code>Viewer</code> text. Text is represented by list of strings.
* Text is originally initialized in 2 copies: one to be modified (after replace or in 'edit' mode)
* and another to be immutable, so we can check is text changed.
*/
public class ViewerTextBuffer implements TextBuffer {
private ArrayList<String> mNumberOfLines;
private ArrayList<String> mOriginalLines;
private StringBuilder mTempBuilder;
public ViewerTextBuffer() {
mNumberOfLines = new ArrayList<String>();
mTempBuilder = new StringBuilder();
}
@Override
public String getLine(int lineNumber) {
return mNumberOfLines.get(lineNumber);
}
@Override
public ArrayList<String> getTextLines() {
return mNumberOfLines;
}
@Override
public void setLine(int lineNumber, String text) {
try {
mNumberOfLines.set(lineNumber, text);
} catch (IndexOutOfBoundsException ignore) {} // some unpredictable cases
}
@Override
public void appendEmptyLine() {
mNumberOfLines.add("");
}
@Override
public int size() {
return mNumberOfLines.size();
}
public boolean isTextChanged() {
for (int i = 0; i < mNumberOfLines.size(); i++) {
String string = mNumberOfLines.get(i);
try {
String originalString = mOriginalLines.get(i);
if (!originalString.equals(string)) {
return true;
}
} catch (IndexOutOfBoundsException e) {
return true;
}
}
return false;
}
@Override
public void swapData(ArrayList<String> strings) {
mNumberOfLines = strings;
mOriginalLines = new ArrayList<String>(mNumberOfLines);
Collections.copy(mOriginalLines, mNumberOfLines);
}
public void syncStringLists() {
mNumberOfLines = new ArrayList<String>(mOriginalLines);
Collections.copy(mNumberOfLines, mOriginalLines);
}
public void replace(String pattern, String replaceTo,
IOCase caseSensitive, boolean wholeWords, boolean regularExpression) {
Pattern patternMatch = FileUtilsExt.createWordSearchPattern(pattern, wholeWords, caseSensitive);
int i = 0;
for (String line : mNumberOfLines) {
String text = line;
Matcher matcher = patternMatch.matcher(text);
if (matcher.find()) {
int firstOccurrence;
int replacement = 0;
int delta = pattern.length() - replaceTo.length();
do {
firstOccurrence = matcher.start();
text = replaceText(text, pattern, replaceTo, firstOccurrence - replacement);
replacement += delta;
} while (matcher.find());
}
mNumberOfLines.set(i++, text);
}
}
public void saveToFile(File file) throws IOException {
saveToFile(new FileOutputStream(file));
}
public void saveToFile(OutputStream stream) throws IOException {
if (!isTextChanged()) {
return;
}
BufferedWriter writer = null;
try {
String charset = App.sInstance.getSettings().getDefaultCharset();
String encoding = charset != null ? charset : Charset.defaultCharset().name();
writer = new BufferedWriter(new OutputStreamWriter(stream, encoding));
for (String string : mNumberOfLines) {
writer.write(string);
writer.newLine();
}
} finally {
if (writer != null) {
try {
writer.flush();
writer.close();
} catch (Exception ignore) { }
}
}
}
public void saveToFileRoot(File file) throws IOException {
if (!isTextChanged()) {
return;
}
try {
StringBuilder resultString = new StringBuilder();
for (String string : mNumberOfLines) {
resultString.append(string).append("//\n");
}
RootTask.saveFile(file, resultString.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
public void save(OutputStream stream) throws IOException {
saveToFile(stream);
syncStringLists();
}
public void save(File file) throws IOException {
if(file.canWrite()) {
saveToFile(file);
} else {
saveToFileRoot(file);
}
syncStringLists();
}
private String replaceText(String text, String pattern, String replaceTo, int firstOccurrence) {
mTempBuilder.delete(0, mTempBuilder.length());
return mTempBuilder.append(text.substring(0, firstOccurrence)).
append(replaceTo).
append(text.substring(firstOccurrence + pattern.length())).toString();
}
}