/**
 * License Agreement.
 *
 * Rich Faces - Natural Ajax for Java Server Faces (JSF)
 *
 * Copyright (C) 2007 Exadel, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1 as published by the Free Software Foundation.
 *
 * This library 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.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
 */

package org.richfaces.taglib;

import org.richfaces.iterator.ForEachIterator;
import org.richfaces.iterator.SimpleForEachIterator;
import org.richfaces.el.ELBuilder;
import com.sun.facelets.tag.TagAttribute;
import com.sun.facelets.FaceletContext;

import javax.servlet.jsp.JspTagException;
import javax.el.ValueExpression;
import javax.el.ELException;
import java.util.List;
import java.util.Collection;
import java.util.Iterator;
import java.util.Enumeration;
import java.util.Map;

/**
 * @author akolonitsky
 * @since Dec 21, 2009
 */
class ColumnsHandlerIterationContext {
    /**
     * Iterator for columns's tag value attribute
     */
    private ForEachIterator items; // our 'digested' items

    /**
     * Var attr - defines page variable for current item
     */
    private String indexId;

    /**
     * Integer value begin attr
     */
    private Integer begin;

    /**
     * Integer value end attr
     */
    private Integer end;

    /**
     * Integer value of end attr.
     */
    private Integer columnsCount;

    /**
     * String value of var attr
     */
    private String itemId = null;

    /**
     * Current column counter
     */
    private Integer index = 0;

    /**
     * Expression for var item
     */
    private IteratedExpression iteratedExpression;

    private String valueExpr;

    public String getVarReplacement(TagAttribute index) {
        if (valueExpr == null) {
            return String.valueOf(index);
        }

        if (items != null && items.getVarReplacement() != null) {
            return items.getVarReplacement();
        }
        
        return valueExpr + "[" + this.index + "]";
    }

    public String getIndexReplacement() {
        return String.valueOf(index);
    }

    /**
	 * Return true if we didn't complete column's count
	 *
	 * @return hasNext
	 */
	boolean hasNext() {
		try {
            return (end == 0 || index < end) && items.hasNext();
		} catch (Exception e) {
			return false;
		}

	}

	/**
	 * Inits first iteration item
	 */
	void correctFirst() {
		if (items != null) {
			if (begin > 0 && (index < begin)) {
				while (index < begin && hasNext()) {
					next();
				}
				if (!hasNext()) {
					index = 0;
				}
			}
		}
	}

	/**
	 * Iterate to next column
	 *
	 * @param ctx
     * @return
	 */
	Object next() {
		try {
			Object o = items.next();
			index++;
			return o;
		} catch (Exception e) {
			return null;
		}
	}

    void setColumnsCount(FaceletContext ctx, TagAttribute columns) {
        if (columns != null) {
            try {
                this.columnsCount = Integer.parseInt((String) columns.getObject(ctx));
                if (this.columnsCount < 0) {
                    this.columnsCount = 0; // If end is negative set up zero
                }
            } catch (Exception e) {
                this.columnsCount = 0;
            }
        } else {
            this.columnsCount = 0;
        }
    }


    void setBegin(FaceletContext ctx, TagAttribute begin) {
        if (begin != null) {
            try {
                Object o = begin.getObject(ctx);
                if (o instanceof Number) {
                    this.begin = ((Number)o).intValue();
                }else if (o instanceof String) {
                    this.begin = Integer.parseInt((String) o);
                }
                this.begin--;
                if (this.begin < 0) {
                    this.begin = 0; // If end is negative set up zero
                }
            } catch (Exception e) {
                this.begin = 0;
            }
        } else {
            this.begin = 0;
        }
    }


    void setEnd(FaceletContext ctx, TagAttribute end) {
        if (end != null) {
            try {
                Object o = end.getObject(ctx);
                if (o instanceof Number) {
                    this.end = ((Number)o).intValue();
                }else if ( o instanceof String) {
                    this.end = Integer.parseInt((String) o);
                }
                if (this.end < 0) {
                    this.end = 0; // If end is negative set up zero
                }
            } catch (Exception e) {
                this.end = 0;
            }
        } else {
            this.end = 0;
        }
    }

    void setIndex(FaceletContext ctx, TagAttribute index) {
        if (index != null) {
            try {
                indexId = (String) index.getObject(ctx);
            } catch (ClassCastException e) {
                indexId = null;
            }
        }
    }

    void setVar(FaceletContext ctx, TagAttribute var) {
        if (var != null) {
            try {
                itemId = (String) var.getObject(ctx);
            } catch (ClassCastException e) {
                itemId = null;
            }
        }
    }

    void setValue(FaceletContext ctx, TagAttribute value) throws JspTagException {
        // produce the right sort of ForEachIterator
        if (value != null) {
            valueExpr = ELBuilder.getVarReplacement(value.getValue());

            // If this is a deferred expression, make a note and get the 'items' instance.
            // extract an iterator over the 'items' we've got
            items = SimpleForEachIterator.supportedTypeForEachIterator(value.getObject(ctx));
        } else {
            // no 'items', so use 'begin' and 'end'
            items = SimpleForEachIterator.beginEndForEachIterator(columnsCount - 1);
        }
    }

    /**
     * Return expression for page variables
     *
     * @param ctx
     * @param expr
     * @return
     */
    ValueExpression getVarExpression(FaceletContext ctx, ValueExpression expr) {
        Object o = expr.getValue(ctx.getFacesContext().getELContext());
        int k = index;
        if (o.getClass().isArray() || o instanceof List) {
            return new IndexedValueExpression(expr, k);
        }

        if (o instanceof Collection || o instanceof Iterator
            || o instanceof Enumeration || o instanceof Map
            || o instanceof String) {

            if (iteratedExpression == null) {
                iteratedExpression = new IteratedExpression(expr, ",");
            }
            return new IteratedValueExpression(iteratedExpression, k);
        }

        throw new ELException("FOREACH_BAD_ITEMS");
    }

    /**
     * Release iteration variables
     */
    void release() {
        items = null;
        index = 0;
    }

    public String getIndexId() {
        return indexId;
    }

    public String getItemId() {
        return itemId;
    }

    public Integer getBegin() {
        return begin;
    }

    public Integer getIndex() {
        return index;
    }
}
