class Quant1PropertiesGroupingAsgStrategy implements AsgStrategy {

    @Override
    public void apply(AsgQuery query, AsgStrategyContext context) {
        // phase 1 - group all Eprops to EPropGroups
        AsgQueryUtil.elements(query, Quant1.class).forEach(quant -> {
                List<AsgEBase<EProp>> ePropsAsgChildren = AsgQueryUtil.nextAdjacentDescendants(quant, EProp.class);
                List<EProp> eProps = Stream.ofAll(ePropsAsgChildren).map(AsgEBase::geteBase).toJavaList();

                if (!eProps.isEmpty()) {
                    EPropGroup ePropGroup = new EPropGroup(
                            Stream.ofAll(eProps).map(EProp::geteNum).min().get(),
                            quant.geteBase().getqType(),
                            eProps);

                    ePropsAsgChildren.forEach(quant::removeNextChild);
                    quant.addNextChild(new AsgEBase<>(ePropGroup));
                } else {
                    List<AsgEBase<EPropGroup>> ePropsGroupAsgChildren = AsgQueryUtil.nextAdjacentDescendants(quant, EPropGroup.class);
                    Optional<AsgEBase<EBase>> ancestor = AsgQueryUtil.ancestor(quant, asgEBase -> asgEBase.geteBase() instanceof ETyped,
                            asgEBase -> !(asgEBase.geteBase() instanceof Rel));
                    if (ePropsGroupAsgChildren.isEmpty()
                            && ancestor.isPresent()
                            && quant.geteBase().getqType().equals(QuantType.all)) {
                        EPropGroup ePropGroup = new EPropGroup(Stream.ofAll(AsgQueryUtil.eNums(query)).max().get() + 1);
                        AsgEBase<? extends EBase> ePropGroupAsgEbase = new AsgEBase<>(ePropGroup);
                        quant.addNextChild(ePropGroupAsgEbase);
                    }
                }
            }
        );

        // phase 2 - group all EpropGroups to other EpropGroups
        AsgQueryUtil.elements(query, Quant1.class).forEach(this::groupEpropGroups);
    }

}