package md2html;
import java.util.ArrayList;
import java.util.List;
import markup.*;
public class PrimePartCreator {
private final String block;
private int currentChar;
public enum MarkdownToken {
WORD,
EMPHASIS_STAR,
STRONG_STAR,
EMPHASIS_UNDERLINE,
STRONG_UNDERLINE,
STRIKEOUT,
CODE,
SCREENING,
NOTHING,
}
public PrimePartCreator(String block) {
this.block = block;
currentChar = 0;
}
public PrimePart createPart() {
PrimePart result;
if (isHeader()) {
int levelOfHeader = 0;
while (
levelOfHeader < block.length() &&
block.charAt(levelOfHeader) == '#'
) {
levelOfHeader++;
}
currentChar = levelOfHeader + 1;
result = new Header(buildPart(MarkdownToken.WORD), levelOfHeader);
} else {
currentChar = 0;
result = new Paragraph(buildPart(MarkdownToken.WORD));
}
return result;
}
private List buildPart(MarkdownToken currentToken) {
List items = new ArrayList<>();
MarkdownToken token = nextMarkdownToken();
StringBuilder sb = new StringBuilder();
while (token != MarkdownToken.NOTHING) {
if (
(token == currentToken && currentToken != MarkdownToken.WORD) ||
isSuffix(currentToken)
) {
addToList(items, sb);
if (
!(token == currentToken &&
currentToken != MarkdownToken.WORD)
) {
currentChar++;
}
break;
}
switch (token) {
case STRIKEOUT -> {
addToList(items, sb);
Strikeout strikeout = new Strikeout(buildPart(token));
items.add(strikeout);
}
case STRONG_STAR, STRONG_UNDERLINE -> {
addToList(items, sb);
Strong strong = new Strong(buildPart(token));
items.add(strong);
}
case EMPHASIS_STAR, EMPHASIS_UNDERLINE -> {
addToList(items, sb);
Emphasis emphasis = new Emphasis(buildPart(token));
items.add(emphasis);
}
case SCREENING -> {
addToList(items, sb);
items.add(
new Text(String.valueOf(block.charAt(currentChar)))
);
currentChar++;
}
case CODE -> {
addToList(items, sb);
Code code = new Code(buildPart(token));
items.add(code);
}
default -> {
if (currentChar < block.length()) {
if (block.charAt(currentChar) == '<') {
sb.append("<");
} else if (block.charAt(currentChar) == '>') {
sb.append(">");
} else if (block.charAt(currentChar) == '&') {
sb.append("&");
} else {
sb.append(block.charAt(currentChar));
}
currentChar++;
}
}
}
token = nextMarkdownToken();
}
if (token == MarkdownToken.NOTHING) {
addToList(items, sb);
}
return items;
}
private MarkdownToken nextMarkdownToken() {
if (currentChar == block.length()) {
return MarkdownToken.NOTHING;
}
switch (block.charAt(currentChar)) {
case '*' -> {
if (isPrefix("**")) {
currentChar += 2;
return MarkdownToken.STRONG_STAR;
} else if (isPrefix("*")) {
currentChar += 1;
return MarkdownToken.EMPHASIS_STAR;
}
}
case '_' -> {
if (isPrefix("__")) {
currentChar += 2;
return MarkdownToken.STRONG_UNDERLINE;
} else if (isPrefix("_")) {
currentChar += 1;
return MarkdownToken.EMPHASIS_UNDERLINE;
}
}
case '-' -> {
if (isPrefix("--")) {
currentChar += 2;
return MarkdownToken.STRIKEOUT;
}
}
case '`' -> {
if (isPrefix("`")) {
currentChar += 1;
return MarkdownToken.CODE;
}
}
case '\\' -> {
if (isScreening(block.charAt(currentChar + 1))) {
currentChar++;
return MarkdownToken.SCREENING;
}
}
default -> {
return MarkdownToken.WORD;
}
}
return MarkdownToken.WORD;
}
private static boolean isScreening(char ch) {
return ch == '*' || ch == '_';
}
private boolean isSuffix(MarkdownToken token) {
if (token == MarkdownToken.WORD) {
return false;
}
String suffix = getHighlight(token);
if (isWordInBlock(suffix, currentChar, currentChar + suffix.length())) {
currentChar += suffix.length() - 1;
return true;
}
return false;
}
private boolean isPrefix(String prefix) {
int i = currentChar + prefix.length();
return (
isValidIndexInBlock(i + prefix.length()) &&
!isWordInBlock(prefix, i, i + prefix.length()) &&
isWordInBlock(prefix, i - prefix.length(), i) &&
!Character.isWhitespace(block.charAt(i))
);
}
private boolean isWordInBlock(String word, int start, int end) {
return word.equals(block.substring(start, end));
}
private boolean isValidIndexInBlock(int index) {
return index < block.length();
}
private boolean isHeader() {
int levelOfHeader = 0;
if (block.charAt(levelOfHeader) != '#') {
return false;
}
while (
levelOfHeader < block.length() && block.charAt(levelOfHeader) == '#'
) {
levelOfHeader++;
}
return (
levelOfHeader < block.length() &&
Character.isWhitespace(block.charAt(levelOfHeader))
);
}
private static String getHighlight(MarkdownToken token) {
switch (token) {
case STRONG_STAR -> {
return "**";
}
case STRONG_UNDERLINE -> {
return "__";
}
case EMPHASIS_STAR -> {
return "*";
}
case EMPHASIS_UNDERLINE -> {
return "_";
}
case CODE -> {
return "`";
}
case STRIKEOUT -> {
return "--";
}
case SCREENING -> {
return "\\";
}
default -> {
return "";
}
}
}
private static void addToList(
List items,
StringBuilder sb
) {
if (!sb.isEmpty()) {
items.add(new Text(sb.toString()));
sb.setLength(0);
}
}
}