/*
 * Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
 *
 * The contents of this file are subject to the CCM Public
 * License (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the
 * License at http://www.redhat.com/licenses/ccmpl.html.
 *
 * Software distributed under the License is distributed on an
 * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
 * or implied. See the License for the specific language
 * governing rights and limitations under the License.
 *
 */
package com.arsdigita.bebop.jsp;

import javax.servlet.jsp.JspException;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.traversal.TreeWalker;

/**
 * JSP tag handler to show contents from a model-backed one-dimensional
 * list of bebop:cells.  Inside a table, this would represent a table
 * row.  Inside a list, this would just be the list itself.
 *
 * @see com.arsdigita.bebop.jsp.ShowTable
 * @see com.arsdigita.bebop.jsp.ShowList
 */

public abstract class ShowCellList extends ShowContainer {

    public static final String versionId = "$Id: //core-platform/dev/src/com/arsdigita/bebop/jsp/ShowCellList.java#9 $ by $Author: dennis $, $DateTime: 2004/04/07 16:07:11 $";

    private TreeWalker m_walker;
    private Node m_currentCell;

    /**
     * set up the input context as our parent class would except
     * evaluate the body of the current show:... tag only if the list in
     * question isn't empty.
     */
    public int doStartTag() throws JspException {
        super.doStartTag();
        m_walker = makeTreeWalker();
        return maybeNextCell();
    }

    private int maybeNextCell() {
        m_currentCell = m_walker.nextNode();
        if (m_currentCell != null) {
            // only evaluate body if the list is non-empty
            setInputContext(m_currentCell);
            return EVAL_BODY_TAG;
        } else {
            return SKIP_BODY;
        }
    }

    /**
     * We call perform the same action (handleText) as our parent class's
     * doAfterBody() handler, but we don't always return SKIP_BODY.  Instead,
     * we keep returning EVAL_BODY_TAG for each element in the
     * list until we're out of list elements.
     */
    public int doAfterBody() throws JspException {
        super.doAfterBody();
        return maybeNextCell();
    }

    /**
     * returns the contents of current list cell.  Example: given the
     * list <pre>
     * &lt;bebop:thead>
     *   &lt;bebop:cell>
     *      &lt;bebop:label>...&lt;bebop:label>
     *   &lt;/bebop:cell>
     * &lt;/bebop:thead>
     * </pre>
     *
     * we'd return the bebop:label element.
     * @pre m_currentCell != null
     */
    public Node getCurrentCell() {
        Node cell = m_currentCell;
        NodeList nl = cell.getChildNodes();
        for (int i = 0; i < nl.getLength(); i++) {
            // return the first Element child of the current cell
            if (nl.item(i) instanceof Element) {
                return nl.item(i);
            }
        }
        return null;
    }

    /**
     * Creates the tree walker to pick out the cells specific to
     * this model-backed collection.
     */
    protected abstract TreeWalker makeTreeWalker();
}
