content: /*
   * Licensed to the Apache Software Foundation (ASF) under one
   * or more contributor license agreements.  See the NOTICE file
   * distributed with this work for additional information
   * regarding copyright ownership.  The ASF licenses this file
   * to you under the Apache License, Version 2.0 (the
   * "License"); you may not use this file except in compliance
   * with the License.  You may obtain a copy of the License at
   *
   *   http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing,
   * software distributed under the License is distributed on an
   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
   * KIND, either express or implied.  See the License for the
   * specific language governing permissions and limitations
   * under the License.
   */
  package org.apache.asterix.translator;
  
  import java.util.ArrayDeque;
  import java.util.Deque;
  import java.util.HashMap;
  import java.util.Map;
  
  import org.apache.asterix.lang.common.base.Expression;
  import org.apache.asterix.lang.common.expression.VariableExpr;
  import org.apache.hyracks.algebricks.core.algebra.base.Counter;
  import org.apache.hyracks.algebricks.core.algebra.base.IVariableContext;
  import org.apache.hyracks.algebricks.core.algebra.base.LogicalVariable;
  
  public final class TranslationContext implements IVariableContext {
  
      private Counter varCounter;
  
      /** The stack is the used to manage the scope of variables for group-by rebindings. */
      private Deque<Map<Integer, LogicalVariable>> stack = new ArrayDeque<>();
      private Map<Integer, LogicalVariable> currentVarMap = new HashMap<>();
      private boolean topFlwor = true;
  
      public TranslationContext(Counter varCounter) {
          this.varCounter = varCounter;
      }
  
      @Override
      public int getVarCounter() {
          return varCounter.get();
      }
  
      @Override
      public LogicalVariable newVar() {
          return newVarFromExpression(null);
      }
  
      @Override
      public LogicalVariable newVar(String displayName) {
          varCounter.inc();
          int varId = varCounter.get();
          LogicalVariable var = new LogicalVariable(varId, displayName);
          currentVarMap.put(varId, var);
          return var;
      }
  
      @Override
      public void setVarCounter(int count) {
          varCounter.set(count);
      }
  
      public boolean isTopFlwor() {
          return topFlwor;
      }
  
      public void setTopFlwor(boolean b) {
          topFlwor = b;
      }
  
      public LogicalVariable getVar(Integer varId) {
          return currentVarMap.get(varId);
      }
  
      public LogicalVariable newVarFromExpression(Expression expr) {
          int varId;
          if (expr != null && expr.getKind() == Expression.Kind.VARIABLE_EXPRESSION) {
              VariableExpr v = (VariableExpr) expr;
              varId = v.getVar().getId();
              if (varId > varCounter.get()) {
                  varCounter.set(varId);
              }
          } else {
              varCounter.inc();
              varId = varCounter.get();
          }
          LogicalVariable var = expr != null && (expr.getKind() == Expression.Kind.VARIABLE_EXPRESSION
                  || expr.getKind() == Expression.Kind.FIELD_ACCESSOR_EXPRESSION)
                          ? new LogicalVariable(varId, expr.toString()) : new LogicalVariable(varId);
          currentVarMap.put(varId, var);
          return var;
      }
  
      public void setVar(VariableExpr v, LogicalVariable var) {
          currentVarMap.put(v.getVar().getId(), var);
      }
  
      /**
       * Within a subplan, an unbounded variable can be rebound in
       * the group-by operator. But the rebinding only exists
       * in the subplan.
       * This method marks that the translation enters a subplan.
       */
      public void enterSubplan() {
          Map<Integer, LogicalVariable> varMap = new HashMap<Integer, LogicalVariable>();
          varMap.putAll(currentVarMap);
          stack.push(currentVarMap);
          currentVarMap = varMap;
      }
  
      /***
       * This method marks that the translation exits a subplan.
       */
      public void exitSubplan() {
          if (!stack.isEmpty()) {
              currentVarMap = stack.pop();
          }
      }
  
      /*
       * Whether the translation is inside a subplan
       */
      public boolean inSubplan() {
          return !stack.isEmpty();
      }
  
      /**
       * @return the variables produced by the top operator in a subplan.
       */
      public LogicalVariable newSubplanOutputVar() {
          LogicalVariable newVar = newVar();
          if (!stack.isEmpty()) {
              Map<Integer, LogicalVariable> varMap = stack.peek();
              varMap.put(varCounter.get(), newVar);
          }
          return newVar;
      }
  }
  