@Override
  public ISourceChange CalculateASTNodeChange(ASTNodePair pair) {
    ISourceChange change = changeBuilder.buildSimpleChange(pair);
    if (change != null) return change;

    SubChangeContainer container = changeBuilder.createSubchangeContainer(pair);
    container.addSubChange(
        blCalculator.CalculateASTNodeChange(
            pair.selectByPropertyDescriptor(TryStatement.BODY_PROPERTY)));
    XList[] catches = pair.selectChildrenByDescriptor(TryStatement.CATCH_CLAUSES_PROPERTY);
    container.addMultiSubChanges(
        new SimilarityASTNodeMapStrategy(
                new IDistanceCalculator() {
                  @Override
                  public int calculateDistance(ASTNode before, ASTNode after) {
                    String e1 =
                        before.getStructuralProperty(CatchClause.EXCEPTION_PROPERTY).toString();
                    String e2 =
                        after.getStructuralProperty(CatchClause.EXCEPTION_PROPERTY).toString();
                    return DlfStringUtils.distance(e1, e2);
                  }
                })
            .map(catches[0], catches[1])
            .select(
                new Function<ASTNodePair, ISourceChange>() {
                  @Override
                  public ISourceChange apply(ASTNodePair arg0) {
                    return ccCalculator.CalculateASTNodeChange(arg0);
                  }
                }));
    return container;
  }
  @Override
  public ISourceChange CalculateASTNodeChange(ASTNodePair pair) {

    ISourceChange change = this.changeBuilder.buildSimpleChange(pair);
    if (change != null) return change;

    if (pair.getNodeBefore().getNodeType() != pair.getNodeAfter().getNodeType()) {
      logger.debug("Before statement: " + pair.getNodeBefore());
      logger.debug("After statement: " + pair.getNodeAfter());
      List<List<ASTNode>> groupsBefore =
          getDecendantStatements.f(pair.getNodeBefore()).snoc(pair.getNodeBefore()).group(typeEq);
      List<List<ASTNode>> groupsAfter =
          getDecendantStatements.f(pair.getNodeAfter()).snoc(pair.getNodeAfter()).group(typeEq);
      List<P2<List<ASTNode>, List<ASTNode>>> groupPairs =
          FJUtils.getSamePairs(groupsBefore, groupsAfter, listTypeEq);
      List<P2<ASTNode, ASTNode>> nodePairs =
          removeSubPairs(groupPairs.bind(similarNodeMapper.tuple()).filter(areBothNotNull));
      SubChangeContainer container = changeBuilder.createSubchangeContainer(pair);
      container.addMultiSubChanges(
          nodePairs.sort(orderByFirstNodeStart).map(statementChangeCalFunc.tuple()).toCollection());
      container = pruneSourceChangeContainer(container);
      return container == null ? changeBuilder.createUnknownChange(pair) : container;
    }

    switch (pair.getNodeBefore().getNodeType()) {
      case ASTNode.IF_STATEMENT:
        return ifCalculator.CalculateASTNodeChange(pair);
      case ASTNode.BLOCK:
        return blockCalculator.CalculateASTNodeChange(pair);
      case ASTNode.FOR_STATEMENT:
        return fsCalculator.CalculateASTNodeChange(pair);
      case ASTNode.ENHANCED_FOR_STATEMENT:
        return enhancedForCal.CalculateASTNodeChange(pair);
      case ASTNode.WHILE_STATEMENT:
        return wsCalculator.CalculateASTNodeChange(pair);
      case ASTNode.DO_STATEMENT:
        return dsCalculator.CalculateASTNodeChange(pair);
      case ASTNode.TRY_STATEMENT:
        return tsCalculator.CalculateASTNodeChange(pair);
      case ASTNode.BREAK_STATEMENT:
        return bsCalculator.CalculateASTNodeChange(pair);
      case ASTNode.CONTINUE_STATEMENT:
        return csCalculator.CalculateASTNodeChange(pair);
      case ASTNode.RETURN_STATEMENT:
        return rsCalculator.CalculateASTNodeChange(pair);
      case ASTNode.THROW_STATEMENT:
        return thsCalculator.CalculateASTNodeChange(pair);
      case ASTNode.VARIABLE_DECLARATION_STATEMENT:
        return varDecStaCal.CalculateASTNodeChange(pair);
      case ASTNode.EXPRESSION_STATEMENT:
        SubChangeContainer container = this.changeBuilder.createSubchangeContainer(pair);
        container.addSubChange(
            expressionCalculator.CalculateASTNodeChange(
                new ASTNodePair(
                    (ASTNode)
                        pair.getNodeBefore()
                            .getStructuralProperty(ExpressionStatement.EXPRESSION_PROPERTY),
                    (ASTNode)
                        pair.getNodeAfter()
                            .getStructuralProperty(ExpressionStatement.EXPRESSION_PROPERTY))));
        return container;
      default:
        return changeBuilder.createUnknownChange(pair);
    }
  }