// Copyright (c) 2001 Oracle Corporation
package oracle.portal.provider.v1.http;

import javax.servlet.http.*;

import oracle.portal.provider.v1.*;
import oracle.portal.utils.xml.v1.*;
import oracle.webdb.utils.SimpleStringBuffer;

/**
 * BaseManagedRenderer is the JPDK's base implementation of the {@link
 * oracle.portal.provider.v1.ManagedRenderer} interface. BaseManagedRenderer
 * maintains information about the page's content type (MIME type) and cache
 * expiry time. These may be set via calls to the appropriate methods or
 * declared at page level in <code>provider.xml</code> using the
 * <code>&ltcontentType&gt</code> and <code>&ltpageExpires&gt</code> tags.<p>
 *
 * BaseManagedRenderer also maintains a reference to its parent {@link
 * oracle.portal.provider.v1.RenderManager} object so that page level
 * attributes can be defaulted at {@link
 * oracle.portal.provider.v1.RenderManager} level.
 *
 * Implementations needing to set HTTP headers other than content type and page
 * expiry should subclass BaseManagedRenderer and override the {@link
 * #prepareResponse(PortletRenderRequest)} method, taking care to call
 * <code>super.prepareResponse(pr)</code> as a first step.
 */
public abstract class BaseManagedRenderer
    implements ManagedRenderer, InitializableXMLObject
{
    protected PortletPageLocator mParent;
    private String mContentType;
    private String mCharacterEncoding = null;
    private int mPageExpires = -1;

    /**
     * Performs the steps required to initialize a BaseManagedRenderer object
     * after it has been constructed.
     * @param o the object that will become this object's parent
     * @exception NodeHandlerException if an error occurs while initializing
     * this object
     */
    public void preInitialize(Object o) throws NodeHandlerException
    {
        // Keep a pointer to the PortletPageLocator that should be this object's parent
        if(o instanceof PortletPageLocator)
        {
            mParent = (PortletPageLocator)o;
            
        }
        else
        {
            throw new NodeHandlerException("Parent of a ManagedRenderer must be a PortletPageLocator");
        }
    }

    /**
     * Performs the extra steps required to initialize and validate a
     * BaseManagedRenderer object once its properties have been set with the
     * appropriate accessor methods.
     * @exception NodeHandlerException if not all properties have been set
     * correctly
     */
    public void postInitialize() throws NodeHandlerException
    {
    }

    /**
     *  Sets the default MIME type to be used as the content type for this
     *  renderer's pages.
     *
     *  @param contentType MIME type to be used as the content type for this
     *  renderer's pages.
     */
    public void setContentType(String contentType)
    {
        mContentType = contentType;
    }

    /**
     *  Gets the default MIME type to be used as the content type for this
     *  renderer's pages. If a content type hasn't been set explicitly on this
     *  <code>BaseManagedRenderer</code>, then the value returned by calling
     *  the {@link PortletPageLocator#getContentType()} method on the parent
     *  <code>PortletPageLocator</code> is returned.
     *
     *  @return MIME type to be used as the content type for this renderer's
     *  pages.
     */
    public String getContentType()
    {
        if(mContentType == null)
        {
            return mParent.getContentType();
        }
        return mContentType;
    }

    /**
     *  Sets the Default IANA character encoding to be used for this renderer's
     *  pages.
     *
     *  @param charSet IANA character encoding to be used for this renderer's
     *  pages
     */
    public void setCharSet(String encoding)
    {
        mCharacterEncoding = encoding;
    }

    /**
     *  Gets the Default IANA character encoding to be used for this renderer's
     *  pages. If a character encoding hasn't been set explicitly on this
     *  <code>BaseManagedRenderer</code>, then the value returned by calling
     *  the {@link PortletPageLocator#getCharSet()} method on the parent
     *  <code>PortletPageLocator</code> is returned.
     *
     *  @return IANA character encoding to be used for this renderer's pages
     */
    public String getCharSet()
    {
        if (mCharacterEncoding == null)
        {
            return mParent.getCharSet();
        }
        return mCharacterEncoding;
    }

    /**
     * Sets the expiration time (in minutes) of the page cache.
     *
     * @param expires the number of minutes a page should be cached by
     * the Portal.
     */
    public void setPageExpires(int expires)
    {
        mPageExpires = expires;
    }

    /**
     * Sets the expiration time (in minutes) of the page cache.
     *
     * @param expires String representation of the integer number of minutes a
     * page should be cached by the Portal.
     */
    public void setPageExpires(String expires)
    {
        setPageExpires(Integer.parseInt(expires));
    }

    /**
     * Gets the page expriation (in minutes). If a page expiration hasn't been
     * set explicitly on this <code>BaseManagedRenderer</code>, then the
     * value returned by calling the {@link
     * PortletPageLocator#getPageExpires()} method on the parent
     * <code>PortletPageLocator</code> is returned.
     *
     * @return page expiration in minutes.  If non-zero it indicates the
     * number of minutes the page should be cached by the Portal.
     */
    public int getPageExpires()
    {
        if(mPageExpires == -1)
        {
            return mParent.getPageExpires();
        }
        return mPageExpires;
    }

    /**
     * Sets default HTTP headers for the response. This consists of
     * <code>content type</code> and page expiry time, both of which may be
     * set programatically via calls to {@link #setContentType(String)} and
     * {@link #setPageExpires(String)} or declaritivley in
     * <code>provider.xml</code> with the <code>&ltcontentType&gt</code> and
     * <code>&ltpageExpires&gt</code> tags.
     *
     * @param pr a {@link PortletRenderRequest}
     * @return boolean flag indicating whether or not to render the portlet's
     * contents (e.g. is the cached version still valid)
     */    
    public boolean prepareResponse(PortletRenderRequest pr)
        throws PortletException, PortletNotFoundException
    {
        // Since the render request attributes should be visible to renderers
        // accessing the (wrapped) servlet request directly, we have to tell the
        // servlet request about this PortletRenderRequest
        Object sr = pr.getAttribute(HttpProvider.SERVLET_REQUEST);
        if(sr instanceof Servlet20RequestWrapper)
        {
            ((Servlet20RequestWrapper)sr).setPortletRenderRequest(pr);
        }

        pr.setContentType(getContentType());
        pr.setCharacterEncoding(getCharSet());

        //Do the expires logic (originally in PageRenderer)
        int pageExpires = getPageExpires();
        if (pageExpires > 0 &&
            pr.getMode() != PortletRenderer.MODE_EDIT &&
            pr.getMode() != PortletRenderer.MODE_EDIT_DEFAULTS)
        {
            HttpPortletRendererUtil.setCacheExpires(pr,
                                                    HttpProvider.USER_LEVEL,
                                                    pageExpires);
        }
        return true;
    }
}
