package com.hubspot.jinjava.lib.tag.eager;

import com.google.common.collect.ImmutableMap;
import com.hubspot.jinjava.interpret.JinjavaInterpreter;
import com.hubspot.jinjava.interpret.TemplateSyntaxException;
import com.hubspot.jinjava.lib.tag.CycleTag;
import com.hubspot.jinjava.tree.parse.TagToken;
import com.hubspot.jinjava.util.ChunkResolver;
import com.hubspot.jinjava.util.HelperStringTokenizer;
import com.hubspot.jinjava.util.WhitespaceUtils;
import java.util.List;

public class EagerCycleTag extends EagerStateChangingTag<CycleTag> {

  public EagerCycleTag() {
    super(new CycleTag());
  }

  @SuppressWarnings("unchecked")
  @Override
  public String getEagerTagImage(TagToken tagToken, JinjavaInterpreter interpreter) {
    List<String> values = null;
    HelperStringTokenizer tk = new HelperStringTokenizer(tagToken.getHelpers());

    List<String> helper = tk.allTokens();
    ChunkResolver chunkResolver = new ChunkResolver(helper.get(0), tagToken, interpreter);
    EagerStringResult resolvedExpression = executeInChildContext(
      eagerInterpreter -> chunkResolver.resolveChunks(),
      interpreter,
      true
    );
    String expression = resolvedExpression.getResult();
    if (WhitespaceUtils.isWrappedWith(expression, "[", "]")) {
      expression = expression.substring(1, expression.length() - 1);
    }
    StringBuilder prefixToPreserveState = new StringBuilder(
      interpreter.getContext().isProtectedMode()
        ? resolvedExpression.getPrefixToPreserveState()
        : ""
    );
    HelperStringTokenizer items = new HelperStringTokenizer(expression).splitComma(true);
    values = items.allTokens();
    if (!chunkResolver.getDeferredWords().isEmpty()) {
      prefixToPreserveState.append(
        reconstructFromContextBeforeDeferring(
          chunkResolver.getDeferredWords(),
          interpreter
        )
      );
    } else {
      for (int i = 0; i < values.size(); i++) {
        values.set(
          i,
          interpreter.resolveString(
            values.get(i),
            tagToken.getLineNumber(),
            tagToken.getStartPosition()
          )
        );
      }
    }
    if (helper.size() == 1) {
      // The helpers get printed out
      return (
        prefixToPreserveState.toString() +
        interpretPrintingCycle(tagToken, interpreter, values, chunkResolver, expression)
      );
    } else if (helper.size() == 3) {
      // The helpers get set to a new variable
      return (
        prefixToPreserveState.toString() +
        interpretSettingCycle(interpreter, values, helper, chunkResolver, expression)
      );
    } else {
      throw new TemplateSyntaxException(
        tagToken.getImage(),
        "Tag 'cycle' expects 1 or 3 helper(s), was: " + helper.size(),
        tagToken.getLineNumber(),
        tagToken.getStartPosition()
      );
    }
  }

  private String interpretSettingCycle(
    JinjavaInterpreter interpreter,
    List<String> values,
    List<String> helper,
    ChunkResolver chunkResolver,
    String resolvedExpression
  ) {
    String var;
    var = helper.get(2);
    if (!chunkResolver.getDeferredWords().isEmpty()) {
      return EagerTagDecorator.buildSetTagForDeferredInChildContext(
        ImmutableMap.of(var, String.format("[%s]", resolvedExpression)),
        interpreter,
        true
      );
    }
    interpreter.getContext().put(var, values);
    return "";
  }

  private String interpretPrintingCycle(
    TagToken tagToken,
    JinjavaInterpreter interpreter,
    List<String> values,
    ChunkResolver chunkResolver,
    String resolvedExpression
  ) {
    String var;
    if (interpreter.getContext().isProtectedMode()) {
      return reconstructCycleTag(resolvedExpression, tagToken);
    }
    Integer forindex = (Integer) interpreter.retraceVariable(
      CycleTag.LOOP_INDEX,
      tagToken.getLineNumber(),
      tagToken.getStartPosition()
    );
    if (forindex == null) {
      forindex = 0;
    }
    if (values.size() == 1) {
      var = values.get(0);
      if (!chunkResolver.getDeferredWords().isEmpty()) {
        return getIsIterable(var, forindex, tagToken);
      } else {
        return values.get(forindex % values.size());
      }
    }
    String item = values.get(forindex % values.size());
    if (
      !chunkResolver.getDeferredWords().isEmpty() &&
      ChunkResolver.shouldBeEvaluated(item, tagToken, interpreter)
    ) {
      return String.format("{{ %s }}", values.get(forindex % values.size()));
    }
    return item;
  }

  private String reconstructCycleTag(String expression, TagToken tagToken) {
    return String.format(
      "%s cycle %s %s",
      tagToken.getSymbols().getExpressionStartWithTag(),
      expression,
      tagToken.getSymbols().getExpressionEndWithTag()
    );
  }

  private static String getIsIterable(String var, int forIndex, TagToken tagToken) {
    String tokenStart = tagToken.getSymbols().getExpressionStartWithTag();
    String tokenEnd = tagToken.getSymbols().getExpressionEndWithTag();
    return (
      String.format("%s if %s is iterable %s", tokenStart, var, tokenEnd) +
      String.format("{{ %s[%d %% %s|length] }}", var, forIndex, var) +
      String.format("%s else %s", tokenStart, tokenEnd) +
      String.format("{{ %s }}", var) +
      String.format("%s endif %s", tokenStart, tokenEnd)
    );
  }
}

@@ -735,40 +735,8 @@
 ) %7B%0A
-    List%3CString%3E values = null;%0A
     
@@ -1579,16 +1579,29 @@
 ue);%0A   
+ List%3CString%3E
  values 
@@ -5050,32 +5050,57 @@
 ar, tokenEnd) +%0A
+      // modulo indexing%0A
       String.for

Add coment