class GroupingRequiredFilterFunctions {

    public static Collection<?> matchesInGroupLeft(Object... args) {
        if (log.isTraceEnabled()) {
            log.trace("matchesInGroupLeft(" + Arrays.asList(args) + ")");
        }
        // positionFrom is either '0', or it is the integer value of the last argument
        // when the argumentCount is odd
        int positionFromLeft = 0;
        if (args.length % 2 != 0) { // it's odd
            Object lastArgument = args[args.length - 1];
            positionFromLeft = Integer.parseInt(lastArgument.toString());
        }
        Collection<ValueTuple> firstMatches;
        Collection<ValueTuple> allMatches = new HashSet<>();
        Object fieldValue1 = args[0];
        String regex = args[1].toString();
        if (fieldValue1 instanceof Iterable) {
            // cast as Iterable in order to call the right getAllMatches method
            firstMatches = EvaluationPhaseFilterFunctions.getAllMatches((Iterable) fieldValue1, regex);
        } else {
            firstMatches = EvaluationPhaseFilterFunctions.getAllMatches(fieldValue1, regex);
        }
        if (log.isTraceEnabled()) {
            log.trace("firstMatches = " + firstMatches);
        }
        for (ValueTuple currentMatch : firstMatches) {
            String matchFieldName = ValueTuple.getFieldName(currentMatch);
            // my firstMatches will be a collection that looks like [NAME.grandparent_0.parent_0.child_0:SANTINO]
            String theFirstMatch = EvaluationPhaseFilterFunctions.getMatchToLeftOfPeriod(matchFieldName, positionFromLeft);
            
            for (int i = 2; i < args.length; i += 2) {
                
                if (args[i] instanceof Iterable) {
                    // args[i] is a collection that looks like:
                    // [[NAME.grandparent_0.parent_1.child_0,LUCA,luca],
                    // [NAME.grandparent_0.parent_0.child_2,MICHAEL,michael],
                    // [NAME.grandparent_0.parent_1.child_1,VINCENT,vincent],
                    // [NAME.grandparent_0.parent_0.child_0,SANTINO,santino],
                    // [NAME.grandparent_0.parent_0.child_1,FREDO,fredo],
                    // [NAME.grandparent_0.parent_0.child_3,CONSTANZIA,constanzia]]
                    // let's say that regex is 'FREDO'
                    // Assuming that positionFromLeft is 0, then for each of these, I will consider only the ones that have a match on
                    // grandparent_0.parent_0, then I will see if the name matches my regex (FREDO)
                    // If the positionFromLeft were 1, I would consider all of the above that include grandparent.0, and then
                    // look for a match on FREDO
                    for (Object fieldValue : (Iterable) args[i]) {
                        String fieldName = ValueTuple.getFieldName(fieldValue);
                        // @formatter:off
                        manageMatchesInGroupLeftRemainingArgs(fieldValue,
                                args[i + 1].toString(), // regex
                                allMatches, theFirstMatch,
                                EvaluationPhaseFilterFunctions.getMatchToLeftOfPeriod(fieldName, positionFromLeft), // the next match
                                currentMatch);
                        // @formatter:on
                    }
                } else if (args[i] instanceof ValueTuple) {
                    // args[i] is a ValueTuple that looks like:
                    // [NAME.grandparent_0.parent_0.child_1,FREDO,fredo],
                    // let's say that regex is 'FREDO'
                    // Assuming that positionFromLeft is 0, then for each of these, I will consider only the ones that have a match on
                    // grandparent_0.parent_0, then I will see if the name matches my regex (FREDO)
                    // If the positionFromLeft were 1, I would consider all of the above that include grandparent.0, and then
                    // look for a match on FREDO
                    Object fieldValue = args[i];
                    String fieldName = ValueTuple.getFieldName(fieldValue);
                    // @formatter:off
                    manageMatchesInGroupLeftRemainingArgs(fieldValue,
                            args[i + 1].toString(), // regex
                            allMatches, theFirstMatch,
                            EvaluationPhaseFilterFunctions.getMatchToLeftOfPeriod(fieldName, positionFromLeft), // the next match
                            currentMatch);
                    // @formatter:on
                }
            }
        }
        
        // if there was a match found at all levels, then the matches.size will be equal to the
        // number of field/regex pairs
        if (allMatches.size() < args.length / 2) { // truncated in case args.length was odd
            allMatches.clear();
        }
        if (log.isTraceEnabled()) {
            log.trace("returning matches:" + allMatches);
        }
        return Collections.unmodifiableCollection(allMatches);
    }

}