protected FilterFamily getFilterFamily(TestSuite suite) {
    FilterFamilies filterFamilies = suite.getFilterFamilies();
    FilterFamily filterFamily = null;
    for (int i = 0; i < filterFamilies.wSize(); i++) {
      FilterFamily child = (FilterFamily) filterFamilies.wGet(i);
      if (EntityUtils.isNotResolver(child)
          && GENERATED_FAMILY_NAME.equals(child.getName().getValue())) {
        filterFamily = child;
        break;
      }
    }

    TestsEntityFactory tef = TestsEntityFactory.instance;
    if (filterFamily == null) {
      filterFamily =
          tef.createFilterFamily(
              CommonsEntityAdapterFactory.createResolver(TestsEntityDescriptorEnum.PackageName),
              tef.createDescription("Auto-generated filter family"),
              tef.createName(GENERATED_FAMILY_NAME),
              tef.createFilterRules(0));
    }
    return filterFamily;
  }
  @Override
  public void visit(TestSuite entity) {
    if (isLearning()) {
      Map<IEntity, List<IEntity>> learntMap = getLearntMap();

      IEntity result = null;
      for (int cycle = 1; cycle <= learnCycles(); cycle++) {
        printWriter().printf("*** Learning cycle %d ***\n\n", cycle);
        ITransactionScope resettableScope = BindingManagerFactory.instance.createTransactionScope();
        getBindings().wEnterScope(resettableScope);
        try {
          getBindings().wDefValue("learnCycle", cycle);
          super.visit(entity);
          result = getBindings().getResult();
        } finally {
          resettableScope.rollback();
          getBindings().wExitScope();
        }
      }
      getBindings().setResult(result);

      FilterFamily filterFamily = getFilterFamily(entity);
      FilterRules filterRules = filterFamily.getFilterRules();
      FreshNameGenerator fnGen = new FreshNameGenerator();
      for (IEntity name :
          BehaviorUtils.compileAndLazyEvaluate(createFindAllFilterRuleNamesQuery(), filterFamily))
        fnGen.addBoundName(name.wStringValue());

      for (IEntity adapter : learntMap.keySet()) {
        List<IEntity> learntEntities = learntMap.get(adapter);

        IEntity value = learntEntities.get(0);
        if (learntEntities.size() > 1 && EntityUtils.isData(value)) {
          for (IEntity learntEntity : learntEntities) if (!learntEntity.wEquals(value)) continue;
        } else if (learntEntities.size() > 1) {
          for (IEntity learntEntity2 : learntEntities)
            if (EntityUtils.isData(learntEntity2)) continue;

          // generate filter rule
          FilterRule filterRule = TestsHelpers.createFilterRule(learntEntities);
          if (EntityUtils.isNotResolver(filterRule)) {
            String filterName;
            IEntity filterBody;
            if ((filterBody = Matcher.find(filterRule.getBody(), filterRules, false)) != null) {
              // try to reuse a generated filter
              filterName = ((FilterRule) filterBody.wGetParent()).getName().getValue();
            } else {
              // add the filter rule to the filter family
              filterName = fnGen.nextFreshName(GENERATED_FILTER_NAME);
              ITransactionScope resettableScope =
                  BindingManagerFactory.instance.createTransactionScope();
              getBindings().wEnterScope(resettableScope);
              try {
                getBindings().wDefValue("filterName", filterName);
                Matcher.substitute(filterRule, getBindings(), false);
                filterRules.wAdd(filterRule);
              } finally {
                resettableScope.rollback();
                getBindings().wExitScope();
              }
            }

            // wrap SubjectStatement with a UsingFilter
            ITransactionScope resettableScope =
                BindingManagerFactory.instance.createTransactionScope();
            getBindings().wEnterScope(resettableScope);
            try {
              SubjectStatement statement =
                  BehaviorUtils.evaluateFirstResult(
                      createFindAncestorSubjectStatement(), adapter, getBindings());
              UsingFilter usingFilter = createUsingFilter(filterName);
              statement.wGetParent().wSet(statement, usingFilter);
              usingFilter.setSubjectStatement(statement);
            } finally {
              resettableScope.rollback();
              getBindings().wExitScope();
            }
          }
        }

        TestsHelpers.replace(adapter, value);
      }
      // add the newly generated family
      if (!EntityUtils.hasParent(filterFamily) && !filterRules.wIsEmpty())
        entity.getFilterFamilies().wAdd(filterFamily);
    } else super.visit(entity);
  }