package org.nibor.autolink.internal;

import org.nibor.autolink.LinkSpan;
import org.nibor.autolink.LinkType;

/**
 * Scan for WWW addresses such as "www.example.org" starting from the trigger character "w".
 * Requires "www." at the beginning and an additional dot in the domain.
 * <p>
 * Based on RFC 3986.
 */
public class WwwScanner implements Scanner {

    @Override
    public LinkSpan scan(final CharSequence input, int triggerIndex, int rewindIndex) {
        final int afterDot = triggerIndex + 4;
        if (afterDot >= input.length() || !isWWW(input, triggerIndex)) {
            return null;
        }

        final int first = findFirst(input, triggerIndex, rewindIndex);
        if (first == -1) {
            return null;
        }
        
        int last = findLast(input, afterDot);
        if (last == -1) {
            return null;
        }

        return new LinkSpanImpl(LinkType.WWW, first, last + 1);
    }
    
    private static int findFirst(final CharSequence input, final int beginIndex, final int rewindIndex) {
        if (beginIndex == rewindIndex) {
            return beginIndex;
        }
        
        // Is the character before www. allowed?
        if (isAllowed(input.charAt(beginIndex - 1))) {
            return beginIndex;
        }
        
        return -1;
    }
    
    private static int findLast(final CharSequence input, final int beginIndex) {
        final int last = Scanners.findUrlEnd(input, beginIndex);
        
        // Make sure there is at least one dot after the first dot,
        // so www.something is not allowed, but www.something.co.uk is
        int pointer = last;
        while (--pointer > beginIndex) {
            if (input.charAt(pointer) == '.' && pointer > beginIndex) return last;
        }
        
        return -1;
    }
    
    private static boolean isAllowed(char c) {
        return c != '.' && !Scanners.isAlnum(c);
    }
    
    private static boolean isWWW(final CharSequence input, final int triggerIndex) {
        return 
                (input.charAt(triggerIndex + 1) == 'w')
             && (input.charAt(triggerIndex + 2) == 'w')
             &&  input.charAt(triggerIndex + 3) == '.';
    }
}

@@ -548,18 +548,18 @@
  %7C%7C !isW
-WW
+ww
 (input, 
@@ -740,33 +740,25 @@
 ;%0A        %7D%0A
-        
 %0A
+
         int 
@@ -915,37 +915,33 @@
 ast + 1);%0A    %7D%0A
-    
 %0A
+
     private stat
@@ -1108,33 +1108,25 @@
 ;%0A        %7D%0A
-        
 %0A
+
         // I
@@ -1254,33 +1254,25 @@
 ;%0A        %7D%0A
-        
 %0A
+
         retu
@@ -1276,37 +1276,33 @@
 eturn -1;%0A    %7D%0A
-    
 %0A
+
     private stat
@@ -1432,25 +1432,17 @@
 Index);%0A
-        
 %0A
+
         
@@ -1715,20 +1715,52 @@
 ex) 
-return last;
+%7B%0A                return last;%0A            %7D
 %0A   
@@ -1770,17 +1770,9 @@
   %7D%0A
-        
 %0A
+
     
@@ -1784,37 +1784,33 @@
 eturn -1;%0A    %7D%0A
-    
 %0A
+
     private stat
@@ -1895,20 +1895,16 @@
 ;%0A    %7D%0A
-    
 %0A    pri
@@ -1926,18 +1926,18 @@
 lean isW
-WW
+ww
 (final C
@@ -2000,26 +2000,8 @@
 urn 
-%0A                (
 inpu
@@ -2025,33 +2025,32 @@
 ndex + 1) == 'w'
-)
 %0A             &&
@@ -2051,12 +2051,14 @@
     
+   
 && 
-(
 inpu
@@ -2094,10 +2094,12 @@
  'w'
-)
 %0A
+   
     
@@ -2109,17 +2109,16 @@
       &&
- 
  input.c

Fix formatting