package japicmp.filter;

import japicmp.exception.JApiCmpException;
import japicmp.util.SignatureParser;
import javassist.CtBehavior;
import javassist.CtClass;
import javassist.CtField;

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

public class BehaviorFilter implements Filter {
    private final String filterString;
    private final Pattern classPattern;
    private final Pattern methodPattern;
    private final List<Pattern> parameterPatterns = new ArrayList<>();

    public BehaviorFilter(String filterString) {
        this.filterString = filterString;
        String regEx = filterString.replace(".", "\\.");
        regEx = regEx.replace("*", ".*");
        String[] parts = regEx.split("#");
        if (parts.length != 2) {
            throw new JApiCmpException(JApiCmpException.Reason.CliError, "Filter option '" + filterString + "' should not contain more than one '#'.");
        }
        classPattern = Pattern.compile(parts[0]);
        String methodPart = parts[1];
        int indexOpeningBracket = methodPart.indexOf('(');
        int indexClosingBracket = methodPart.indexOf(')');
        if (indexOpeningBracket == -1) {
            throw new JApiCmpException(JApiCmpException.Reason.CliError, "Filter option '" + filterString + "' should contain one opening '('.");
        }
        if (indexClosingBracket == -1) {
            throw new JApiCmpException(JApiCmpException.Reason.CliError, "Filter option '" + filterString + "' should contain one opening ')'.");
        }
        if (indexClosingBracket <= indexOpeningBracket) {
            throw new JApiCmpException(JApiCmpException.Reason.CliError, "Filter option '" + filterString + "' should contain first an opening '(' and then a closing ')'.");
        }
        if (indexOpeningBracket == 0) {
            throw new JApiCmpException(JApiCmpException.Reason.CliError, "Filter option '" + filterString + "' should contain at least one character before the opening '('.");
        }
        String methodName = methodPart.substring(0, indexOpeningBracket);
        methodPattern = Pattern.compile(methodName);
        String paramList = methodPart.substring(indexOpeningBracket + 1, indexClosingBracket);
        if (paramList.length() > 0) {
            String[] params = paramList.split(",");
            for (String param : params) {
                parameterPatterns.add(Pattern.compile(param));
            }
        }
    }

    @Override
    public boolean matches(CtClass ctClass) {
        String name = ctClass.getName();
        return classPattern.matcher(name).matches();
    }

    @Override
    public boolean matches(CtBehavior ctBehavior) {
        boolean classMatches = true;
        boolean methodMatches = true;
        boolean parameterMatches = true;
        CtClass declaringClass = ctBehavior.getDeclaringClass();
        String name = declaringClass.getName();
        if (!classPattern.matcher(name).matches()) {
            classMatches = false;
        }
        String methodName = ctBehavior.getName();
        if (!methodPattern.matcher(methodName).matches()) {
            methodMatches = false;
        }
        SignatureParser signatureParser = new SignatureParser();
        signatureParser.parse(ctBehavior.getSignature());
        List<String> parameters = signatureParser.getParameters();
        if (parameters.size() != parameterPatterns.size()) {
            parameterMatches = false;
        } else {
            for (int i = 0; i < parameters.size(); i++) {
                Pattern pattern = parameterPatterns.get(i);
                if (!pattern.matcher(parameters.get(i)).matches()) {
                    parameterMatches = false;
                }
            }
        }
        return (classMatches && methodMatches && parameterMatches);
    }

    @Override
    public boolean matches(CtField ctField) {
        return true;
    }

    @Override
    public String toString() {
        return this.filterString;
    }
}

@@ -18,16 +18,56 @@
 ilter;%0A%0A
+import com.google.common.base.Splitter;%0A
 import j
@@ -2316,47 +2316,97 @@
     
+for (
 String
-%5B%5D
  param
-s = paramList.split(%22,%22);
+ : Splitter.on(%22,%22).trimResults().omitEmptyStrings().split(paramList)) %7B
 %0A   
@@ -2418,37 +2418,48 @@
     
-for (String
+   
  param 
-:
+=
  param
-s) %7B
+.replaceAll(%22%5C%5Cs+%22,%22%22);
 %0A   

remove white space chars in parameter list of methods