package org.caudexorigo.jpt;
import java.io.IOException;
import java.io.Serializable;
import java.io.Writer;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.caudexorigo.ErrorAnalyser;
import org.mvel2.MVEL;
import org.mvel2.ParserContext;
public class JptLoopNode extends JptParentNode
{
private boolean _isInSlot;
private RepeatElements _repeatElements;
private Serializable _compiled_exp;
JptLoopNode(RepeatElements repeatElements, boolean isInSlot)
{
_repeatElements = repeatElements;
_isInSlot = isInSlot;
}
public void render(Map<String, Object> context, Writer out) throws IOException
{
if (_compiled_exp == null)
{
ParserContext parser_context = ParserContext.create();
Set<Entry<String, Object>> ctx_entries = context.entrySet();
for (Entry<String, Object> entry : ctx_entries)
{
parser_context.addInput(entry.getKey(), entry.getValue().getClass());
}
// Compile the expression.
_compiled_exp = MVEL.compileExpression(_repeatElements.getLoopSourceExpression(), parser_context);
}
int child_count = getChildCount();
int increment = _repeatElements.getLoopIncrement();
String loopVar = _repeatElements.getLoopVar();
String pad = _repeatElements.getPadding();
try
{
Object collection = MVEL.executeExpression(_compiled_exp, context);
if (collection == null)
{
arrayLoop(context, out, new Object[0], child_count, increment, loopVar, pad);
return;
}
if (collection.getClass().isArray())
{
arrayLoop(context, out, (Object[]) collection, child_count, increment, loopVar, pad);
return;
}
if (collection instanceof Collection)
{
collectionLoop(context, out, (Collection) collection, child_count, increment, loopVar, pad);
return;
}
if (collection instanceof Iterable)
{
iterableLoop(context, out, (Iterable) collection, child_count, increment, loopVar, pad);
return;
}
if (collection instanceof Iterator)
{
iteratorLoop(context, out, (Iterator) collection, child_count, increment, loopVar, pad);
return;
}
arrayLoop(context, out, new Object[0], child_count, increment, loopVar, pad);
}
catch (Throwable t)
{
Throwable r = ErrorAnalyser.findRootCause(t);
throw new RuntimeException(String.format("Error processing JptLoopNode:%nexpression: '%s';%ncontext: %s;%nmessage: '%s'", loopVar, context, r.getMessage()));
}
}
private void arrayLoop(Map<String, Object> context, Writer out, Object[] items, int child_count, int increment, String loopVar, String pad) throws IOException
{
checkAllowed(context, loopVar);
for (int n = 0; n < items.length; n = n + increment)
{
context.put(loopVar, items[n]);
context.put("$index", n + 1);
context.put("$length", items.length);
for (int i = 0; i < child_count; i++)
{
JptNode jpt_node = getChild(i);
jpt_node.render(context, out);
}
if (n < items.length - 1)
out.write(pad);
}
context.remove(loopVar);
context.remove("$index");
context.remove("$length");
}
private void iteratorLoop(Map<String, Object> context, Writer out, Iterator items, int child_count, int increment, String loopVar, String pad) throws IOException
{
int len = -1;
if (context.containsKey("$length"))
{
len = ((Integer) context.get("$length")).intValue();
}
int index = 0;
checkAllowed(context, loopVar);
for (; items.hasNext();)
{
Object item = items.next();
index++;
if (index % increment == 0)
{
context.put(loopVar, item);
context.put("$index", index);
context.put("$length", len);
for (int i = 0; i < child_count; i++)
{
JptNode jpt_node = getChild(i);
jpt_node.render(context, out);
}
out.write(pad);
context.remove(loopVar);
}
}
context.remove(loopVar);
context.remove("$index");
context.remove("$length");
}
private void iterableLoop(Map<String, Object> context, Writer out, Iterable items, int child_count, int increment, String loopVar, String pad) throws IOException
{
if (items != null)
{
iteratorLoop(context, out, items.iterator(), child_count, increment, loopVar, pad);
}
}
private void collectionLoop(Map<String, Object> context, Writer out, Collection items, int child_count, int increment, String loopVar, String pad) throws IOException
{
if (items != null)
{
context.put("$length", items.size());
iteratorLoop(context, out, items.iterator(), child_count, increment, loopVar, pad);
}
}
boolean isLoopNode()
{
return true;
}
public boolean isInSlot()
{
return _isInSlot;
}
}