/*  Copyright (c) 2000 by Oracle Corporation. All Rights Reserved. */

package oracle.portal.provider.v2.render;

import java.io.PrintWriter;
import java.io.IOException;
import java.util.ResourceBundle;
import java.util.Map;
import java.util.Locale;

import oracle.portal.utils.BiDiUtils;
import oracle.portal.provider.v2.PortletDefinition;
import oracle.portal.provider.v2.PortletException;
import oracle.portal.provider.v2.ProviderDefinition;
import oracle.portal.provider.v2.security.AccessControlException;
import oracle.portal.provider.v2.resource.ProviderBundle;
import oracle.portal.provider.v2.event.EventUtils;
import oracle.portal.provider.v2.url.UrlUtils;
import oracle.portal.utils.v2.ParameterMap;
import oracle.portal.utils.v2.NameValuePair;
import oracle.webdb.utils.SimpleStringBuffer;

/**
 *  A PortletContainerRenderer is a utility class that renders the container
 *  for a portlet.
 *
 *  The container that is renderered may vary depending on the SHOW mode that
 *  is being requested. For example, Edit, Edit Defaults. Help, About, and
 *  Show Details are all rendered in "full screen" mode whereas the regular
 *  Show and Preview modes have variable size containers depending on the
 *  size of the portlet.
 */

public class DefaultContainerRenderer extends PortletContainerRenderer
{
    // system event names
    // NOTE: these must be kept in sync with the constants
    // defined in the event engine package oracle.webdb.event
    private static final String SYS_EVENT_PREFIX   = "_portal_";
    private static final String SYS_EVENT_COLLAPSE = SYS_EVENT_PREFIX + "collapse";
    private static final String SYS_EVENT_REMOVE   = SYS_EVENT_PREFIX + "delete";

    // system event parameters
    // NOTE: these must be kept in sync with the constants
    // defined in the event engine package oracle.webdb.event
    private static final String SYS_EVENT_PARAM_STATE       = "p_state";
    private static final String SYS_EVENT_PARAM_PORTLET_REF = "p_portlet_ref";

    // system event images
    private static final String SYS_EVENT_IMAGE_RESTORE  = "/images/restore.gif";
    private static final String SYS_EVENT_IMAGE_MINIMIZE = "/images/minimize.gif";
    private static final String SYS_EVENT_IMAGE_REMOVE   = "/images/remove.gif";

    //Full screen mode border images
    private static final String TOP_IMAGE = "\"/images/FFFFFFsl.gif\"";
    private static final String TOP_BIDI_IMAGE = "\"/images/FFFFFFsr.gif\"";
    private static final String BOTTOM_IMAGE = "\"/images/FFFFFFbr.gif\"";
    private static final String BOTTOM_BIDI_IMAGE = "\"/images/FFFFFFbl.gif\"";

    private static final String TOP = "top";
    private static final String BOTTOM = "bottom";
    private static final String RIGHT = "right";
    private static final String LEFT = "left";

    /**
     *  Renders the header for the portlet SHOW mode
     *
     *  @param request the portlet render request
     *  @param out PrintWriter that should be used to write the portlet header
     *  @param params additional parameters passed in by the PortletRenderer
     */
    public void renderShowHeader(PortletRenderRequest request,
                                 PrintWriter out,
                                 Map params)
        throws PortletException, IOException
    {
        RenderContext context = request.getRenderContext();
        Locale l = request.getLocale();

        if (context.hasTitle())
        {
            renderPortletTitlebar(request, out, params);
        }

        if (context.hasBorder())
        {
            out.println("<TABLE BORDER=\"1\" ");
            out.print("WIDTH=\"100%\" CELLPADDING=\"0\"");
            out.print("CELLSPACING=\"0\" class=\"RegionBorder\">");
        }
        else
        {
            out.println("<TABLE BORDER=\"0\" ");
            out.print("WIDTH=\"100%\" CELLPADDING=\"0\"");
            out.print("CELLSPACING=\"0\" class=\"RegionNoBorder\">");
        }

        out.println("<TR><TD class=\"RegionHeaderColor\" WIDTH=\"100%\" ");
        out.print(BiDiUtils.getDirAttribute(l));
        out.print(" >");
    }


    /**
     *  Renders the footer for the portlet SHOW mode
     *
     *  @param request the portlet render request
     *  @param out PrintWriter that should be used to write the portlet header
     *  @param params additional parameters passed in by the PortletRenderer
     */
    public void renderShowFooter(PortletRenderRequest request,
                                 PrintWriter out,
                                 Map params)
        throws PortletException, IOException
    {
        out.println("</TD></TR>");
        out.println("</TABLE>");
    }

    /**
     *  Renders the header for the portlet PREVIEW mode
     *
     *  @param request the portlet render request
     *  @param out PrintWriter that should be used to write the portlet header
     *  @param params additional parameters passed in by the PortletRenderer
     */
    public void renderPreviewHeader(PortletRenderRequest request,
                                    PrintWriter out,
                                    Map params)
        throws PortletException, IOException
    {
        renderShowHeader(request, out, params);
    }


    /**
     *  Renders the footer for the portlet PREVIEW mode
     *
     *  @param request the portlet render request
     *  @param out PrintWriter that should be used to write the portlet header
     *  @param params additional parameters passed in by the PortletRenderer
     */
    public void renderPreviewFooter(PortletRenderRequest request,
                                    PrintWriter out,
                                    Map params)
        throws PortletException, IOException
    {
        renderShowFooter(request, out, params);
    }

    /**
     *  Renders the header for the portlet SHOW_DETAILS mode
     *
     *  @param request the portlet render request
     *  @param out PrintWriter that should be used to write the portlet header
     *  @param params additional parameters passed in by the PortletRenderer
     */
    public void renderDetailsHeader(PortletRenderRequest request,
                                    PrintWriter out,
                                    Map params)
        throws PortletException, IOException
    {
        // no header for DETAILS mode
    }


    /**
     *  Renders the footer for the portlet SHOW_DETAILS mode
     *
     *  @param request the portlet render request
     *  @param out PrintWriter that should be used to write the portlet header
     *  @param params additional parameters passed in by the PortletRenderer
     */
    public void renderDetailsFooter(PortletRenderRequest request,
                                    PrintWriter out,
                                    Map params)
        throws PortletException, IOException
    {
        // no footer for DETAILS mode
    }


    /**
     *  Renders the header for the portlet EDIT mode
     *
     *  @param request the portlet render request
     *  @param out PrintWriter that should be used to write the portlet header
     *  @param params additional parameters passed in by the PortletRenderer
     */
    public void renderEditHeader(PortletRenderRequest request,
                                 PrintWriter out,
                                 Map params)
        throws PortletException, IOException
    {
        boolean renderCustomize = true;
        Boolean renderCustomizeObj = (Boolean)params.get(PortletContainerRenderer.RENDER_CUSTOMIZE);

        if (renderCustomizeObj != null)
        {
            renderCustomize = renderCustomizeObj.booleanValue();
        }

        if (renderCustomize)
        {
            String helpURL = (String)params.get(PortletContainerRenderer.HELP_URL);
            String formName = (String)params.get(PortletContainerRenderer.EDIT_FORM_NAME);
            String actionParam = (String)params.get(PortletContainerRenderer.ACTION_PARAM_NAME);
            String title = (String)params.get(PortletContainerRenderer.PORTLET_TITLE);

            // default values if not provided
            if (formName == null)
            {
                formName = CUSTOMIZE_FORM_NAME;
            }

            if (actionParam == null)
            {
                actionParam = DEFAULT_ACTION_PARAM;
            }

            // default the portlet title if not specified
            if (title == null)
            {
                title = PortletRendererUtil.getModeTitle(request);
            }

            out.print("<FORM ACTION=\"");
            out.print(UrlUtils.htmlFormActionLink(request,
                            UrlUtils.PAGE_LINK));
            out.print("\" METHOD=\"POST\" ONSUBMIT=\"return false\" NAME=\"");
            out.print(formName);
            out.println("\" ENCTYPE=\"application/x-www-form-urlencoded\">");

            out.println(UrlUtils.emitHiddenField(actionParam, ""));
            out.println(UrlUtils.htmlFormHiddenFields(request,
                                               UrlUtils.PAGE_LINK));

            renderDesignFormBodyBegin(request, out, formName, title,
                                      actionParam, helpURL);
        }
    }


    /**
     *  Renders the footer for the portlet EDIT mode
     *
     *  @param request the portlet render request
     *  @param out PrintWriter that should be used to write the portlet header
     *  @param params additional parameters passed in by the PortletRenderer
     */
    public void renderEditFooter(PortletRenderRequest request,
                                 PrintWriter out,
                                 Map params)
        throws PortletException, IOException
    {
        boolean renderCustomize = true;
        Boolean renderCustomizeObj = (Boolean)params.get(PortletContainerRenderer.RENDER_CUSTOMIZE);

        if (renderCustomizeObj != null)
        {
            renderCustomize = renderCustomizeObj.booleanValue();
        }

        if (renderCustomize)
        {
            renderDesignFormBodyEnd(request, out);
            out.println("</FORM>");
        }
    }


    /**
     *  Renders the header for the portlet EDIT_DEFAULTS mode
     *
     *  @param request the portlet render request
     *  @param out PrintWriter that should be used to write the portlet header
     *  @param params additional parameters passed in by the PortletRenderer
     */
    public void renderEditDefaultsHeader(PortletRenderRequest request,
                                         PrintWriter out,
                                         Map params)
        throws PortletException, IOException
    {
        renderEditHeader(request, out, params);
    }


    /**
     *  Renders the footer for the portlet EDIT_DEFAULTS mode
     *
     *  @param request the portlet render request
     *  @param out PrintWriter that should be used to write the portlet header
     *  @param params additional parameters passed in by the PortletRenderer
     */
    public void renderEditDefaultsFooter(PortletRenderRequest request,
                                         PrintWriter out,
                                         Map params)
        throws PortletException, IOException
    {
        renderEditFooter(request, out, params);
    }


    /**
     *  Renders the header for the portlet HELP mode
     *
     *  @param request the portlet render request
     *  @param out PrintWriter that should be used to write the portlet header
     *  @param params additional parameters passed in by the PortletRenderer
     */
    public void renderHelpHeader(PortletRenderRequest request,
                                 PrintWriter out,
                                 Map params)
        throws PortletException, IOException
    {
        renderInformationFormHeader(request, out, params);
    }


    /**
     *  Renders the footer for the portlet HELP mode
     *
     *  @param request the portlet render request
     *  @param out PrintWriter that should be used to write the portlet header
     *  @param params additional parameters passed in by the PortletRenderer
     */
    public void renderHelpFooter(PortletRenderRequest request,
                                 PrintWriter out,
                                 Map params)
        throws PortletException, IOException
    {
        renderInformationFormFooter(request, out, params);
    }


    /**
     *  Renders the header for the portlet HELP mode
     *
     *  @param request the portlet render request
     *  @param out PrintWriter that should be used to write the portlet header
     *  @param params additional parameters passed in by the PortletRenderer
     */
    public void renderAboutHeader(PortletRenderRequest request,
                                  PrintWriter out,
                                  Map params)
        throws PortletException, IOException
    {
        renderInformationFormHeader(request, out, params);
    }


    /**
     *  Renders the footer for the portlet HELP mode
     *
     *  @param request the portlet render request
     *  @param out PrintWriter that should be used to write the portlet header
     *  @param params additional parameters passed in by the PortletRenderer
     */
    public void renderAboutFooter(PortletRenderRequest request,
                                  PrintWriter out,
                                  Map params)
        throws PortletException, IOException
    {
        renderInformationFormFooter(request, out, params);
    }


    /**
     *  Utility method for rendering the About/Help form.  This method should be
     *  used in conjunction with renderInformationFormFooter() to work correctly.
     *  This routine emits the proper html FORM tag, appropriate hidden fields,
     *  the standard look/feel for the Form container, and the customize form
     *  'Close' button.
     */
    protected void renderInformationFormHeader(PortletRenderRequest request,
                                               PrintWriter out,
                                               Map params)
        throws PortletException, IOException
    {
        String title = (String)params.get(PortletContainerRenderer.PORTLET_TITLE);
        String formName = (String)params.get(PortletContainerRenderer.EDIT_FORM_NAME);
        String actionParam = (String)params.get(PortletContainerRenderer.ACTION_PARAM_NAME);
        String helpURL = (String)params.get(PortletContainerRenderer.HELP_URL);

        // validate required parameters are available
        if (formName == null)
        {
            formName = CUSTOMIZE_FORM_NAME;
        }

        if (actionParam == null)
        {
            actionParam = DEFAULT_ACTION_PARAM;
        }

        // default the portlet title if not specified
        if (title == null)
        {
            title = PortletRendererUtil.getModeTitle(request);
        }

        out.println("<FORM>");
        renderDesignFormBodyBegin(request, out, formName,
                                  title, actionParam, helpURL);
    }

    /**
     *  Utility method for completing the rendering of the Help/About information form.
     *  This method should be
     *  used in conjunction with renderInformationFormHeader() to work correctly.
     *  This routine emits the proper html tags to close the FORM including
     *  the standard look/feel for the Form container.
     *
     *  @param request the portlet render request.
     *  @param writer the response writer used to output the customize form header.
     */
    protected void renderInformationFormFooter(PortletRenderRequest request,
                                               PrintWriter out,
                                               Map params)
        throws PortletException, IOException
    {
        renderDesignFormBodyEnd(request, out);
        out.println("</FORM>");
    }

    /**
     *  Utility method for rendering the Design forms.  This method should be
     *  used in conjunction with renderDessignFormFooter() to work correctly.
     *  This routine emits the proper html FORM tag, appropriate hidden fields,
     *  the standard look/feel for the Form container, and the appropriate form
     *  buttons (based on the rendermode).
     *
     *  @param request the portlet render request.
     *  @param writer the response writer used to output the customize form header.
     *  @param formName the name used in the <FORM> tag's NAME attribute.  This must
     *  be none null so appropriate javascript can be generated to set the
     *  <i>actionParam</i> value.
     *  @param title the to display in the header (titlebar)
     *  @param actionParam the name of the hidden field that will hold the value
     *  that indicates which button was clicked.  The value is 'OK' if the OK button
     *  was clicked.  The value is 'APPLY' if the APPLY button is clicked
     *  @param helpURL  a URL to this customize form's help screen.  If null the help link
     *  is not displayed.
     */
    protected void renderDesignFormBodyBegin(PortletRenderRequest request,
                                             PrintWriter out,
                                             String formName,
                                             String title,
                                             String actionParam,
                                             String helpURL)
        throws IOException
    {
        ResourceBundle res = request.getProviderResource();
        Locale l = request.getPortletReference().getLocale();

        // start container
        out.println("<CENTER>");
        out.println("<TABLE BORDER=\"0\" CELLPADDING=\"0\" CELLSPACING=\"0\" ");
        out.print("WIDTH =\"90%\">");

        // Put Javascript to set button value
        // Needed so developers can set display value in appropriate language
        out.println("<SCRIPT LANGUAGE=\"JavaScript1.1\">");
        out.println("<!-- Comment out script for old browsers");
        out.println("function doSubmit(action) {");

        out.print("   document.");
        out.print(formName);
        out.print(".");
        out.print(actionParam);
        out.println(".value=action");

        out.print("   document.");
        out.print(formName);
        out.println(".submit()");

        out.println("}");
        out.println("//-->");
        out.println("</SCRIPT>");

        // draw title
        out.println("<TR><TD>");
        out.println("<TABLE WIDTH=\"100%\" BORDER=\"0\" CELLPADDING=\"0\" ");
        out.print("CELLSPACING=\"0\">");
        out.println("<TR>");
        out.println("<TD width=\"3%\" class=\"OraBgColorDark\">&nbsp;</TD>");

        if (helpURL != null)
        {
            out.print("<TD width=\"90%\" class=\"OraBgColorDark\">");
            out.print("<FONT class=\"OraGlobalPageTitle\">");
            out.print(title);
            out.println("</FONT></TD>");

            out.print("<TD width=\"6%\" valign=\"MIDDLE\" ");
            out.print("class=\"OraBgColorDark\">");
            out.print("<A href=\"javascript:show_context_help('");
            out.print(helpURL);
            out.print("')\"><IMG src=\"/images/helps.gif\" alt=\"Help\" ");
            out.println("border=\"0\"></A></TD>");
        }
        else
        {
            out.print("<TD width=\"96%\" class=\"OraBgColorDark\">");
            out.print("<FONT class=\"OraGlobalPageTitle\">");
            out.print(title);
            out.println("</FONT></TD>");
        }
        out.println("<TD class=\"OraBgColorDark\">&nbsp;</TD>");
        out.println("</TR>");
        out.println("</TABLE>");
        out.println("</TD></TR>");

        // draw header
        out.println("<TR><TD>");
        out.println("<TABLE border=\"0\" cellpadding=\"0\" cellspacing=\"0\" ");
        out.print("width=\"100%\">");
        out.println("<TR>");
        out.println("<TD rowspan=\"2\" valign=\"TOP\">");
        out.println("<TABLE border=\"0\" cellpadding=\"0\" cellspacing=\"0\">");
        out.println("<TR>");
        out.println("<TD valign=\"TOP\" class=\"OraBgColorDark\"><IMG src=");
        out.print(getBorderImage(l, TOP));
        out.print(" valign=\"TOP\" border=\"0\"></TD>");
        out.println("</TR>");
        out.println("</TABLE>");
        out.println("</TD>");
        out.println("<TD rowspan=\"2\" valign=\"TOP\">");
        out.print("<IMG src=\"/images/compedit.gif\" valign=\"TOP\" ");
        out.print("border=\"0\"></TD>");
        out.println("<TD align=\"" + BiDiUtils.getAlignment(l, RIGHT) +
                    "\" valign=\"TOP\" width=\"100%\">");
        out.println("<TABLE border=\"0\" cellpadding=\"1\" cellspacing=\"4\">");
        out.println("<TR>");

        // draw buttons
        RenderContext context = request.getRenderContext();
        if (request.getMode() == PortletRenderer.MODE_EDIT
            || request.getMode() == PortletRenderer.MODE_EDIT_DEFAULTS)
        {
            out.print("<TD BGCOLOR=\"#999999\"><INPUT TYPE=\"button\" ");
            out.print("NAME=\"p_request\" VALUE=\"");
            out.print(res.getString(ProviderBundle.APPLY_LABEL));
            out.println("\" onClick=\"javascript:doSubmit('APPLY')\"></TD>");

            out.print("<TD BGCOLOR=\"#999999\"><INPUT TYPE=\"button\" ");
            out.print("NAME=\"p_request\" VALUE=\"");
            out.print(res.getString(ProviderBundle.OK_LABEL));
            out.println("\" onClick=\"javascript:doSubmit('OK')\"></TD>");

            out.print("<TD BGCOLOR=\"#999999\"><INPUT TYPE=\"button\" ");
            out.print("NAME=\"p_request\" VALUE=\"");
            out.print(res.getString(ProviderBundle.CANCEL_LABEL));
            out.print("\" onClick=\"javascript:window.location='");
            out.print(context.getBackURL());
            out.println("'\"></TD>");
        }
        else
        {
            out.print("<TD BGCOLOR=\"#999999\"><INPUT TYPE=\"button\" ");
            out.print("NAME=\"p_request\" VALUE=\"");
            out.print(res.getString(ProviderBundle.CLOSE_LABEL));

            if ( context.isRewriteUrls() )
            {
                String portletRef = request.getRenderContext().getPortletPageReference();
                out.print("\" onClick=\"javascript:p");
                out.print(portletRef);
                out.print(".backUrl()\"></TD>");
            }
            else
            {
                out.print("\" onClick=\"javascript:window.location='");
                out.print(context.getBackURL());
                out.println("'\"></TD>");
            }
        }

        out.println("</TR>");
        out.println("</TABLE>");
        out.println("</TD>");
        out.println("</TR>");
        out.println("</TABLE>");
        out.println("</TD></TR>");

        // end container
        out.println("</TABLE>");
        out.println("</CENTER>");

        // start Table for design form/display
        out.println("<CENTER>");
        out.println("<TABLE  WIDTH=\"90%\" BORDER=\"0\" CELLPADDING=\"0\" ");
        out.print("CELLSPACING=\"0\">");
        out.println("<TR><TD><BLOCKQUOTE><BLOCKQUOTE>");
        out.println("<TABLE " + BiDiUtils.getDirAttribute(l) + ">");
    }



    /**
     *  Utility method for completing the rendering of the Design form.
     *
     *  This method should be used in conjunction with renderDesignFormHeader()
     *  to work correctly. This routine emits the proper html tags to close
     *  the FORM including the standard look/feel for the Form container.
     *
     *  @param request the portlet render request.
     *  @param out the writer used to emit the html.
     */
    protected void renderDesignFormBodyEnd(PortletRenderRequest request,
                                           PrintWriter out)
        throws IOException
    {
        Locale l = request.getPortletReference().getLocale();

        // complete the form table
        out.println("</TABLE>");
        out.println("</BLOCKQUOTE></BLOCKQUOTE></TD></TR>");
        out.println("</TABLE>");
        out.println("</CENTER>");

        // now write the footer
        out.println("<CENTER>");
        out.println("<TABLE border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"90%\">");
        out.println("<TR>");
        out.println("<TD><IMG src=\"/images/pobtrans.gif\" width=\"1\" height=\"8\"></TD>");
        out.println("</TR>");
        out.println("<TR>");
        out.println("<TD>");

        // begin new style design form
        out.println("<TABLE width=\"100%\" border=\"0\" cellpadding=\"0\" ");
        out.print("cellspacing=\"0\">");
        out.println("<TR>");
        out.println("<TD align=\"" + BiDiUtils.getAlignment(l, RIGHT) + "\">");
        out.println("<TABLE border=\"0\" cellpadding=\"0\" cellspacing=\"0\">");
        out.println("<TR>");
        out.println("<TD align=\"" + BiDiUtils.getAlignment(l, RIGHT)
                    + "\" class=\"OraBgColorDark\"><IMG src=");
        out.print(getBorderImage(l, BOTTOM));
        out.print("></TD>");
        out.println("</TR>");
        out.println("</TABLE>");
        out.println("</TD>");
        out.println("</TR>");
        out.println("<TR>");
        out.println("<TD height=\"14\" class=\"OraBgColorDark\">&nbsp;</TD>");
        // end new style design form

        out.println("</TR>");
        out.println("</TABLE>");
        out.println("</TD>");
        out.println("</TR>");
        out.println("</TABLE>");
        out.println("</CENTER>");
    }


    /**
     *  Renders a portlet's titlebar. Portlets are responsible for rendering their container.  This method renders
     *  the standard portlet titlebar using information from the request and
     *  Portlet meta-data. Typically, clients will not use this method.  Rather they
     *  wil rely on renderPortletBegin() to render the entire container including the
     *  titlebar.  If however, renderPortletBegin is not used, this method is
     *  provided for convenience.
     *
     *  @param request the portlet render request
     *  @param title the label that should be displayed as the title.  if <b>null</b> then
     *  the method will render the static title retrieved via Portlet.getTitle();
     */
    protected void renderPortletTitlebar(PortletRenderRequest request,
                                         PrintWriter out,
                                         Map params)
        throws PortletException, IOException
    {
        int renderMode = request.getMode();
        PortletDefinition pd = request.getPortletInstance().getPortletDefinition();
        RenderContext renderContext = request.getRenderContext();

        //
        // Get the Portlet Title
        //
        String title = (String)params.get(PortletContainerRenderer.PORTLET_TITLE);
        if (title == null)
        {
            try
            {
                title = PortletRendererUtil.getTitle(request);
            }
            catch (AccessControlException e)
            {
                throw new PortletException(e);
            }
        }

        //
        // Open the table and row for the portlet header
        //
        out.print("<TABLE BORDER=\"0\" class=\"");
        out.print(PortletRenderer.PORTLET_HEADER_COLOR);
        out.println("\" CELLSPACING=\"0\" CELLPADDING=\"0\" WIDTH=\"100%\">");

        out.print("<TR class=\"");
        out.print(PortletRenderer.PORTLET_HEADER_COLOR);
        out.println("\">");

        //
        // The first table cell contains the curved graphic (10px)
        //
        out.print("<TD align=\"left\" NOWRAP class=\"");
        out.print(PortletRenderer.LEFT_CURVE);
        out.print("\" width=\"10\" ");
        out.println(" height=\"10\">&nbsp;</TD>");

        //
        // The second table cell contains the portlet title.  This cell
        // has a width of 100%.  It may contain the details link as well.
        //
        if (pd.hasShowDetails() &&
            renderContext.showDetails() &&
            !(renderMode == PortletRenderer.MODE_PREVIEW))
        {
            renderTitle(request, title, out, pd, true);
        }
        else
        {
            renderTitle(request, title, out, pd, false);
        }

        //
        // The third table cell contains zero or more of the following links:
        //  customize, help, about.
        //
        if (renderMode == PortletRenderer.MODE_PREVIEW)
        {
            renderDummyActions(out, pd, request);
        }
        else
        {
            renderActions(out, pd, request, title);
        }

        //
        // The fourth table cell contains the Collapse and Remove icons.
        //
        if (   request.getRenderContext().showRemove()
            || request.getRenderContext().showCollapse() )
        {
            // try to render system events
            try
            {
                ResourceBundle res = request.getProviderResource();

                String portletRef = request.getRenderContext().getPortletPageReference();

                // sys event 'collapse'
                if (request.getRenderContext().showCollapse())
                {
                    // render system event / icon for 'collapse portlet'

                    boolean isCollapsed = request.getRenderContext().isCollapsed();

                    NameValuePair[] eventParameters =
                    {
                      new NameValuePair( SYS_EVENT_PARAM_STATE, (isCollapsed?"0":"1") ),
                      new NameValuePair( SYS_EVENT_PARAM_PORTLET_REF, portletRef )
                    };

                    String image = isCollapsed ? SYS_EVENT_IMAGE_RESTORE
                                               : SYS_EVENT_IMAGE_MINIMIZE;

                    String imageAltText =  res.getString(
                                 isCollapsed ? ProviderBundle.RESTORE_LABEL
                                             : ProviderBundle.MINIMIZE_LABEL);

                    out.print("<TD>");
                    out.print( EventUtils.eventImageLink(
                                  request,
                                  image,              // image
                                  imageAltText,       // image Alt attribute
                                  SYS_EVENT_COLLAPSE, // event name
                                  eventParameters,    // event parameters
                                  false,              // encode parameters?
                                  false               // replace parameters?
                                  ) );
                    out.println("</TD>");
                }

                // sys event 'remove'
                if (request.getRenderContext().showRemove())
                {

                    // spacer between collapse and remove
                    if ( request.getRenderContext().showCollapse() )
                        out.println("<TD>&nbsp;</TD>");

                    // render system event / icon for 'remove portlet'

                    NameValuePair[] eventParameters =
                    {
                      new NameValuePair( SYS_EVENT_PARAM_PORTLET_REF, portletRef )
                    };

                    String imageAltText = 
                                  res.getString(ProviderBundle.REMOVE_LABEL);

                    out.print("<TD>");
                    out.print( EventUtils.eventImageLink(
                                  request,
                                  SYS_EVENT_IMAGE_REMOVE, // image
                                  imageAltText,
                                  SYS_EVENT_REMOVE,       // event name
                                  eventParameters,        // event parameters
                                  false,                  // encode parameters?
                                  false                   // replace parameters?
                                  ) );
                    out.println("</TD>");
                }

                // tiny space before the end of the row
                out.println("<TD>&nbsp;</TD>");
            }
            // if the event url is not present which can legitimately happen
            // (e.g. old version of portal or titlebar for a page as portlet)
            // we'll just not render these events hence we're ignoring these
            // exceptions
            catch( PortletException pe ) {}
            catch( IllegalArgumentException iae ) {}
        }
        else
        {
            //
            // If neither Collapse or Restore is shown, then show the
            // right-hand curved graphic
            //
            out.print("<TD class=\"");
            out.print(PortletRenderer.RIGHT_CURVE);
            out.println("\">&nbsp;</TD>");
        }

        //
        // Close the table and row for the portlet header
        //
        out.println("</TR>");
        out.println("</TABLE>");
    }


    /**
     * Renders the title.
     *
     *  @param request the portlet render request
     *  @param title Title
     *  @param out the output stream
     *  @param pd Portlet Definition
     *  @param isDetailsLinkRequired should the title also be a link 
     *          to the details page
     *
     *  @deprecated use UrlUtils.constructHTMLLink
     */
    protected void renderTitle(PortletRenderRequest request,
                               String title,
                               PrintWriter out,
                               PortletDefinition pd,
                               boolean isDetailsLinkRequired)
        throws java.io.IOException
    {
        Locale l = request.getLocale();
        String link = "";
        SimpleStringBuffer displayText = new SimpleStringBuffer(100);
        displayText.append("<font class=\"")
                   .append(PortletRenderer.PORTLET_HEADER_TEXT)
                   .append("\">")
                   .append(title)
                   .append("</font>");

        if (isDetailsLinkRequired)
        {
            out.print("<TD NOWRAP class=\"");
            out.print(PortletRenderer.PORTLET_HEADER_COLOR);
            out.print("\" width=\"100%\">");

            NameValuePair[] designParameters =
            {
                new NameValuePair( "_mode", 
                         Integer.toString(PortletRenderer.MODE_SHOW_DETAILS) ),
                new NameValuePair( "_title", title )
            };
            // get a full HTML link 
            link = UrlUtils.constructHTMLLink(request,
                                UrlUtils.DESIGN_LINK,
                                displayText.toString(),   
                                "",   // other HTML attributes
                                designParameters,
                                true,
                                false);
            out.print(link);
            out.println("&nbsp;&nbsp;&nbsp;</TD>");

        }
        else
        {
            out.print("<TD NOWRAP class=\"");
            out.print(PortletRenderer.PORTLET_HEADER_COLOR);
            out.print("\" width=\"100%\">");
            out.print(displayText.toString());
            out.println("&nbsp;&nbsp;&nbsp;</TD>");
        }

    }

    /**
     * Renders the title.
     *
     *  @param request the portlet render request
     *  @param title Title
     *  @param out the output stream
     *  @param pd Portlet Definition
     *  @param href part of an anchor tag got by caling getAnchorRef()
     *
     *  @deprecated use renderTitle(PortletRenderRequest, String, PrintWriter
     *                  PortletDefinition, boolean)
     */
    protected void renderTitle(PortletRenderRequest request,
                               String title,
                               PrintWriter out,
                               PortletDefinition pd,
                               String href)
        throws java.io.IOException
    {
        String endAnchor;
        if (href == null) {
            href = "";
            endAnchor = "";
        } else {
            endAnchor = "</a>";
        }

        out.print("<TD NOWRAP class=\"");
        out.print(PortletRenderer.PORTLET_HEADER_COLOR);
        out.print("\" width=\"100%\">");
        out.print(href);
        out.print("<font class=\"");
        out.print(PortletRenderer.PORTLET_HEADER_TEXT);
        out.print("\">");
        out.print(title);
        out.print(" </font>");
        out.print(endAnchor);
        out.println("&nbsp;&nbsp;&nbsp;</TD>");
    }

    protected void renderActions(PrintWriter out,
                                 PortletDefinition pd,
                                 PortletRenderRequest request,
                                 String title)
        throws java.io.IOException
    {
        out.print("<TD class=\"");
        out.print(PortletRenderer.PORTLET_HEADER_COLOR);
        out.println("\" NOWRAP>&nbsp;");

        ResourceBundle res = request.getProviderResource();
        RenderContext renderContext = request.getRenderContext();

        if (pd.hasShowEdit() && renderContext.showEdit())
        {
            boolean showCustomize = false;
            int userAuthLevel = request.getUser().getAuthenticationLevel();
            showCustomize = (userAuthLevel >= pd.getMinEditAuthLevel());

            if (showCustomize)
            {
                renderAction(out, pd, request, PortletRenderer.MODE_EDIT,
                             res.getString(ProviderBundle.CUSTOMIZE_LABEL), title);
            }
        }

        if (pd.hasHelp() && renderContext.showHelp())
        {
            renderAction(out, pd, request, PortletRenderer.MODE_HELP,
                         res.getString(ProviderBundle.HELP_LABEL), title);
        }


        if (pd.hasAbout() && renderContext.showAbout())
        {
            renderAction(out, pd, request, PortletRenderer.MODE_ABOUT,
                         res.getString(ProviderBundle.ABOUT_LABEL), title);
        }

        out.println("</TD>" );
    }

    protected void renderAction(PrintWriter out,
                                PortletDefinition pd,
                                PortletRenderRequest request,
                                int action,
                                String label,
                                String title)
        throws java.io.IOException
    {
        NameValuePair[] designParameters =
        {
            new NameValuePair( "_mode", Integer.toString(action) ),
            new NameValuePair( "_title", title )
        };
 
        SimpleStringBuffer displayText = new SimpleStringBuffer(100);
        displayText.append("<font class=\"")
                   .append(PortletRenderer.PORTLET_HEADER_LINK)
                   .append("\">")
                   .append(label)
                   .append("</font>");
        // get a full HTML link and then remove the </A> from the end
        String newHTMLRef = UrlUtils.constructHTMLLink(request,
                                UrlUtils.DESIGN_LINK,
                                displayText.toString(),   
                                "",   // other HTML attributes
                                designParameters,
                                true,
                                false);
        out.print(newHTMLRef);
        out.println("&nbsp;");
    }

    protected void renderDummyActions(PrintWriter out,
                                      PortletDefinition pd,
                                      PortletRenderRequest request)
        throws java.io.IOException
    {
        out.print("<TD class=\"");
        out.print(PortletRenderer.PORTLET_HEADER_COLOR);
        out.println("\" NOWRAP>&nbsp;");

        ResourceBundle res = request.getProviderResource();

        if (pd.hasShowEdit()) {
            renderDummyAction(out, res.getString(ProviderBundle.CUSTOMIZE_LABEL));
        }

        if (pd.hasHelp()) {
            renderDummyAction(out, res.getString(ProviderBundle.HELP_LABEL));
        }

        if (pd.hasAbout()) {
            renderDummyAction(out, res.getString(ProviderBundle.ABOUT_LABEL));
        }

        out.print("</TD>" );
    }

    protected void renderDummyAction(PrintWriter out, String label)
        throws java.io.IOException
    {
        out.print("<font class=\"");
        out.print(PortletRenderer.PORTLET_HEADER_LINK);
        out.print("\">");
        out.print(label);
        out.println("</font>&nbsp;");
    }

    /**
     *  gets an anchor ref without the display text or the trailing tag.
     *
     *  @param request the portlet render request
     *  @param pd Portlet Definition
     *  @param mode the display mode
     *  @param title Title
     *
     *  @deprecated use UrlUtils.constructHTMLLink
     */
    protected String getAnchorRef(PortletRenderRequest request,
                                  PortletDefinition pd,
                                  int mode,
                                  String title)
        throws java.io.IOException
    {
        NameValuePair[] designParameters =
        {
            new NameValuePair( "_mode", Integer.toString(mode) ),
            new NameValuePair( "_title", title )
        };

        // get a full HTML link and then remove the </A> from the end
        String newAnchorRef = UrlUtils.constructHTMLLink(request,
                            UrlUtils.DESIGN_LINK,
                            "",   // display text
                            "",   // other HTML attributes
                            designParameters,
                            true,
                            false);
        return newAnchorRef.substring(0, newAnchorRef.lastIndexOf("</A>") );  
    }

    static private String getBorderImage(Locale l, String vAlignment)
    {
        if(BiDiUtils.isBiDi(l))
        {
            if(vAlignment.equals(TOP))
            {
                return TOP_BIDI_IMAGE;
            }
            else
            {
                return BOTTOM_BIDI_IMAGE;
            }
        }
        else
        {
            if(vAlignment.equals(TOP))
            {
                return TOP_IMAGE;
            }
            else
            {
                return BOTTOM_IMAGE;
            }
        }
    }

//////////////////////////////////////////////////////////////////////////////
//
//                           DEPRECATED METHODS
//
//////////////////////////////////////////////////////////////////////////////


    /**
     *  Renders the header for the portlet SHOW mode
     *
     *  @param request the portlet render request
     *  @param out PrintWriter that should be used to write the portlet header
     *  @param params additional parameters passed in by the PortletRenderer
     *
     *  @deprecated use {@link #renderShowHeader(PortletRenderRequest,
     *                                           PrintWriter,
     *                                           Map)}
     */
    public void renderShowHeader(PortletRenderRequest request,
                                 PrintWriter out,
                                 ParameterMap params)
        throws PortletException, IOException
    {
        renderShowHeader(request, out, convertParameterMap(params));
    }


    /**
     *  Renders the footer for the portlet SHOW mode
     *
     *  @param request the portlet render request
     *  @param out PrintWriter that should be used to write the portlet header
     *  @param params additional parameters passed in by the PortletRenderer
     *
     *  @deprecated use {@link #renderShowFooter(PortletRenderRequest,
     *                                           PrintWriter,
     *                                           Map)}
     */
    public void renderShowFooter(PortletRenderRequest request,
                                 PrintWriter out,
                                 ParameterMap params)
        throws PortletException, IOException
    {
        renderShowFooter(request, out, convertParameterMap(params));
    }

    /**
     *  Renders the header for the portlet PREVIEW mode
     *
     *  @param request the portlet render request
     *  @param out PrintWriter that should be used to write the portlet header
     *  @param params additional parameters passed in by the PortletRenderer
     *
     *  @deprecated use {@link #renderPreviewHeader(PortletRenderRequest,
     *                                              PrintWriter,
     *                                              Map)}
     */
    public void renderPreviewHeader(PortletRenderRequest request,
                                    PrintWriter out,
                                    ParameterMap params)
        throws PortletException, IOException
    {
        renderPreviewHeader(request, out, convertParameterMap(params));
    }


    /**
     *  Renders the footer for the portlet PREVIEW mode
     *
     *  @param request the portlet render request
     *  @param out PrintWriter that should be used to write the portlet header
     *  @param params additional parameters passed in by the PortletRenderer
     *
     *  @deprecated use {@link #renderPreviewFooter(PortletRenderRequest,
     *                                              PrintWriter,
     *                                              Map)}
     */
    public void renderPreviewFooter(PortletRenderRequest request,
                                    PrintWriter out,
                                    ParameterMap params)
        throws PortletException, IOException
    {
        renderPreviewFooter(request, out, convertParameterMap(params));
    }

    /**
     *  Renders the header for the portlet SHOW_DETAILS mode
     *
     *  @param request the portlet render request
     *  @param out PrintWriter that should be used to write the portlet header
     *  @param params additional parameters passed in by the PortletRenderer
     *
     *  @deprecated use {@link #renderDetailsHeader(PortletRenderRequest,
     *                                              PrintWriter,
     *                                              Map)}
     */
    public void renderDetailsHeader(PortletRenderRequest request,
                                    PrintWriter out,
                                    ParameterMap params)
        throws PortletException, IOException
    {
        renderDetailsHeader(request, out, convertParameterMap(params));
    }


    /**
     *  Renders the footer for the portlet SHOW_DETAILS mode
     *
     *  @param request the portlet render request
     *  @param out PrintWriter that should be used to write the portlet header
     *  @param params additional parameters passed in by the PortletRenderer
     *
     *  @deprecated use {@link #renderDetailsFooter(PortletRenderRequest,
     *                                              PrintWriter,
     *                                              Map)}
     */
    public void renderDetailsFooter(PortletRenderRequest request,
                                    PrintWriter out,
                                    ParameterMap params)
        throws PortletException, IOException
    {
        renderDetailsFooter(request, out, convertParameterMap(params));
    }


    /**
     *  Renders the header for the portlet EDIT mode
     *
     *  @param request the portlet render request
     *  @param out PrintWriter that should be used to write the portlet header
     *  @param params additional parameters passed in by the PortletRenderer
     *
     *  @deprecated use {@link #renderEditHeader(PortletRenderRequest,
     *                                           PrintWriter,
     *                                           Map)}
     */
    public void renderEditHeader(PortletRenderRequest request,
                                 PrintWriter out,
                                 ParameterMap params)
        throws PortletException, IOException
    {
        renderEditHeader(request, out, convertParameterMap(params));
    }


    /**
     *  Renders the footer for the portlet EDIT mode
     *
     *  @param request the portlet render request
     *  @param out PrintWriter that should be used to write the portlet header
     *  @param params additional parameters passed in by the PortletRenderer
     *
     *  @deprecated use {@link #renderEditFooter(PortletRenderRequest,
     *                                           PrintWriter,
     *                                           Map)}
     */
    public void renderEditFooter(PortletRenderRequest request,
                                 PrintWriter out,
                                 ParameterMap params)
        throws PortletException, IOException
    {
        renderEditFooter(request, out, convertParameterMap(params));
    }


    /**
     *  Renders the header for the portlet EDIT_DEFAULTS mode
     *
     *  @param request the portlet render request
     *  @param out PrintWriter that should be used to write the portlet header
     *  @param params additional parameters passed in by the PortletRenderer
     *
     *  @deprecated use {@link #renderEditDefaultsHeader(PortletRenderRequest,
     *                                                   PrintWriter,
     *                                                   Map)}
     */
    public void renderEditDefaultsHeader(PortletRenderRequest request,
                                         PrintWriter out,
                                         ParameterMap params)
        throws PortletException, IOException
    {
        renderEditDefaultsHeader(request, out, convertParameterMap(params));
    }


    /**
     *  Renders the footer for the portlet EDIT_DEFAULTS mode
     *
     *  @param request the portlet render request
     *  @param out PrintWriter that should be used to write the portlet header
     *  @param params additional parameters passed in by the PortletRenderer
     *
     *  @deprecated use {@link #renderEditDefaultsFooter(PortletRenderRequest,
     *                                                   PrintWriter,
     *                                                   Map)}
     */
    public void renderEditDefaultsFooter(PortletRenderRequest request,
                                            PrintWriter out,
                                            ParameterMap params)
        throws PortletException, IOException
    {
        renderEditDefaultsFooter(request, out, convertParameterMap(params));
    }


    /**
     *  Renders the header for the portlet HELP mode
     *
     *  @param request the portlet render request
     *  @param out PrintWriter that should be used to write the portlet header
     *  @param params additional parameters passed in by the PortletRenderer
     *
     *  @deprecated use {@link #renderHelpHeader(PortletRenderRequest,
     *                                           PrintWriter,
     *                                           Map)}
     */
    public void renderHelpHeader(PortletRenderRequest request,
                                 PrintWriter out,
                                 ParameterMap params)
        throws PortletException, IOException
    {
        renderHelpHeader(request, out, convertParameterMap(params));
    }


    /**
     *  Renders the footer for the portlet HELP mode
     *
     *  @param request the portlet render request
     *  @param out PrintWriter that should be used to write the portlet header
     *  @param params additional parameters passed in by the PortletRenderer
     *
     *  @deprecated use {@link #renderHelpFooter(PortletRenderRequest,
     *                                           PrintWriter,
     *                                           Map)}
     */
    public void renderHelpFooter(PortletRenderRequest request,
                                 PrintWriter out,
                                 ParameterMap params)
        throws PortletException, IOException
    {
        renderHelpFooter(request, out, convertParameterMap(params));
    }


    /**
     *  Renders the header for the portlet ABOUT mode
     *
     *  @param request the portlet render request
     *  @param out PrintWriter that should be used to write the portlet header
     *  @param params additional parameters passed in by the PortletRenderer
     *
     *  @deprecated use {@link #renderAboutHeader(PortletRenderRequest,
     *                                            PrintWriter,
     *                                            Map)}
     */
    public void renderAboutHeader(PortletRenderRequest request,
                                  PrintWriter out,
                                  ParameterMap params)
        throws PortletException, IOException
    {
        renderAboutHeader(request, out, convertParameterMap(params));
    }


    /**
     *  Renders the footer for the portlet ABOUT mode
     *
     *  @param request the portlet render request
     *  @param out PrintWriter that should be used to write the portlet header
     *  @param params additional parameters passed in by the PortletRenderer
     *
     *  @deprecated use {@link #renderAboutFooter(PortletRenderRequest,
     *                                            PrintWriter,
     *                                            Map)}
     */
    public void renderAboutFooter(PortletRenderRequest request,
                                  PrintWriter out,
                                  ParameterMap params)
        throws PortletException, IOException
    {
        renderAboutFooter(request, out, convertParameterMap(params));
    }

    /**
     *  Utility method for rendering the About/Help form.  This method should be
     *  used in conjunction with renderInformationFormFooter() to work correctly.
     *  This routine emits the proper html FORM tag, appropriate hidden fields,
     *  the standard look/feel for the Form container, and the customize form
     *  'Close' button.
     *
     *  @deprecated use {@link #renderInformationFormHeader(PortletRenderRequest,
     *                                                      PrintWriter,
     *                                                      Map)}
     */
    protected void renderInformationFormHeader(PortletRenderRequest request,
                                               PrintWriter out,
                                               ParameterMap params)
        throws PortletException, IOException
    {
        renderInformationFormHeader(request, out, convertParameterMap(params));
    }


    /**
     *  Utility method for rendering the About/Help form.  This method should be
     *  used in conjunction with renderInformationFormFooter() to work correctly.
     *  This routine emits the proper html FORM tag, appropriate hidden fields,
     *  the standard look/feel for the Form container, and the customize form
     *  'Close' button.
     *
     *  @deprecated use {@link #renderInformationFormFooter(PortletRenderRequest,
     *                                                      PrintWriter,
     *                                                      Map)}
     */
    protected void renderInformationFormFooter(PortletRenderRequest request,
                                               PrintWriter out,
                                               ParameterMap params)
        throws PortletException, IOException
    {
        renderInformationFormFooter(request, out, convertParameterMap(params));
    }


    /**
     *  Renders a portlet's titlebar. Portlets are responsible for rendering
     *  their container.
     *
     *  This method renders the standard portlet titlebar using information
     *  from the request and Portlet meta-data. Typically, clients will not
     *  use this method.  Rather they wil rely on renderPortletHeader() to
     *  render the entire container including the titlebar.  If however,
     *  renderPortletHeader() is not used, this method is provided for
     *  convenience.
     *
     *  @param request the portlet render request
     *  @param title the label that should be displayed as the title.  if <b>null</b> then
     *  the method will render the static title retrieved via Portlet.getTitle();
     *
     *  @deprecated use {@link #renderPortletTitlebar(PortletRenderRequest,
     *                                                PrintWriter,
     *                                                Map)}
     */
    protected void renderPortletTitlebar(PortletRenderRequest request,
                                         PrintWriter out,
                                         ParameterMap params)
        throws PortletException, IOException
    {
        renderPortletTitlebar(request, out, convertParameterMap(params));
    }
}


