package com.github.petrovich4j;

public class Petrovich {

    private final RuleSet firstNameRules;
    private final RuleSet lastNameRules;
    private final RuleSet patronymicNameRules;

    public Petrovich() {
        this(Library.FIRST_NAME_RULES, Library.LAST_NAME_RULES, Library.PATRONYMIC_NAME_RULES);
    }

    public Petrovich(RuleSet firstNameRules, RuleSet lastNameRules, RuleSet patronymicNameRules) {
        if (firstNameRules == null || lastNameRules == null || patronymicNameRules == null) {
            throw new IllegalArgumentException("Rule set is null! First:" + firstNameRules + ", last:" + lastNameRules + ", patronymic: " + patronymicNameRules);
        }
        this.firstNameRules = firstNameRules;
        this.lastNameRules = lastNameRules;
        this.patronymicNameRules = patronymicNameRules;
    }

    public String say(String name, NameType type, Gender gender, Case cas) {
        if (name == null || name.isEmpty()) { // do not force caller to check every name it asks.
            return null;
        }
        if (type == null || gender == null || cas == null) { // configuration parameters must always be set up correctly.
            throw new IllegalArgumentException("Not all required parameters are set! Type: " + type + ", gender:" + gender + ", case: " + cas);
        }
        RuleSet rules = type == NameType.FirstName ? firstNameRules : type == NameType.LastName ? lastNameRules : patronymicNameRules;
        Rule exceptionRule = findRule(rules.exceptions, gender, name);
        Rule suffixRule = findRule(rules.suffixes, gender, name);
        Rule rule;
        if (exceptionRule != null && exceptionRule.gender == gender) {
            rule = exceptionRule;
        } else if (suffixRule != null && suffixRule.gender == gender) {
            rule = suffixRule;
        } else {
            rule = exceptionRule != null ? exceptionRule : suffixRule;
        }
        return rule == null ? name : applyMod(rule.mods[cas.modIdx], name);
    }

    static String applyMod(String mod, String name) {
        if (mod.equals(Library.KEEP_MOD)) {
            return name;
        }
        String result = name;
        if (mod.indexOf(Library.REMOVE_CHARACTER) >= 0) {
            for (int i = 0; i < mod.length(); i++) {
                if (mod.charAt(i) == Library.REMOVE_CHARACTER) {
                    result = result.substring(0, result.length() - 1);
                } else {
                    result += mod.substring(i);
                    break;
                }
            }
        } else {
            result = name + mod;
        }
        return result;
    }

    static Rule findRule(Rule[] allRules, Gender gender, String name) {
        if (allRules == null) {
            return null;
        }
        String lcName = name.toLowerCase();
        for (Rule rule : allRules) {
            for (String test : rule.test) {
                boolean fullMatch = test.charAt(0) == '^';
                boolean nameMatched = fullMatch ? test.substring(1).equals(lcName) : lcName.endsWith(test);
                if (nameMatched && (rule.gender == Gender.Both || rule.gender == gender)) {
                    return rule;
                }
            }
        }
        return null;
    }
}

@@ -1510,32 +1510,38 @@
 ns, gender, name
+, true
 );%0A        Rule 
@@ -1586,24 +1586,30 @@
 gender, name
+, true
 );%0A        R
@@ -1999,32 +1999,873 @@
 , name);%0A    %7D%0A%0A
+    public Gender resolve(String name, NameType type, Gender defaultValue) %7B%0A        if (name == null %7C%7C name.isEmpty()) %7B%0A            return defaultValue;%0A        %7D%0A        if (type == null) %7B%0A            throw new IllegalArgumentException(%22Not all required parameters are set! Type: %22 + type + %22, gender:%22 + gender + %22, case: %22 + cas);%0A        %7D%0A        RuleSet rules = type == NameType.FirstName ? firstNameRules : type == NameType.LastName ? lastNameRules : patronymicNameRules;%0A        Rule exceptionRule = findRule(rules.exceptions, gender, name, false);%0A        Rule suffixRule = findRule(rules.suffixes, gender, name, false);%0A        Rule rule;%0A        if (exceptionRule != null) %7B%0A            return defaulValue;%0A        %7D else if (suffixRule != null) %7B%0A            return rule.gender;%0A        %7D%0A        return defaultValue;%0A    %7D%0A%0A
     static Strin
@@ -3540,32 +3540,53 @@
 der, String name
+, boolean checkGender
 ) %7B%0A        if (
@@ -3932,16 +3932,16 @@
 (test);%0A
-
         
@@ -3968,16 +3968,32 @@
 hed && (
+!checkGender %7C%7C 
 rule.gen

Add gender resolver