package com.fsck.k9.message.html;


import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import android.text.TextUtils;


public class UriLinkifier {
    private static final Pattern URI_SCHEME;
    private static final Map<String, UriParser> SUPPORTED_URIS;
    private static final String SCHEME_SEPARATOR = " (";

    static {
        SUPPORTED_URIS = new HashMap<>();
        SUPPORTED_URIS.put("bitcoin:", new BitcoinUriParser());
        UriParser httpParser = new HttpUriParser();
        SUPPORTED_URIS.put("http:", httpParser);
        SUPPORTED_URIS.put("https:", httpParser);
        SUPPORTED_URIS.put("rtsp:", httpParser);

        String allSchemes = TextUtils.join("|", SUPPORTED_URIS.keySet());
        URI_SCHEME = Pattern.compile(allSchemes, Pattern.CASE_INSENSITIVE);
    }


    public static void linkifyText(String text, StringBuffer outputBuffer) {
        int currentPos = 0;
        Matcher matcher = URI_SCHEME.matcher(text);

        while (matcher.find(currentPos)) {
            int startPos = matcher.start();

            String textBeforeMatch = text.substring(currentPos, startPos);
            outputBuffer.append(textBeforeMatch);

            if (!isPrecededByValidSeparator(textBeforeMatch)) {
                outputBuffer.append(text.charAt(startPos));
                currentPos = startPos + 1;
                continue;
            }

            String scheme = matcher.group().toLowerCase(Locale.US);
            UriParser parser = SUPPORTED_URIS.get(scheme);
            int newPos = parser.linkifyUri(text, startPos, outputBuffer);

            boolean uriWasNotLinkified = newPos <= startPos;
            if (uriWasNotLinkified) {
                outputBuffer.append(text.charAt(startPos));
                currentPos = startPos + 1;
            } else {
                currentPos = (newPos > currentPos) ? newPos : currentPos + 1;
            }

            if (currentPos >= text.length()) {
                break;
            }
        }

        String textAfterLastMatch = text.substring(currentPos);
        outputBuffer.append(textAfterLastMatch);
    }

    private static boolean isPrecededByValidSeparator(String textBeforeMatch) {
        if (textBeforeMatch.isEmpty()) {
            return true;
        }

        String characterBeforeMatch = textBeforeMatch.substring(textBeforeMatch.length() - 1);
        return SCHEME_SEPARATOR.contains(characterBeforeMatch);
    }
}

@@ -389,16 +389,17 @@
 ATOR
+S
  = %22 (%22;
 %0A%0A  
@@ -394,16 +394,114 @@
  = %22 (%22;
+%0A    private static final String ALLOWED_SEPARATORS_PATTERN = %22(?:%5E%7C%5B%22 + SCHEME_SEPARATORS + %22%5D)%22;
 %0A%0A    st
@@ -884,24 +884,102 @@
 .keySet());%0A
+        String pattern = ALLOWED_SEPARATORS_PATTERN + %22(%22 + allSchemes + %22)%22;%0A
         URI_
@@ -1003,26 +1003,23 @@
 compile(
-allSchemes
+pattern
 , Patter
@@ -1289,16 +1289,17 @@
 r.start(
+1
 );%0A%0A    
@@ -1424,216 +1424,8 @@
 );%0A%0A
-            if (!isPrecededByValidSeparator(textBeforeMatch)) %7B%0A                outputBuffer.append(text.charAt(startPos));%0A                currentPos = startPos + 1;%0A                continue;%0A            %7D%0A%0A
     
@@ -1462,16 +1462,17 @@
 r.group(
+1
 ).toLowe
@@ -2094,24 +2094,24 @@
 urrentPos);%0A
+
         outp
@@ -2156,330 +2156,7 @@
    %7D
-%0A%0A    private static boolean isPrecededByValidSeparator(String textBeforeMatch) %7B%0A        if (textBeforeMatch.isEmpty()) %7B%0A            return true;%0A        %7D%0A%0A        String characterBeforeMatch = textBeforeMatch.substring(textBeforeMatch.length() - 1);%0A        return SCHEME_SEPARATOR.contains(characterBeforeMatch);%0A    %7D
 %0A%7D%0A

Use regexp to skip schema matches not preceded by allowed separator