package kata.wordwrap.a20160813; import java.util.stream.Stream; /** * Word Wrap Kata. * Copyright (c) 2016, Peter Kofler, licensed under BSD License. */ public class WordWrapReduce { interface Paragraph { default Paragraph add(String word) { if (canAdd(word)) { return appendLine(word); } return newLineWith(word); } boolean canAdd(String word); Paragraph appendLine(String word); Paragraph newLineWith(String word); String get(); } private final int maxLineLen; public WordWrapReduce(int maxLineLen) { this.maxLineLen = maxLineLen; } public static String wrap(String line, int maxLineLen) { return new WordWrapReduce(maxLineLen).wrap(line); } private class MultiLineParagraph extends FirstLineParagraph { private static final char NEWLINE = '\n'; private final String wrappedParagraph; public MultiLineParagraph(String paragraph, String currentLine) { super(currentLine); this.wrappedParagraph = paragraph; } @Override public Paragraph appendLine(String word) { return new MultiLineParagraph(wrappedParagraph, super.appendLine(word).get()); } @Override public String get() { return wrappedParagraph + NEWLINE + super.get(); } } private class FirstLineParagraph implements Paragraph { private static final String BLANK = " "; private final String currentLine; public FirstLineParagraph(String word) { currentLine = word; } @Override public boolean canAdd(String word) { return currentLine.length() + BLANK.length() + word.length() <= maxLineLen; } @Override public Paragraph appendLine(String word) { return new FirstLineParagraph(currentLine + BLANK + word); } @Override public Paragraph newLineWith(String word) { return new MultiLineParagraph(get(), word); } @Override public String get() { return currentLine; } } private class EmptyParagraph implements Paragraph { @SuppressWarnings("unused") @Override public boolean canAdd(String word) { return true; } @Override public Paragraph appendLine(String word) { return new FirstLineParagraph(word); } @SuppressWarnings("unused") @Override public Paragraph newLineWith(String word) { throw new UnsupportedOperationException("cannot have a newline on empty paragraph"); } @Override public String get() { return ""; } } public String wrap(String line) { return Stream.of(everyWord(line)). // flatMap(this::splitLongWords). // reduce(new EmptyParagraph(), Paragraph::add, (p1, p2) -> p1). // get(); } private String[] everyWord(String line) { int allowTrailingBlanks = -1; return line.split(" ", allowTrailingBlanks); } private Stream splitLongWords(String word) { if (word.length() <= maxLineLen) { return Stream.of(word); } String part = word.substring(0, maxLineLen); String remaining = word.substring(maxLineLen); return Stream.concat(Stream.of(part), splitLongWords(remaining)); } }