/**
   * recursive method to get all conditions from "condition tree"
   *
   * @param conds - at the beginning root conditions, at lower level conditions under
   *     CompoundCondition
   * @param op - at the beginning null, at lower level operator of Compound Condition
   * @return group of its subgroups and of conditions
   */
  private GenPredicGroup getGroupConditions(Conditions conds, GenPredicGroup.EOperator op) {
    GenPredicGroup myConds = new GenPredicGroup();
    myConds.setOperator((op != null) ? op : GenPredicGroup.EOperator.ALL);
    Iterator<Condition> it = conds.iterator();
    while (it.hasNext()) {
      Condition cond = it.next();
      // if true, a new condition group is created and filled
      if (cond instanceof CompoundCondition) {
        // set group operator
        GenPredicGroup.EOperator actualOp = null;
        if (cond instanceof ConditionAll) {
          actualOp = GenPredicGroup.EOperator.ALL;
        } else if (cond instanceof ConditionAny) {
          actualOp = GenPredicGroup.EOperator.ANY;
        } else if (cond instanceof ConditionNone) {
          actualOp = GenPredicGroup.EOperator.NONE;
        }

        if (myConds.getMyGroups() == null) {
          myConds.setMyGroups(new ArrayList<GenPredicGroup>());
        }
        // call recursively to get conditions of actual group
        myConds
            .getMyGroups()
            .add(getGroupConditions(((CompoundCondition) cond).getConditions(), actualOp));
      } else {
        // get condition
        if (myConds.getGeneratorPredicts() == null) {
          myConds.setGeneratorPredicts(new ArrayList<GeneratorPredicate>());
        }
        myConds.getGeneratorPredicts().add(getGP(cond));
      }
    }

    return myConds;
  }
  /**
   * according to .gwt.xml files generates a LinkedMap which has interfaces as keys array of
   * generators as values keys are sorted according order of <generate-with> elements in .gwt.xml
   * files
   *
   * @param context
   * @throws UnableToCompleteException
   */
  private void fillUpGeneratorChainMap(TreeLogger logger, GeneratorContext context)
      throws UnableToCompleteException {

    GeneratorChain.customGenerators = new LinkedList<AbstractGenerator>();
    GeneratorChain.replacers = new LinkedList<AbstractGenerator>();
    GeneratorChain.thirdPartyGenerators = new LinkedHashMap<Generator, AbstractGenerator>();
    ModuleDef moduleDef =
        ((CompilerContext) getPrivateField(context, "compilerContext")).getModule();
    Rules rules = moduleDef.getRules();
    Iterator<Rule> rulesIter = rules.iterator();
    while (rulesIter.hasNext()) {
      Rule rul = rulesIter.next();
      Generator gen = null;

      // =================replace with
      if (rul instanceof RuleReplaceWith) {
        String replaceClass = (String) getPrivateField(rul, "replacementTypeName");
        gen = new ReplaceByGenerator(replaceClass);
        // gen = null;

        // =================generate with
      } else if (rul instanceof RuleGenerateWith) {
        Class<? extends Generator> generatorClass =
            (Class<? extends Generator>) getPrivateField(rul, "generatorClass");
        Constructor<?> constructor;
        try {
          constructor = generatorClass.getDeclaredConstructor();
        } catch (Exception e) {
          logger.log(
              Type.ERROR, "Unable to obtain default constructor of generator " + generatorClass);
          throw new UnableToCompleteException();
        }
        constructor.setAccessible(true);
        try {
          gen = (Generator) constructor.newInstance();
        } catch (Exception e) {
          logger.log(Type.ERROR, "Unable to create instance of generator " + generatorClass);
          throw new UnableToCompleteException();
        }
      }

      if (gen != null) {
        if (gen instanceof AbstractGenerator) {
          GenPredicGroup newGroup = null;
          AbstractGenerator myGen = (AbstractGenerator) gen;
          if (GeneratorChain.customGenerators.contains(gen)
              || GeneratorChain.replacers.contains(gen)) {
            newGroup = addPredicsToExisting(rul, myGen.getConditions());
            myGen.setConditions(newGroup);
          } else {
            newGroup = getGroupConditions(rul.getRootCondition().getConditions(), null);
            myGen.setConditions(newGroup);
            if (gen instanceof ReplaceByGenerator) {
              GeneratorChain.replacers.addFirst(myGen);
            } else {
              GeneratorChain.customGenerators.addFirst(myGen);
            }
          }

        } else {
          if (GeneratorChain.thirdPartyGenerators.containsKey(gen)) {
            AbstractGenerator myGen = GeneratorChain.thirdPartyGenerators.get(gen);
            GenPredicGroup newGroup = addPredicsToExisting(rul, myGen.getConditions());
            myGen.setConditions(newGroup);
            GeneratorChain.thirdPartyGenerators.put(gen, myGen);
          } else {
            AbstractGenerator myGen =
                new AbstractGenerator() {

                  @Override
                  public String doGenerate(
                      TreeLogger logger, GeneratorContext context, String typeName)
                      throws UnableToCompleteException {
                    return null;
                  }
                };
            myGen.setConditions(getGroupConditions(rul.getRootCondition().getConditions(), null));
            GeneratorChain.thirdPartyGenerators.put(gen, myGen);
          }
        }
      }
    }
  }