package org.xpect.text;
import java.util.List;
import com.google.common.base.Joiner;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
public abstract class Canvas implements ICanvas {
protected static class RenderContext implements IRenderContext {
private int columns;
private int left;
private int lines;
private final Canvas parent;
private int top;
protected RenderContext(Canvas parent) {
super();
this.parent = parent;
this.lines = parent.getLineCount();
this.columns = parent.getColumnCount();
}
public IRenderContext at(int line, int column) {
int parentLines = parent.getLineCount();
int parentColumns = parent.getColumnCount();
Preconditions.checkArgument(line >= 0);
Preconditions.checkArgument(column >= 0);
Preconditions.checkArgument(line < parentLines);
Preconditions.checkArgument(column < parentColumns);
this.top = line;
this.left = column;
this.lines = Math.min(parentLines - line, this.lines);
this.columns = Math.min(parentColumns - column, this.columns);
return this;
}
public void fill(Object value) {
List<String> block = TextBlock.get(value).getLines();
char background = parent.getBackground();
int blockLenght = 0;
for (String b : block) {
int l = b.length();
if (l > blockLenght)
blockLenght = l;
}
List<String> padded = Lists.newArrayList();
for (String b : block) {
StringBuilder chunk = new StringBuilder(blockLenght);
chunk.append(b);
while (chunk.length() < blockLenght)
chunk.append(background);
StringBuilder line = new StringBuilder(this.columns);
while (line.length() < this.columns)
line.append(chunk);
padded.add(line.toString());
}
List<String> full = Lists.newArrayList();
while (full.size() < this.lines)
full.addAll(padded);
parent.print(top, left, lines, columns, full);
}
public ICanvas newSubCanvas() {
return new SubCanvas(parent, top, left, columns, lines);
}
public void print(Object value) {
ITextBlock block = TextBlock.get(value);
parent.print(top, left, lines, columns, block.getLines());
}
public IRenderContext withBounds(int maxLines, int maxColumns) {
Preconditions.checkArgument(maxLines > 0);
Preconditions.checkArgument(maxColumns > 0);
Preconditions.checkArgument(maxLines + top <= parent.getLineCount());
Preconditions.checkArgument(maxColumns + left <= parent.getColumnCount());
this.lines = maxLines;
this.columns = maxColumns;
return this;
}
}
protected static class RootCanvas extends Canvas {
private final Character background;
private final List<StringBuilder> document = Lists.newArrayList();
private final String lineSeparator;
protected RootCanvas() {
this(' ');
}
protected RootCanvas(Character background) {
this(background, "\n");
}
protected RootCanvas(Character background, String lineSeparator) {
super();
this.background = background;
this.lineSeparator = lineSeparator;
}
@Override
protected char getBackground() {
return background;
}
protected void print(int line, int column, int maxLines, int maxColumns, List<String> strings) {
int lineCount = Math.min(strings.size(), maxLines);
for (int i = document.size(); i < line + lineCount; i++)
document.add(new StringBuilder());
for (int i = 0; i < lineCount; i++) {
StringBuilder l = document.get(line + i);
String s = strings.get(i);
if (s.length() > maxColumns)
s = s.substring(0, maxColumns);
int length = l.length();
int end = column + s.length();
if (length < end)
l.setLength(end);
for (int j = length; j < column; j++)
l.setCharAt(j, background);
l.replace(column, end, s);
}
}
@Override
public String toString() {
return Joiner.on(lineSeparator).join(document);
}
}
protected static class SubCanvas extends Canvas {
private final int columns;
private final int left;
private final int lines;
private final Canvas parent;
private final int top;
protected SubCanvas(Canvas parent, int top, int left, int columns, int rows) {
super();
this.parent = parent;
this.top = top;
this.left = left;
this.columns = columns;
this.lines = rows;
}
@Override
protected char getBackground() {
return parent.getBackground();
}
public int getColumnCount() {
return columns;
}
public int getLineCount() {
return lines;
}
public ICanvas newSubCanvas() {
return new SubCanvas(parent, top, left, columns, lines);
}
@Override
protected void print(int line, int column, int maxLines, int maxColumns, List<String> strings) {
parent.print(line + top, column + left, maxLines, maxColumns, strings);
}
}
public static ICanvas create() {
return new RootCanvas();
}
public static ICanvas create(char backgroud) {
return new RootCanvas(backgroud);
}
public static ICanvas create(char backgroud, String lineSeparator) {
return new RootCanvas(backgroud, lineSeparator);
}
public IRenderContext at(int line, int column) {
return new RenderContext(this).at(line, column);
}
public void fill(Object value) {
new RenderContext(this).fill(value);
}
protected abstract char getBackground();
public int getColumnCount() {
return Integer.MAX_VALUE;
}
public int getLineCount() {
return Integer.MAX_VALUE;
}
public ICanvas newSubCanvas() {
return new SubCanvas(this, 0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE);
}
protected abstract void print(int line, int column, int maxLines, int maxColumns, List<String> strings);
public void print(Object value) {
new RenderContext(this).print(value);
}
public IRenderContext withBounds(int maxLines, int maxColumns) {
return new RenderContext(this).withBounds(maxLines, maxColumns);
}
}