/*
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 1999 Bull S.A.
 * Contact: jonas-team@ow2.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or any later version.
 *
 * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 * USA
 *
 * Initial developer(s): Michel-Ange ANTON
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */

package org.ow2.jonas.webapp.taglib;

import java.io.IOException;
import java.net.URLEncoder;

import javax.servlet.http.HttpServletResponse;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;





public class TreeControlRenderTag extends TreeControlTag {
    /**
     * The names of tree state images that we need.
     */
    static final String IMAGE_NODE_OPEN = "node_open.gif";
    static final String IMAGE_NODE_OPEN_FIRST = "node_open_first.gif";
    static final String IMAGE_NODE_OPEN_MIDDLE = "node_open_middle.gif";
    static final String IMAGE_NODE_OPEN_LAST = "node_open_last.gif";
    static final String IMAGE_NODE_CLOSE = "node_close.gif";
    static final String IMAGE_NODE_CLOSE_FIRST = "node_close_first.gif";
    static final String IMAGE_NODE_CLOSE_MIDDLE = "node_close_middle.gif";
    static final String IMAGE_NODE_CLOSE_LAST = "node_close_last.gif";
    static final String IMAGE_BLANK = "noline.gif";
    static final String IMAGE_LINE_FIRST = "line_first.gif";
    static final String IMAGE_LINE_LAST = "line_last.gif";
    static final String IMAGE_LINE_MIDDLE = "line_middle.gif";
    static final String IMAGE_LINE_VERTICAL = "line.gif";

// --------------------------------------------------------- Instance Variables

    /**
     * Flag who indicate when the first node is rendered.
     */
    private boolean mb_FirstNodeRendered;
    private int mi_MaxChar;

// --------------------------------------------------------- Public Methods

    /**
     * Render this tree control.
     *
     * @exception JspException if a processing error occurs
     */
    public int doEndTag()
        throws JspException {
        /*
              mb_FirstNodeRendered = false;
              return super.doEndTag();
         */

        TreeControl treeControl = getTreeControl();
        JspWriter out = pageContext.getOut();
        try {
            out.print("<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\"");
            if (style != null) {
                out.print(" class=\"");
                out.print(style);
                out.print("\"");
            }
            out.println(">");
            int level = 0;
            mb_FirstNodeRendered = false;
            mi_MaxChar = 0;
            TreeControlNode node = treeControl.getRoot();
            render(out, node, level, treeControl.getWidth(), true);

            // Avoid bug Netscape 4
            out.print("<tr>");
            for (int i = 0; i < treeControl.getWidth() + 2; i++) {
                out.print("<td></td>");
            }
            StringBuffer sb = new StringBuffer("<td nowrap>");
            for (int i = 0; i < (mi_MaxChar + 1); i++) {
                sb.append("&nbsp;&nbsp;");
            }
            sb.append("</td>");
            out.print(sb.toString());
            out.println("</tr>");

            out.println("</table>");
        }
        catch (IOException e) {
            throw new JspException(e);
        }
        return (EVAL_PAGE);

    }

// ------------------------------------------------------ Protected Methods

    /**
     * Render the specified node, as controlled by the specified parameters.
     *
     * @param out The <code>JspWriter</code> to which we are writing
     * @param node The <code>TreeControlNode</code> we are currently
     *  rendering
     * @param level The indentation level of this node in the tree
     * @param width Total displayable width of the tree
     * @param last Is this the last node in a list?
     *
     * @exception IOException if an input/output error occurs
     */
    protected void render(JspWriter out, TreeControlNode node, int level, int width, boolean last)
        throws IOException {
        HttpServletResponse response = (HttpServletResponse) pageContext.getResponse();

        // if the node is root node and the label value is
        // null, then do not render root node in the tree.

        if ("ROOT-NODE".equalsIgnoreCase(node.getName()) && (node.getLabel() == null)) {
            // Render the children of this node
            TreeControlNode children[] = node.findChildren();
            int firstIndex = children.length - 1;
            int lastIndex = children.length - 1;
            int newLevel = level + 1;
            for (int i = 0; i < children.length; i++) {
                render(out, children[i], newLevel, width, i == lastIndex);
            }
            return;
        }

        // Render the beginning of this node
        out.println("  <tr valign=\"middle\">");

        // Create the appropriate number of indents
        for (int i = 0; i < level; i++) {
            int levels = level - i;
            TreeControlNode parent = node;
            for (int j = 1; j <= levels; j++) {
                parent = parent.getParent();
            }
            if (parent.isLast()) {
                out.print("    <td></td>");
            }
            else {
                out.print("    <td><img src=\"");
                out.print(images);
                out.print("/");
                out.print("tree/");
                out.print(IMAGE_LINE_VERTICAL);
                out.print("\" border=\"0\"></td>");
            }
            out.println();
        }

        // Render the tree state image for this node

        // HACK to take into account special characters like = and &
        // in the node name, could remove this code if encode URL
        // and later request.getParameter() could deal with = and &
        // character in parameter values.
        String encodedNodeName = URLEncoder.encode(node.getName(),"UTF-8");

        String action = replace(getAction(), "${name}", encodedNodeName);

        String updateTreeAction = replace(getAction(), "tree=${name}", "select=" + encodedNodeName);
        updateTreeAction = ((HttpServletResponse) pageContext.getResponse()).encodeURL(
            updateTreeAction);

        out.print("    <td>");
        if ((action != null) && !node.isLeaf()) {
            out.print("<a href=\"");
            out.print(response.encodeURL(action));
            out.print("\">");
        }
        out.print("<img src=\"");
        out.print(images);
        out.print("/");
        out.print("tree/");
        if (node.isLeaf()) {
            if (mb_FirstNodeRendered == false) {
                if (node.isLast()) {
                    out.print(IMAGE_BLANK);
                }
                else {
                    out.print(IMAGE_LINE_FIRST);
                }
            }
            else if (node.isLast()) {
                out.print(IMAGE_LINE_LAST);
            }
            else {
                out.print(IMAGE_LINE_MIDDLE);
            }
        }
        else if (node.isExpanded()) {
            if (mb_FirstNodeRendered == false) {
                if (node.isLast()) {
                    out.print(IMAGE_NODE_OPEN);
                }
                else {
                    out.print(IMAGE_NODE_OPEN_FIRST);
                }
            }
            else if (node.isLast()) {
                out.print(IMAGE_NODE_OPEN_LAST);
            }
            else {
                out.print(IMAGE_NODE_OPEN_MIDDLE);
            }
        }
        else {
            if (mb_FirstNodeRendered == false) {
                if (node.isLast()) {
                    out.print(IMAGE_NODE_CLOSE);
                }
                else {
                    out.print(IMAGE_NODE_CLOSE_FIRST);
                }
            }
            else if (node.isLast()) {
                out.print(IMAGE_NODE_CLOSE_LAST);
            }
            else {
                out.print(IMAGE_NODE_CLOSE_MIDDLE);
            }
        }
        out.print("\" border=\"0\" align=\"absmiddle\">");
        if ((action != null) && !node.isLeaf()) {
            out.print("</a>");
        }
        out.println("</td>");

        // Calculate the hyperlink for this node (if any)
        String hyperlink = null;
        if (node.getAction() != null) {
            hyperlink = ((HttpServletResponse) pageContext.getResponse()).encodeURL(node.getAction());
        }

        // Render the icon for this node (if any)
        out.print("    <td>");

        // Anchor name
        out.print("<a name=\"");
        out.print(encodedNodeName);
        out.print("\"></a>");

        if (node.getIcon() != null) {
            if (hyperlink != null) {
                out.print("<a href=\"");
                out.print(hyperlink);
                out.print("\"");
                String target = node.getTarget();
                if (target != null) {
                    out.print(" target=\"");
                    out.print(target);
                    out.print("\"");
                }
                // to refresh the tree in the same 'self' frame
                out.print(" onclick=\"");
                out.print("self.location.href='" + updateTreeAction + "'");
                out.print("\"");
                out.print(">");
            }
            out.print("<img src=\"");
            out.print(images);
            out.print("/");
            out.print(node.getIcon());
            out.print("\" border=\"0\" align=\"absmiddle\">");
            if (hyperlink != null) {
                out.print("</a>");
            }
        }
        out.println("</td>");

        // Render the label for this node (if any)
        int iColspan = width - level + 1;
        if (iColspan > 1) {
            out.print("    <td width=\"100%\" colspan=\"");
            out.print(iColspan);
            out.print("\" nowrap>");
        }
        else {
            out.print("    <td width=\"100%\" nowrap>");
        }
        if (node.getLabel() != null) {
            if (node.getLabel().length() > mi_MaxChar) {
                mi_MaxChar = node.getLabel().length();
            }
            // Note the leading space so that the text has some space
            // between it and any preceding images
            out.print("&nbsp;");
            String labelStyle = null;
            if (node.isSelected() && (styleSelected != null)) {
                labelStyle = styleSelected;
            }
            else if (!node.isSelected() && (styleUnselected != null)) {
                labelStyle = styleUnselected;
            }
            if (hyperlink != null) {
                out.print("<a href=\"");
                out.print(hyperlink);
                out.print("\"");
                String target = node.getTarget();
                if (target != null) {
                    out.print(" target=\"");
                    out.print(target);
                    out.print("\"");
                }
                if (labelStyle != null) {
                    out.print(" class=\"");
                    out.print(labelStyle);
                    out.print("\"");
                }
                // to refresh the tree in the same 'self' frame
                out.print(" onclick=\"");
                out.print("self.location.href='" + updateTreeAction + "'");
                out.print("\"");
                out.print(">");
            }
            else if (labelStyle != null) {
                out.print("<span class=\"");
                out.print(labelStyle);
                out.print("\">");
            }
            out.print(node.getLabel());
            if (hyperlink != null) {
                out.print("</a>");
            }
            else if (labelStyle != null) {
                out.print("</span>");
            }
        }
        out.println("</td>");

        // Render the end of this node
        out.println("  </tr>");
        // Remember the first node is rendered
        mb_FirstNodeRendered = true;

        // Render the children of this node
        if (node.isExpanded()) {
            TreeControlNode children[] = node.findChildren();
            int lastIndex = children.length - 1;
            int newLevel = level + 1;
            for (int i = 0; i < children.length; i++) {
                render(out, children[i], newLevel, width, i == lastIndex);
            }
        }

    }
}
