package com.github.therapi.runtimejavadoc.internal.parser;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.github.therapi.runtimejavadoc.Comment;
import com.github.therapi.runtimejavadoc.CommentElement;
import com.github.therapi.runtimejavadoc.CommentText;
import com.github.therapi.runtimejavadoc.InlineLink;
import com.github.therapi.runtimejavadoc.InlineTag;
import com.github.therapi.runtimejavadoc.Link;

class CommentParser {

    private static final Pattern inlineTag = Pattern.compile("\\{@(\\w+)\\s+(\\w[^}]+)\\}");

    private static final Pattern inlineTagSplitter = Pattern.compile("((?=(\\{@))|(?<=}))");

    private static final Pattern whitespace = Pattern.compile("\\s+");

    private static final Pattern linkRefSplitter = Pattern.compile("#");

    static Comment parse(String commentText) {
        String[] parts = inlineTagSplitter.split(commentText);

        List<CommentElement> elements = new ArrayList<>();
        for (String part : parts) {
            CommentElement elt = parseElement(part);

            if (elt instanceof CommentText) {
                CommentElement last = last(elements);
                if (last instanceof CommentText) {
                    CommentText merged = merge((CommentText) last, (CommentText) elt);
                    elements.set(elements.size() - 1, merged);
                    continue;
                }
            }

            elements.add(elt);
        }
        return new Comment(elements);
    }

    private static CommentElement parseElement(String elt) {
        Matcher matcher = inlineTag.matcher(elt);
        if (matcher.matches()) {
            return createTagElement(matcher.group(1), matcher.group(2));
        } else {
            return new CommentText(elt);
        }
    }

    private static CommentElement createTagElement(String name, String value) {
        if ("link".equals(name)) {
            return createLinkElement(value);
        }
        return new InlineTag(name, value);
    }

    private static InlineLink createLinkElement(String value) {
        String[] linkElts = whitespace.split(value, 2);
        String label = linkElts.length > 1 ? linkElts[1] : linkElts[0];

        String[] ref = linkRefSplitter.split(linkElts[0], 2);
        String classRef = ref[0];
        String memberRef = ref.length > 1 ? ref[1] : null;

        Link link = new Link(label, classRef, memberRef);
        return new InlineLink(link);
    }

    private static CommentElement last(List<CommentElement> elements) {
        if (elements.isEmpty()) {
            return null;
        }
        return elements.get(elements.size() - 1);
    }

    private static CommentText merge(CommentText left, CommentText right) {
        return new CommentText(left.getValue() + right.getValue());
    }
}

@@ -77,24 +77,54 @@
 .ArrayList;%0A
+import java.util.Collections;%0A
 import java.
@@ -626,105 +626,9 @@
 %7D%5D+)
-%5C%5C%7D%22);%0A%0A    private static final Pattern inlineTagSplitter = Pattern.compile(%22((?=(%5C%5C%7B@))%7C(?%3C=%7D))
+%7D
 %22);%0A
@@ -782,272 +782,311 @@
     
-static Comment parse(String commentText) %7B%0A        String%5B%5D parts = inlineTagSplitter.split(commentText);%0A%0A        List%3CCommentElement%3E elements = new ArrayList%3C%3E();%0A        for (String part : parts) %7B%0A            CommentElement elt = parseElement(part)
+private static final Comment EMPTY_COMMENT = new Comment(Collections.singletonList(new CommentText(%22%22)));%0A%0A    static Comment parse(String commentText) %7B%0A        if (commentText == null) %7B%0A            return null;%0A        %7D%0A        if (commentText.isEmpty()) %7B%0A            return EMPTY_COMMENT
 ;%0A
-%0A
         
     
@@ -1085,32 +1085,52 @@
     
+%7D%0A
     
-if (elt instanceof C
+    return new Comment(parseElements(c
 omme
@@ -1140,313 +1140,336 @@
 ext)
- %7B
+);
 %0A    
+%7D%0A%0A
     
-        CommentElement last = last(elements);%0A                if (last instanceof CommentText) %7B%0A                    CommentText merged = merge((CommentText) last, (CommentText) elt);%0A                    elements.set(elements.size() - 1, merged);%0A                    continue;%0A                %7D
+private static List%3CCommentElement%3E parseElements(String commentText) %7B%0A        Matcher matcher = inlineTag.matcher(commentText);%0A        List%3CCommentElement%3E elements = new ArrayList%3C%3E();%0A        int pos = 0;%0A        while (matcher.find()) %7B%0A            int start = matcher.start();%0A            if (start %3E pos) %7B
 %0A   
@@ -1477,23 +1477,16 @@
     
-    %7D%0A%0A
         
     
@@ -1481,20 +1481,16 @@
         
-    
 elements
@@ -1494,22 +1494,73 @@
 nts.add(
-elt);%0A
+new CommentText(commentText.substring(pos, start)));%0A    
         
@@ -1569,34 +1569,27 @@
         
-return new
+   
  Comment
 (element
@@ -1584,135 +1584,137 @@
 ment
-(e
+E
 lement
-s);%0A    %7D%0A%0A    private static CommentElement parseElement(String elt) %7B%0A        Matcher matcher = inlineTag.
+ elt = createTagElement(matcher.group(1), matcher.group(2));%0A            elements.add(elt);%0A            pos = 
 matcher
-(elt
+.end(
 );%0A 
@@ -1724,102 +1724,120 @@
     
-if (matcher.matches()) %7B%0A            return createTagElement(matcher.group(1), matcher.group(2
+%7D%0A%0A        if (pos %3C commentText.length()) %7B%0A            elements.add(new CommentText(commentText.substring(pos)
 ));%0A
@@ -1849,15 +1849,8 @@
    %7D
- else %7B
 %0A   
@@ -1858,50 +1858,24 @@
     
-    
 return 
-new CommentText(elt);%0A        %7D
+elements;
 %0A   
@@ -2551,356 +2551,7 @@
    %7D
-%0A%0A    private static CommentElement last(List%3CCommentElement%3E elements) %7B%0A        if (elements.isEmpty()) %7B%0A            return null;%0A        %7D%0A        return elements.get(elements.size() - 1);%0A    %7D%0A%0A    private static CommentText merge(CommentText left, CommentText right) %7B%0A        return new CommentText(left.getValue() + right.getValue());%0A    %7D
 %0A%7D%0A

Simplify CommentParser by properly using a regex Matcher