package us.codecraft.webmagic.selector;

import org.apache.commons.lang3.StringUtils;

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

/**
 * Selector in regex.<br>
 *
 * @author code4crafter@gmail.com <br>
 * @since 0.1.0
 */
public class RegexSelector implements Selector {

    private String regexStr;

    private Pattern regex;

    private int group = 1;

    public RegexSelector(String regexStr, int group) {
        if (StringUtils.isBlank(regexStr)) {
            throw new IllegalArgumentException("regex must not be empty");
        }
        // Check bracket for regex group. Add default group 1 if there is no group.
        // Only check if there exists the valid left parenthesis, leave regexp validation for Pattern.
        if ( ! hasGroup(regexStr) ){
            regexStr = "(" + regexStr + ")";
        }
        this.regexStr = regexStr;
        try {
            regex = Pattern.compile(regexStr, Pattern.DOTALL | Pattern.CASE_INSENSITIVE);
        } catch (PatternSyntaxException e) {
            throw new IllegalArgumentException("invalid regex", e);
        }
        this.group = group;
    }

    public RegexSelector(String regexStr) {
        this(regexStr, 1);
    }

    private boolean hasGroup(String regexStr) {
        if (StringUtils.countMatches(regexStr, "(") - StringUtils.countMatches(regexStr, "\\(") ==
                StringUtils.countMatches(regexStr, "(?:") - StringUtils.countMatches(regexStr, "\\(?:")){
            return false;
        }
        if (StringUtils.countMatches(regexStr, "(") - StringUtils.countMatches(regexStr, "\\(") ==
                StringUtils.countMatches(regexStr, "(?=") - StringUtils.countMatches(regexStr, "\\(?=") ) {
            return false;
        }
        if (StringUtils.countMatches(regexStr, "(") - StringUtils.countMatches(regexStr, "\\(") ==
                StringUtils.countMatches(regexStr, "(?<") - StringUtils.countMatches(regexStr, "\\(?<") ) {
            return false;
        }
        if (StringUtils.countMatches(regexStr, "(") - StringUtils.countMatches(regexStr, "\\(") ==
                StringUtils.countMatches(regexStr, "(?!") - StringUtils.countMatches(regexStr, "\\(?!") ) {
            return false;
        }
        if (StringUtils.countMatches(regexStr, "(") - StringUtils.countMatches(regexStr, "\\(") ==
                StringUtils.countMatches(regexStr, "(?#") - StringUtils.countMatches(regexStr, "\\(?#") ) {
            return false;
        }
        return true;
    }

    @Override
    public String select(String text) {
        return selectGroup(text).get(group);
    }

    @Override
    public List<String> selectList(String text) {
        List<String> strings = new ArrayList<String>();
        List<RegexResult> results = selectGroupList(text);
        for (RegexResult result : results) {
            strings.add(result.get(group));
        }
        return strings;
    }

    public RegexResult selectGroup(String text) {
        Matcher matcher = regex.matcher(text);
        if (matcher.find()) {
            String[] groups = new String[matcher.groupCount() + 1];
            for (int i = 0; i < groups.length; i++) {
                groups[i] = matcher.group(i);
            }
            return new RegexResult(groups);
        }
        return RegexResult.EMPTY_RESULT;
    }

    public List<RegexResult> selectGroupList(String text) {
        Matcher matcher = regex.matcher(text);
        List<RegexResult> resultList = new ArrayList<RegexResult>();
        while (matcher.find()) {
            String[] groups = new String[matcher.groupCount() + 1];
            for (int i = 0; i < groups.length; i++) {
                groups[i] = matcher.group(i);
            }
            resultList.add(new RegexResult(groups));
        }
        return resultList;
    }

    @Override
    public String toString() {
        return regexStr;
    }

}

@@ -1358,35 +1358,39 @@
 Str) %7B%0A        i
-f (
+nt x = 
 StringUtils.coun
@@ -1448,35 +1448,33 @@
 regexStr, %22%5C%5C(%22)
- ==
+;
 %0A               
@@ -1458,39 +1458,39 @@
 %22%5C%5C(%22);%0A        
-       
+int a =
  StringUtils.cou
@@ -1565,404 +1565,130 @@
 ?:%22)
-)%7B%0A            return false;%0A        %7D%0A        if (StringUtils.countMatches(regexStr, %22(%22) - StringUtils.countMatches(regexStr, %22%5C%5C(%22) ==%0A                StringUtils.countMatches(regexStr, %22(?=%22) - StringUtils.countMatches(regexStr, %22%5C%5C(?=%22) ) %7B%0A            return false;%0A        %7D%0A        if (StringUtils.countMatches(regexStr, %22(%22) - StringUtils.countMatches(regexStr, %22%5C%5C(%22) ==%0A               
+;%0A        int b = StringUtils.countMatches(regexStr, %22(?=%22) - StringUtils.countMatches(regexStr, %22%5C%5C(?=%22);%0A        int c =
  Str
@@ -1771,20 +1771,17 @@
 %22%5C%5C(?%3C%22)
- ) %7B
+;
 %0A       
@@ -1785,48 +1785,16 @@
     
-    return false;%0A        %7D%0A        if (
+int d = 
 Stri
@@ -1818,32 +1818,34 @@
 hes(regexStr, %22(
+?!
 %22) - StringUtils
@@ -1872,32 +1872,30 @@
 tr, %22%5C%5C(
-%22) ==%0A  
+?!%22);%0A
         
       St
@@ -1878,37 +1878,39 @@
 %5C(?!%22);%0A        
-     
+int e =
  StringUtils.cou
@@ -1924,33 +1924,33 @@
 es(regexStr, %22(?
-!
+#
 %22) - StringUtils
@@ -1982,40 +1982,11 @@
 %5C%5C(?
-!
+#
 %22)
- ) %7B%0A            return false
 ;%0A  
@@ -1983,33 +1983,32 @@
 %5C(?#%22);%0A        
-%7D
 %0A        if (Str
@@ -2008,199 +2008,32 @@
 if (
-StringUtils.countMatches(regexStr, %22(%22) - StringUtils.countMatches(regexStr, %22%5C%5C(%22) ==%0A                StringUtils.countMatches(regexStr, %22(?#%22) - StringUtils.countMatches(regexStr, %22%5C%5C(?#%22) 
+x == (a + b + c + d + e)
 ) %7B%0A

Update RegexSelector.java