package org.apache.struts.taglib.logic;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.List;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.BodyTagSupport;
import org.apache.struts.util.MessageResources;
import org.apache.struts.util.PropertyUtils;
import org.apache.struts.util.RequestUtils;
import org.apache.struts.util.ResponseUtils;




public class TableTag extends BodyTagSupport {
    
    
    protected Iterator iterator = null;
    
    protected int position = 0;
    
    protected int cellsValue = 0;
    
    protected int collectionValue = 0;
    
    
    
    protected static MessageResources messages =
    MessageResources.getMessageResources
    ("org.apache.struts.taglib.logic.ApplicationResources");
    
    
    protected Object collection = null;
    
    public Object getCollection() {
        return (this.collection);
    }
    
    public void setCollection(Object collection) {
        this.collection = collection;
    }
    
    
    protected String id = null;
    
    public String getId() {
        return (this.id);
    }
    
    public void setId(String id) {
        this.id = id;
    }
    
    
    
    protected String length = null;
    
    public String getLength() {
        return (this.length);
    }
    
    public void setLength(String length) {
        this.length = length;
    }
    
    
    protected String name = null;
    
    public String getName() {
        return (this.name);
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    
    protected String property = null;
    
    public String getProperty() {
        return (this.property);
    }
    
    public void setProperty(String property) {
        this.property = property;
    }
    
    
    protected String scope = null;
    
    public String getScope() {
        return (this.scope);
    }
    
    public void setScope(String scope) {
        this.scope = scope;
    }
    
    
    protected String type = null;
    
    public String getType() {
        return (this.type);
    }
    
    public void setType(String type) {
        this.type = type;
    }
    
    protected int offsetValue = 0;
    
    protected String offset = null;
    
    public String getOffset() {
        return (this.offset);
    }
    
    public void setOffset(String offset) {
        this.offset = offset;
    }
    
    protected int columnsValue = 0;
    protected String columns = null;
    
    public String getColumns() {
        return (this.columns);
    }
    
    public void setColumns(String columns) {
        this.columns = columns;
    }
    
    
    public int doStartTag() throws JspException {
        
        // Acquire the collection we are going to iterate over
        Object collection = this.collection;
        if (collection == null)
            collection =
            RequestUtils.lookup(pageContext, name, property, scope);
        if (collection == null) {
            JspException e = new JspException
            (messages.getMessage("tableTag.collection"));
            RequestUtils.saveException(pageContext, e);
            throw e;
        }
        
        
        // Construct an iterator for this collection
        
        if (collection.getClass().isArray()) {
	    collection = Arrays.asList((Object[]) collection);
            collectionValue = ((List)collection).size();
        } if (collection instanceof Collection) {
            collectionValue = ((Collection)collection).size();
	    iterator = ((Collection) collection).iterator();
        } else if (collection instanceof Iterator)
	    iterator = (Iterator) collection;
        else if (collection instanceof Map) { 
            collectionValue = ((Map)collection).values().size();
            iterator = ((Map)collection).values().iterator();
        }	
        else {
                JspException e = new JspException
                (messages.getMessage("tableTag.iterator"));
                RequestUtils.saveException(pageContext, e);
                throw e;
        }
            
            // Calculate the starting offset
            if (offset == null)
                offsetValue = 0;
            else {
                try {
                    offsetValue = Integer.parseInt(offset);
                } catch (NumberFormatException e) {
                    Integer offsetObject =
                    (Integer) pageContext.findAttribute(offset);
                    if (offsetObject == null)
                        offsetValue = 0;
                    else
                        offsetValue = offsetObject.intValue();
                }
            }
            if (offsetValue < 0)
                offsetValue = 0;
            
            // Calculate the rendering length
            if (columns == null)
                columnsValue = 1;
            else {
                try {
                    columnsValue = Integer.parseInt(columns);
                } catch (NumberFormatException e) {
                    columnsValue = 1;
                }
            }
            
            if (columnsValue <= 0)
                columnsValue = 1;
            
            if (offsetValue >= columnsValue)
                throw new JspException
                (messages.getMessage("tableTag.offsetIncorrect"));
            
            int rowsValue = (collectionValue + offsetValue) / columnsValue;
            if ((collectionValue + offsetValue) % columnsValue != 0)
                rowsValue++;
            
            cellsValue = columnsValue * rowsValue;
            
            position = 0;
            
            // Store the first value and evaluate, or skip the body if none
            
            if (iterator.hasNext()) {
                pageContext.removeAttribute(id);
                doBeforeBody();
                return (EVAL_BODY_TAG);
            } else {
                return (SKIP_BODY);
            }
            
        }
        
        public void doBeforeBody() throws JspException {
            
            if ( position % columnsValue == 0 ) {
                try {
                    JspWriter writer = pageContext.getOut();
                    writer.println("<TR>");
                } catch (IOException e) {
                    throw new JspException
                    (messages.getMessage("tableTag.io", e.toString()));
                }
            }
            
            if ( position < offsetValue ) {
                pageContext.removeAttribute(id);
            }else if (position >= collectionValue + offsetValue) {
                pageContext.removeAttribute(id);
            }else{
                Object element = iterator.next();
                pageContext.setAttribute(id, element);
            }
            
        }
        
        
        public int doAfterBody() throws JspException {
            
            if (bodyContent != null) {
                try{
                    if ( position % columnsValue == columnsValue -1 ) {
                        JspWriter writer = pageContext.getOut();
                        writer.println("</TR>");
                    }
                } catch (IOException e) {
                    throw new JspException
                    (messages.getMessage("tableTag.io", e.toString()));
                }
                ResponseUtils.writePrevious(pageContext, bodyContent.getString());
                bodyContent.clearBody();
            }
            position++;           
            if ( position >= cellsValue ) {
                return (SKIP_BODY);
                
            } else {
                doBeforeBody(); 
                return (EVAL_BODY_TAG);
            }
            
        }
        
        
        public int doEndTag() throws JspException {
            
            return (EVAL_PAGE);
            
        }
        
        
        public void release() {
            
            super.release();
            
            iterator = null;
            position = 0;
            offsetValue = 0;
            columnsValue = 0;
            
            id = null;
            collection = null;
            name = null;
            offset = null;
            property = null;
            scope = null;
            columns = null;
            
        }
        
        
    }
