gt:       throw new UnsupportedOperationException();
context: /*
   * Copyright (c) 1998-2010 Caucho Technology -- all rights reserved
   *
   * This file is part of Resin(R) Open Source
   *
   * Each copy or derived work must preserve the copyright notice and this
   * notice unmodified.
   *
   * Resin Open Source is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   *
   * Resin Open Source is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
   * of NON-INFRINGEMENT.  See the GNU General Public License for more
   * details.
   *
   * You should have received a copy of the GNU General Public License
   * along with Resin Open Source; if not, write to the
   *   Free SoftwareFoundation, Inc.
   *   59 Temple Place, Suite 330
   *   Boston, MA 02111-1307  USA
   *
   * @author Scott Ferguson
   */
  
  package com.caucho.jstl.el;
  
  import com.caucho.el.Expr;
  import com.caucho.jsp.PageContextImpl;
  import com.caucho.util.CharBuffer;
  import com.caucho.util.EnumIterator;
  import com.caucho.util.L10N;
  import com.caucho.util.NullIterator;
  
  import javax.el.ELContext;
  import javax.servlet.jsp.JspException;
  import javax.servlet.jsp.JspTagException;
  import javax.servlet.jsp.jstl.core.LoopTag;
  import javax.servlet.jsp.jstl.core.LoopTagStatus;
  import javax.servlet.jsp.tagext.IterationTag;
  import javax.servlet.jsp.tagext.TagSupport;
  import java.lang.reflect.Array;
  import java.util.Collection;
  import java.util.Enumeration;
  import java.util.Iterator;
  import java.util.Map;
  
  public class ForEachTag extends TagSupport
    implements IterationTag, LoopTag, LoopTagStatus {
    private static L10N L = new L10N(ForEachTag.class);
    
    protected Expr _itemsExpr;
    
    protected Expr _beginExpr;
    protected Expr _endExpr;
    protected Expr _stepExpr;
    
    protected String _var;
    protected String _varStatus;
  
    // runtime values
    protected Iterator _iterator;
    
    protected int _begin;
    protected int _end;
    protected int _step;
  
    protected Object _initialVar;
    protected Object _current;
    protected int _index;
    protected int _count;
  
    /**
     * Sets the collection expression.
     */
    public void setItems(Expr items)
    {
      _itemsExpr = items;
    }
  
    /**
     * Sets the beginning index.
     */
    public void setBegin(Expr begin)
    {
      _beginExpr = begin;
    }
  
    /**
     * Sets the ending index.
     */
    public void setEnd(Expr end)
    {
      _endExpr = end;
    }
  
    /**
     * Sets the step index.
     */
    public void setStep(Expr step)
    {
      _stepExpr = step;
    }
  
    /**
     * Sets the iteration variable.
     */
    public void setVar(String var)
    {
      _var = var;
    }
  
    /**
     * Sets the status variable.
     */
    public void setVarStatus(String var)
    {
      _varStatus = var;
    }
  
    /**
     * Process the tag.
     */
    public int doStartTag()
      throws JspException
    {
      try {
        _iterator = null;
        _index = 0;
        _count = 0;
  
        PageContextImpl pageContext = (PageContextImpl) this.pageContext;
        ELContext env = pageContext.getELContext();
  
        if (_beginExpr != null)
  	_begin = (int) _beginExpr.evalLong(env);
        else
  	_begin = -1;
  
        if (_endExpr != null)
  	_end = (int) _endExpr.evalLong(env);
        else
  	_end = Integer.MAX_VALUE;
  
        if (_stepExpr != null)
  	_step = (int) _stepExpr.evalLong(env);
        else
  	_step = 0;
      
        Object items = null;
  
        if (_itemsExpr != null) {
  	items = _itemsExpr.evalObject(env);
  
  	_iterator = getIterator(items);
  
  	while (_index < _begin && _iterator.hasNext()) {
  	  _index++;
  	  _iterator.next();
  	}
        }
        else if (_beginExpr == null)
  	throw new JspException(L.l("c:forEach must specify `items' or `begin'"));
        else if (_endExpr == null)
  	throw new JspException(L.l("c:forEach must specify `items' or `begin'"));
        else {
  	_iterator = new RangeIterator(_begin, _end);
  	_end = -1;
        }
  
        if (_varStatus != null)
  	pageContext.setAttribute(_varStatus, this);
  
        if (_var != null)
  	_initialVar = pageContext.getAttribute(_var);
  
        return doAfterBody();
      } catch (Exception e) {
        throw new JspException(e);
      }
    }
  
    public int doAfterBody() throws JspException
    {
      if (_iterator == null) {
        if (_var != null)
  	pageContext.setAttribute(_var, _initialVar);
  	
        return SKIP_BODY;
      }
      else if (_iterator.hasNext()) {
        int stepCount;
  
        if (_step <= 0 || _count == 0)
          stepCount = 1;
        else
          stepCount = _step;
  
        for (; stepCount > 0; stepCount--) {
          if (! _iterator.hasNext()) {
  	  if (_var != null)
  	    pageContext.setAttribute(_var, _initialVar);
  	
            return SKIP_BODY;
  	}
          
          _index++;
          _current = _iterator.next();
        }
  
        _count++;
  
        if (_var != null)
          pageContext.setAttribute(_var, _current);
  
        if (_index - 1 <= _end || _end < 0)
          return EVAL_BODY_AGAIN;
        else {
  	if (_var != null)
  	  pageContext.setAttribute(_var, _initialVar);
  	
          return SKIP_BODY;
        }
      }
      else {
        if (_var != null)
  	pageContext.setAttribute(_var, _initialVar);
  	
        return SKIP_BODY;
      }
    }
  
    // LoopTag
  
    /**
     * Returns the status.
     */
    public LoopTagStatus getLoopStatus()
    {
      return this;
    }
      
  
    // LoopTagStatus
  
    /**
     * Returns the current object.
     */
    public Object getCurrent()
    {
      return _current;
    }
  
    /**
     * Returns the index.
     */
    public int getIndex()
    {
      return _index - 1;
    }
  
    /**
     * Returns the number of objects returned.
     */
    public int getCount()
    {
      return _count;
    }
  
    /**
     * Returns true if this is the first item.
     */
    public boolean isFirst()
    {
      return _count == 1;
    }
  
    /**
     * Returns true if this is the last item.
     */
    public boolean isLast()
    {
      if (_iterator == null || ! _iterator.hasNext())
        return true;
      else if (_step > 0 && _step + _index > _end)
        return true;
      else
        return false;
    }
  
    /**
     * Returns the begin index.
     */
    public Integer getBegin()
    {
      if (_beginExpr != null && _itemsExpr != null)
        return new Integer(_begin);
      else
        return null;
    }
    
    /**
     * Returns the end index.
     */
    public Integer getEnd()
    {
      if (_endExpr != null && _itemsExpr != null)
        return new Integer(_end);
      else
        return null;
    }
    
    /**
     * Returns the step index.
     */
    public Integer getStep()
    {
      if (_stepExpr != null)
        return new Integer(_step);
      else
        return null;
    }
  
    public static Iterator getIterator(Object items)
      throws JspTagException
    {
      if (items == null)
        return NullIterator.create();
      else if (items instanceof Map)
        return ((Map) items).entrySet().iterator();
      else if (items instanceof Collection)
        return ((Collection) items).iterator();
      else if (items.getClass().isArray())
        return new ArrayIterator(items);
      else if (items instanceof Iterator)
        return (Iterator) items;
      else if (items instanceof Enumeration)
        return new EnumIterator((Enumeration) items);
      else if (items instanceof String)
        return new StringIterator((String) items);
      else
        throw new JspTagException(L.l("unknown items value `{0}'", items));
    }
  
    public static class ArrayIterator implements Iterator {
      private Object _array;
      private int _index;
      private int _length;
  
      ArrayIterator(Object array)
      {
        _array = array;
        _length = Array.getLength(array);
      }
      
      public boolean hasNext()
      {
        return _index < _length;
      }
      
      public Object next()
      {
        if (_index < _length)
          return Array.get(_array, _index++);
        else
          return null;
      }
      
      public void remove()
      {
        throw new UnsupportedOperationException();
      }
    }
  
    public static class StringIterator implements Iterator {
      private String _value;
      private int _length;
      private int _i;
  
      StringIterator(String value)
      {
        _value = value;
        _length = value.length();
  
        for (; _i < _length; _i++)
          if (_value.charAt(_i) != ',')
            break;
      }
      
      public boolean hasNext()
      {
        return _i < _length;
      }
      
      public Object next()
      {
        char ch;
        int begin = _i;
        int tail = -1;
  
        for (; _i < _length; _i++) {
          ch =_value.charAt(_i);
  
          if (ch == ',') {
            if (tail == -1)
              tail = _i;
          } else {
            if (tail != -1)
              break;
          }
        }
  
        if (tail == -1)
          tail = _length;
  
        String value = _value.substring(begin, tail);
  
        return value;
      }
      
      public void remove()
      {
        throw new UnsupportedOperationException();
      }
    }
  
    public static class RangeIterator implements Iterator {
      private int _end;
      private int _i;
  
      RangeIterator(int begin, int end)
      {
        _i = begin;
        _end = end;
      }
      
      public boolean hasNext()
      {
        return _i <= _end;
      }
      
      public Object next()
      {
        if (_i <= _end)
          return new Integer(_i++);
        else
          return null;
      }
      
      public void remove()
      {
  