/**
   * La methode principale qui renvoie l'arbre remplace si il y a matching et null sinon
   *
   * @param rule la rule qui va nous permettre de tester notre arbre.
   * @param arbre l'arbre a tester
   * @return le return qui vaut null si ça ne match pas, et qui vaut l'arbre remplacé sinon
   */
  public Expression check(Rule rule, Expression arbre) {
    boolean check;
    // ici on recupere le pattern de la rule et l'arbre
    Expression pattern = rule.getLeft();

    // Maintenant on homogeneise les noms de variable
    Hashtable<Character, Expression> ht = new Hashtable<Character, Expression>();

    check = this.compareExpressions(pattern, arbre, ht);
    if (check == false) return null;

    return replace(rule.getRight(), ht);
  }
  public boolean apply(Rule r) {
    //		System.out.println("ApplRuleSequencesGraTraImpl.apply(Rule) : "+r.getName()+"
    // "+updateTypeObjectsMapAfterStep);

    //		long time0 = System.currentTimeMillis();

    this.stoppingRule = false;
    boolean result = false;
    boolean valid = false;

    this.currentMatch = r.getMatch();
    if (this.currentMatch == null) {
      this.currentMatch = this.grammar.createMatch(r);
      this.currentMatch.setCompletionStrategy(
          (MorphCompletionStrategy) this.strategy.clone(), true);
      //		strategy.showProperties();
    } else if (this.updateTypeObjectsMapAfterStep) {
      this.currentMatch.setTypeObjectsMapChanged(true);
    }

    boolean parallelApply = true;
    boolean is_applied = false;
    //		int matchCompletions = 0;

    //		time0 = System.currentTimeMillis();

    while (parallelApply) {

      if (!isInputParameterSet(r.getLeft(), true, this.currentMatch)) {
        fireGraTra(new GraTraEvent(this, GraTraEvent.INPUT_PARAMETER_NOT_SET, this.currentMatch));
      }

      if (this.stopping || this.stoppingRule) {
        this.currentMatch.clear();
        return false;
      }

      if (this.pauseRule) return false;

      valid = false;
      while (!valid) {
        if (this.currentMatch.isTotal() || this.currentMatch.nextCompletion()) {
          if (this.currentMatch.isValid()) {
            valid = true;
            //						matchCompletions++;

            if (r.isParallelApplyEnabled() && this.currentMatch.typeObjectsMapChanged) {
              this.currentMatch.typeObjectsMapChanged = false;
              // das hat Auswirkung auf den naechsten Aufruf
              // von nextCompletion():
              // die Graphaenderungen nach dem Step werden
              // NICHT BEACHTET!!!
            }
          } else {
            this.errorMsg = this.currentMatch.getErrorMsg();
            this.currentMatch.clear();
          }
        } else {
          this.errorMsg = this.currentMatch.getErrorMsg();
          break;
        }
      }

      if (valid) {

        fireGraTra(new GraTraEvent(this, GraTraEvent.MATCH_VALID, this.currentMatch));

        if (!isInputParameterSet(r.getRight(), false, this.currentMatch)) {
          fireGraTra(new GraTraEvent(this, GraTraEvent.INPUT_PARAMETER_NOT_SET, this.currentMatch));
        }

        if (this.stopping || this.stoppingRule) {
          if (this.currentMatch != null) {
            this.currentMatch.clear();
          }
          return false;
        }

        if (this.pauseRule) return false;

        try { // check attr context: variables only
          boolean checkVarsOnly = true;
          this.currentMatch
              .getAttrContext()
              .getVariables()
              .getAttrManager()
              .checkIfReadyToTransform(this.currentMatch.getAttrContext(), checkVarsOnly);
        } catch (AttrException ex) {
          fireGraTra(new GraTraEvent(this, GraTraEvent.NOT_READY_TO_TRANSFORM, r.getName()));
          // destroyMatch(currentMatch);
          return false;
        }

        Morphism coMatch = apply(this.currentMatch);
        if (coMatch != null) {
          this.errorMsg = "";
          is_applied = true;

          this.currentMatch.clear();
          // destroyMatch(currentMatch);
          coMatch.dispose();
          coMatch = null;
          result = true;
        } else {
          valid = false;
          fireGraTra(
              new GraTraEvent(this, GraTraEvent.NO_COMPLETION, this.currentMatch, this.errorMsg));
          this.currentMatch.clear();
          // destroyMatch(currentMatch);

          result = false;
        }
      } else {
        fireGraTra(
            new GraTraEvent(
                this,
                GraTraEvent.NO_COMPLETION,
                this.currentMatch,
                this.currentMatch.getErrorMsg()));
        this.currentMatch.clear();
        // destroyMatch(currentMatch);

        result = false;
      }

      //
      if (r.isParallelApplyEnabled()) {
        if (!valid) {
          parallelApply = false;
          this.currentMatch.typeObjectsMapChanged = true;
        }
        if (is_applied) {
          result = true;
        }
      } else {
        parallelApply = false;
        break;
      }
      //
    }

    return result;
  }