/*
   * In need some cases, we need to transform the fecthing of a relation for overcoming the problem of traversing lazy relations
   * If we encounter an eager relation after traversing lazy relations, we transform the eager relation pretends to be a lazy one
   * so its columns are not traversed
   */
  private Fetching getFetchingForRelationNode(RelationNode relationNode) {

    Fetching fetch = relationNode.getTableRelation().getFetching();

    if (fetch.equals(Fetching.EAGER)) {
      TableNode parentTableNode = relationNode.getParentTable();
      RelationNode parentRelNode = (RelationNode) parentTableNode.getParent();
      if (parentRelNode == null) return fetch;

      if (startedALazySelect(parentRelNode)) return fetch;

      if (parentRelNode.getTableRelation().getFetching().equals(Fetching.LAZY)) {
        relationNode.setMarkedAsLazy(true);
        return Fetching.LAZY;
      }
    }

    return fetch;
  }
  /*
   * Determines whether we reached the current relation node through a lazy relation in the past
   */
  private boolean traversedLazyRelation(Fetching currFetching, RelationNode relationNode) {
    TableNode parentTableNode = relationNode.getParentTable();
    RelationNode parentRelNode = (RelationNode) parentTableNode.getParent();
    if (parentRelNode == null) // in case the parent table was the base table
    return false;

    boolean parentRelIsLazy = parentRelNode.getTableRelation().getFetching().equals(Fetching.LAZY);

    if (startedALazySelect(parentRelNode)) return false;

    boolean traversedLazyRel = parentRelIsLazy || parentRelNode.isMarkedAsLazy();
    // Can not traverse an eager relation after traversing a Lazy one except in a lazy Select.

    return currFetching != null && currFetching.equals(Fetching.EAGER) && traversedLazyRel;
  }
  /*
   * Implements the relational tree traversal
   */
  public void visit(TableNode tableNode, boolean baseTable) {

    ctx.createTableContext(tableNode);

    if (baseTable) ctx.setBaseTable(tableNode.getTable());

    if (baseTable) onVisitBaseTable(tableNode);
    else {
      onVisitRelatedTable(tableNode);
    }

    if (inRecursiveRelation(tableNode)) {
      ctx.setVisitedRecursion(tableNode.getTable());
      if (ctx.isInLazyQuery()) ctx.setVisitedTable(tableNode.getTable(), tableNode);
    }

    // Add
    if (shouldStopVisiting(tableNode)) return;
    ctx.setVisitedTable(tableNode.getTable(), tableNode);

    for (RelationNode relationNode : tableNode.getChildren()) {
      if (eligibleForVisitation(relationNode, tableNode)) {
        //				relationNode.setRelContextManager(ctx); //pass the context to the node
        Fetching relationFecthing = getFetchingForRelationNode(relationNode);
        if (fetching == null
            || fetching.equals(relationFecthing)
            || allowedForVisitation(relationNode)) {
          if (traversedLazyRelation(
              relationFecthing,
              relationNode)) // stop if we reached the tableNode by traversing a relation with lazy
            // fetching
            continue;
          for (TableNode childTableNode : relationNode.getChildren()) {
            visit(childTableNode, false);
          }
          onVisitedTableRelation(relationNode);
        }
      }
    }
  }