/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2015 Neil C Smith.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3 only, as
* published by the Free Software Foundation.
*
* This code 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 General Public License
* version 3 for more details.
*
* You should have received a copy of the GNU General Public License version 3
* along with this work; if not, see http://www.gnu.org/licenses/
*
*
* Please visit http://neilcsmith.net if you need additional information or
* have any questions.
*/
package net.neilcsmith.praxis.live.tracker;
import java.util.ArrayList;
import java.util.List;
import net.neilcsmith.praxis.core.ArgumentFormatException;
import net.neilcsmith.praxis.core.syntax.Token;
import net.neilcsmith.praxis.core.syntax.Tokenizer;
/**
*
* @author Neil C Smith (http://neilcsmith.net)
*/
class TrackerUtils {
static Patterns parse(String data) throws ArgumentFormatException {
Patterns patterns = new Patterns();
List<Object> row = new ArrayList<>();
Pattern pattern = null;
int maxColumn = 0;
int column = 0;
Tokenizer tk = new Tokenizer(data);
for (Token t : tk) {
Token.Type type = t.getType();
switch (type) {
case PLAIN:
case QUOTED:
case BRACED:
if (maxColumn > 0 && column >= maxColumn) {
throw new ArgumentFormatException();
}
row.add(type == Token.Type.PLAIN
? parsePlainToken(t.getText())
: t.getText());
column++;
break;
case EOL:
if (column > 0) {
// inside pattern
if (pattern == null) {
pattern = new Pattern();
pattern.setColumnCount(column);
maxColumn = column;
} else {
// pad to end of row
while (column < maxColumn) {
row.add(null);
column++;
}
}
pattern.addRow(row.toArray());
row.clear();
column = 0;
} else if (pattern != null) {
// end of pattern
patterns.addPattern(pattern);
pattern = null;
maxColumn = 0;
}
break;
case COMMENT:
break;
default:
throw new ArgumentFormatException();
}
}
if (pattern != null) {
patterns.addPattern(pattern);
}
return patterns;
}
static String write(Patterns data) {
StringBuilder sb = new StringBuilder();
write(data, sb);
return sb.toString();
}
static void write(Patterns data, StringBuilder sb) {
boolean first = true;
for (Pattern table : data) {
if (!first) {
sb.append('\n');
}
write(table, sb);
first = false;
}
}
static void write(Pattern data, StringBuilder sb) {
write(data, sb, 0, 0, data.getRowCount(), data.getColumnCount());
}
static void write(Pattern data, StringBuilder sb,
int rowOffset, int columnOffset, int rows, int columns) {
for (int r = 0; r < rows; r++) {
if (isEmpty(data, rowOffset + r, columnOffset, columnOffset + columns)) {
sb.append('.');
sb.append('\n');
} else {
boolean first = true;
for (int c = 0; c < columns; c++) {
Object obj = data.getValueAt(rowOffset + r, columnOffset + c);
if (!first) {
sb.append(' ');
}
sb.append(writeValue(obj));
first = false;
}
sb.append('\n');
}
}
}
private static String parsePlainToken(String token) {
if (".".equals(token)) {
return null;
} else {
return token;
}
}
private static String writeValue(Object value) {
if (value == null) {
return ".";
}
return escape(value.toString());
}
private static boolean isEmpty(Pattern data, int row, int start, int end) {
for (int i = start; i < end; i++) {
if (data.getValueAt(row, i) != null) {
return false;
}
}
return true;
}
private static String escape(String input) {
String res = escapePlain(input);
if (res == null) {
res = escapeQuoted(input);
}
return res;
}
private static String escapePlain(String input) {
int len = input.length();
if (len == 0) {
return null;
}
if (input.startsWith(".") || input.startsWith("#")) {
return null;
}
for (int i = 0; i < len; i++) {
char c = input.charAt(i);
if (Character.isLetterOrDigit(c)
|| c == '.' || c == '-' || c == '_' || c == '#') {
continue;
} else {
return null;
}
}
return input;
}
private static String escapeQuoted(String input) {
int len = input.length();
if (len == 0) {
return "\"\"";
}
StringBuilder sb = new StringBuilder(len * 2);
sb.append("\"");
for (int i = 0; i < len; i++) {
char c = input.charAt(i);
switch (c) {
case '{':
case '}':
case '[':
case ']':
sb.append('\\');
sb.append(c);
break;
case '\t':
sb.append("\\t");
break;
case '\n':
sb.append("\\n");
break;
case '\r':
sb.append("\\r");
break;
case '\"':
sb.append("\\\"");
break;
case '\\':
sb.append("\\\\");
break;
default:
sb.append(c);
}
}
sb.append("\"");
return sb.toString();
}
}