package org.apache.jetspeed.util;

/* ====================================================================
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2000-2001 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Apache" and "Apache Software Foundation" and
 *     "Apache Jetspeed" must not be used to endorse or promote products
 *    derived from this software without prior written permission. For
 *    written permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache" or
 *    "Apache Jetspeed", nor may "Apache" appear in their name, without
 *    prior written permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

//jetspeed support
import org.apache.jetspeed.portal.Portlet;
import org.apache.jetspeed.portal.PortletControl;
import org.apache.jetspeed.om.registry.PortletEntry;
import org.apache.jetspeed.services.Registry;
import org.apache.jetspeed.services.resources.JetspeedResources;
import org.apache.jetspeed.services.rundata.JetspeedRunData;

//turbine
import org.apache.turbine.util.*;
import org.apache.turbine.util.template.TemplateLink;


/**
 * <p>
 * URI lookup related functions.
 * </p>
 * 
 * <p>
 *  Functions to get an URI based on a type like info, edit, save
 *  and to identify the type of an URI.
 * </p>
 * 
 * <p>
 * To overwrite the default behaviour, specify one
 * of the following parameters in the JR.p file. URILookup
 * will then return the uri specified in the properties file.
 * </p>
 * <p>
 * all possible property parameters:
 * </p>
 * 
 * <UL>
 * <LI>URILookup.home.uri</LI>
 * <LI>URILookup.home.acceptlogin.uri</LI>
 * <LI>URILookup.home.restore.uri</LI>
 * <LI>URILookup.home.logout.uri</LI>
 * </UL>
 * <UL>
 * <LI>URILookup.info.uri</LI>
 * <LI>URILookup.info.mark.uri</LI>
 * </UL>
 * <UL>
 * <LI>URILookup.login.uri</LI>
 * </UL>
 * <UL>
 * <LI>URILookup.editaccount.uri</LI>
 * <LI>URILookup.editaccount.mark.uri</LI>
 * </UL>
 * <UL>
 * <LI>URILookup.back.uri</LI>
 * </UL>
 * <UL>
 * <LI>URILookup.enrollment.uri</LI>
 * </UL>
 * <UL>
 * <LI>URILookup.customizer.uri</LI>
 * <LI>URILookup.customizer.save.uri</LI>
 * </UL>
 * 
 * @author <A HREF="shesmer@raleigh.ibm.com">Stephan Hesmer</A>
 * @author <A HREF="sgala@apache.org">Santiago Gala</A>
 * @version $Id: URILookup.java,v 1.21 2003/03/04 00:05:15 sgala Exp $
 */

public class URILookup {

    /**
     * <P>show Jetspeed Home page<BR>
     * allowed Subtypes:<BR>
     * <UL>
     * <LI>SUBTYPE_NONE</LI>
     * <LI>SUBTYPE_RESTORE</LI>
     * <LI>SUBTYPE_MAXIMIZE</LI>
     * <LI>SUBTYPE_LOGOUT</LI>
     * <LI>SUBTYPE_ACCEPT_LOGIN</LI>
     * </UL>
     */
    public static final int TYPE_HOME               = 0;
    /**
     * <P>show some additional information about the portlet</P>
     * allowed Subtypes:<BR>
     * <UL>
     * <LI>SUBTYPE_NONE</LI>
     * <LI>SUBTYPE_MARK</LI>
     * </UL>
     */
    public static final int TYPE_INFO               = 1;

    /**
     * <P>show the edit page of the account</P>
     * allowed Subtypes:<BR>
     * <UL>
     * <LI>SUBTYPE_NONE</LI>
     * <LI>SUBTYPE_MARK</LI>
     * </UL>
     */
    public static final int TYPE_EDIT_ACCOUNT       = 3;
    /**
     * <P>show portlet customization</P>
     * allowed Subtypes:<BR>
     * <UL>
     * <LI>SUBTYPE_NONE</LI>
     * <LI>SUBTYPE_SAVE</LI>
     * </UL>
     */
    public static final int TYPE_CUSTOMIZE          = 4;
    /**
     * <P>show login screen</P>
     * allowed Subtypes:<BR>
     * <UL>
     * <LI>SUBTYPE_NONE</LI>
     * </UL>
     */
    public static final int TYPE_LOGIN              = 5;
    /**
     * <P>show the marked page<BR>
     * only used in function getURI, not in getURIType</P>
     * allowed Subtypes:<BR>
     * <UL>
     * <LI>SUBTYPE_NONE</LI>
     * </UL>
     */
    public static final int TYPE_BACK               = 6;

    /**
     * <P>creates new account<BR>
     * allowed Subtypes:<BR>
     * <UL>
     * <LI>SUBTYPE_NONE</LI>
     * </UL>
     */
    public static final int TYPE_ENROLLMENT         = 7;

    /**
     * apply no subtype to the url
     */
    public static final int SUBTYPE_NONE            = 0;
    /**
     * restore portlet to default size
     */
    public static final int SUBTYPE_RESTORE         = 1;
    /**
     * show the current portlet maximized<BR>
     * additionally, the current page is marked for restoring
     */
    public static final int SUBTYPE_MAXIMIZE        = 2;
    /**
     * mark the current page before processing portlet
     */
    public static final int SUBTYPE_MARK            = 3;
    /**
     * logs out the user
     */
    public static final int SUBTYPE_LOGOUT          = 4;
    /**
     * trues to login, after entering username and password
     */
    public static final int SUBTYPE_ACCEPT_LOGIN    = 5;
    /**
     * save user settings before processing portlet
     */
    public static final int SUBTYPE_SAVE            = 6;

    /**
     * Gets the URI for the specified type
     * 
     * @param aType    type of the URI
     * @param aSubType subtype of the URI
     * @param rundata  the RunData object
     * @return the URI
     * @exception JetspeedException
     */
    public static String getURI(int aType,
                                int aSubType,
                                RunData rundata)
        throws JetspeedException
    {
        return getURI(aType, 
                      aSubType,
                      null,
                      (String)null,
                      rundata);
    }

    /**
     * Gets the URI of the specified portlet with the specified type
     * 
     * @param aType    type of the URI
     * @param aSubType subtype of the URI
     * @param aPortlet Portlet the URI points to
     * @param rundata  the RunData object
     * @return the URI
     */
    public static String getURI(int aType, 
                                int aSubType, 
                                Portlet aPortlet, 
                                RunData rundata)
        throws JetspeedException
    {
        return getURI(aType,
                      aSubType,
                      null,
                      aPortlet, 
                      rundata);
    }

    /**
     * Gets the URI of the specified portlet with the specified type
     * 
     * @param aType    type of the URI
     * @param aSubType subtype of the URI
     * @param aPortletName Portlet the URI points to
     * @param rundata  the RunData object
     * @return the URI
     */
    public static String getURI(int aType,
                                int aSubType,
                                String aPortletName,
                                RunData rundata)
        throws JetspeedException
    {
        return getURI(aType,
                      aSubType,
                      null,
                      aPortletName,
                      rundata);
    }

    /**
     * Gets the URI of the specified portlet with the specified type and adds
     * given user data.
     * 
     * @param aType    type of the URI
     * @param aSubType subtype of the URI
     * @param userData string which should be added to the URL
     * @param aPortlet Portlet the URI points to
     * @param rundata  the RunData object
     * @return the URI
     */
    public static String getURI(int aType,
                                int aSubType,
                                String userData,
                                Portlet aPortlet,
                                RunData rundata)
        throws JetspeedException
    {
        if (aPortlet!=null) {
            aPortlet = getRealPortlet(aPortlet);
            return getURI(aType,
                          aSubType,
                          userData,
                          aPortlet.getName(),
                          rundata);
        }
        else {
            return getURI(aType,
                          aSubType,
                          userData,
                          (String)null,
                          rundata);
        }
    }

    /**
     * Gets the URI of the specified portlet with the specified type and adds
     * given user data.
     * 
     * @param aType    type of the URI
     * @param aSubType subtype of the URI
     * @param userData string which should be added to the URL
     * @param aPortletName Portlet the URI points to
     * @param rundata  the RunData object
     * @return the URI
     */
    public static String getURI(int aType,
                                int aSubType,
                                String userData,
                                String aPortletName,
                                RunData rundata)
        throws JetspeedException
    {
        String newURI = null;

        String propertiesParameter = "URILookup.";

        TemplateLink uri = new TemplateLink( rundata );

        if (aType==TYPE_HOME)
        {
            propertiesParameter += "home.";
            
            if (aSubType==SUBTYPE_RESTORE)
            {
                propertiesParameter += "restore.";

                newURI = getMarkedPage( rundata );
            }
            else if (aSubType==SUBTYPE_MAXIMIZE)
            {
                propertiesParameter += "maximize.";
                
                if (aPortletName==null)
                {
                    throw new JetspeedException( "A portlet is required to return an URI." );
                }
                uri.setAction( ACTION_MARKPAGE );
                uri.addPathInfo( "portlet", aPortletName );
            }
            else if (aSubType==SUBTYPE_LOGOUT)
            {
                propertiesParameter += "logout.";

                uri.setAction( ACTION_LOGOUT );
            }
            else if (aSubType==SUBTYPE_ACCEPT_LOGIN)
            {
                propertiesParameter += "acceptlogin.";

                uri.setAction( ACTION_ACCEPT_LOGIN );
            }
            else if (aSubType!=SUBTYPE_NONE)
            {
                throw new JetspeedException( "Incorrect Type / Subtype combination." );
            }
        }
        else if (aType==TYPE_INFO)
        {
            propertiesParameter += "info.";
            
            if (aPortletName==null)
            {
                throw new JetspeedException( "A portlet is required to return an URI." );
            }
            
            uri.setPage( SCREEN_INFO );
            uri.addPathInfo( "portlet", aPortletName );

            if (aSubType==SUBTYPE_MARK)
            {
                propertiesParameter += "mark.";

                uri.setAction( ACTION_MARKPAGE );
            }
            else if (aSubType!=SUBTYPE_NONE)
            {
                throw new JetspeedException( "Incorrect Type / Subtype combination." );
            }
        }
        else if (aType==TYPE_EDIT_ACCOUNT)
        {
            propertiesParameter += "editaccount.";
            
            uri.setPage( SCREEN_EDIT_ACCOUNT );

            if (aSubType==SUBTYPE_NONE)
            {
                uri.setAction( ACTION_PREPARE_SCREEN_EDIT_ACCOUNT );
            }
            else if (aSubType==SUBTYPE_MARK)
            {
                propertiesParameter += "mark.";
                
                if (aPortletName==null) 
                {
                    throw new JetspeedException( "A portlet is required to return an URI." );
                }

                // FIX ME: how can we add a prepare action and a mark action at the same time?
                //         But I think this branch is never used anyway. (?)
                uri.setAction( ACTION_MARKPAGE );
                uri.addPathInfo( "portlet", aPortletName );
            }
            else
            {
                throw new JetspeedException( "Incorrect Type / Subtype combination." );
            }
        }
        else if (aType==TYPE_CUSTOMIZE)
        {
            propertiesParameter += "customize.";
            
            uri.setPage( SCREEN_CUSTOMIZE );
            
            if( aPortletName != null )
            {
                uri.addPathInfo( "portlet", aPortletName );
            }
            if (aSubType==SUBTYPE_NONE)
            {
                if (ACTION_CUSTOMIZER!=null) uri.setAction( ACTION_CUSTOMIZER );
            }
            else if (aSubType==SUBTYPE_SAVE)
            {
                propertiesParameter += "save.";
                
                uri.setAction( ACTION_CUSTOMIZER_SAVE );
            }
            else
            {
                throw new JetspeedException( "Incorrect Type / Subtype combination." );
            }
        }
        else if (aType==TYPE_LOGIN)
        {
            propertiesParameter += "login.";
            
            if (aSubType==SUBTYPE_NONE)
            {
                uri.setPage( SCREEN_LOGIN );
            }
            else
            {
                throw new JetspeedException( "Incorrect Type / Subtype combination." );
            }
        }
        else if (aType==TYPE_BACK)
        {
            propertiesParameter += "back.";
            
            if (aSubType==SUBTYPE_NONE)
            {
                newURI = getMarkedPage( rundata );
            }
            else
            {
                throw new JetspeedException( "Incorrect Type / Subtype combination." );
            }
        }
        else if (aType==TYPE_ENROLLMENT)
        {
            propertiesParameter += "enrollment.";
            uri.setPage( SCREEN_NEWACCOUNT );
        }
        else
        {
            throw new JetspeedException( "Incorrect Type / Subtype combination." );
        }

        if (newURI==null)
        {
            newURI = uri.toString();
        }

        propertiesParameter += "uri";
        String propertiesParameterValue = JetspeedResources.getString( propertiesParameter, null );

        if (propertiesParameterValue!=null)
        {
            // found the parameter value, so replace the newURI with this one
            Log.info("URILookup: replaced uri "+newURI+" with "+propertiesParameterValue);
            newURI = propertiesParameterValue;
        }

        if (userData!=null)
        {
            newURI = addURIParameter(newURI, userData);
        }

        // remove sessionid, if exists
        if (newURI.indexOf(";jsessionid")!=-1)
        {
            newURI = newURI.substring(0,newURI.indexOf(";jsessionid"));
        }

        // adds sessionid if necessary
        newURI = rundata.getResponse().encodeURL( newURI );

        // remove starting slash, so that the URI is relative, and the Base-Tag is used
        // Note: if there is no starting slash, the function encodeURL inserts one slash in front of the URI
        if (newURI.startsWith("/"))
        {
            newURI = newURI.substring(1);
        }

        return newURI;
    }

    /**
     * Gets the type of the URI (e.g. TYPE_INFO, TYPE_EDIT).
     * 
     * @param rundata the RunData object
     * @return the type
     */
    public static int getURIType(RunData rundata)
    {
        return getURIType( null, rundata );
    }

    /**
     * Gets the type of the URI (e.g. TYPE_INFO, TYPE_EDIT).
     * The default return value is TYPE_HOME
     * <P>Hint:<BR>
     * Portlets should check for TYPE_EDIT_PORTLET and in any other case render the content</P>
     * 
     * @param aPortlet the associated portlet
     * @param rundata  the RunData object
     * @return the type
     */
    public static int getURIType(Portlet aPortlet, RunData rundata)
    {
        if (aPortlet!=null)
        {
            aPortlet = getRealPortlet(aPortlet);

            if (aPortlet.getName().equals(((JetspeedRunData)rundata).getPortlet()))
            {
                if (rundata.getScreen()!=null)
                {
                    if (rundata.getScreen().equals(SCREEN_INFO)) return TYPE_INFO;
                }
            }
        }
        
        if (rundata.getScreen()!=null)
        {
            if (rundata.getScreen().equals(SCREEN_CUSTOMIZE)) return TYPE_CUSTOMIZE;
            else if (rundata.getScreen().equals(SCREEN_NEWACCOUNT)) return TYPE_ENROLLMENT;
            else if (rundata.getScreen().equals(SCREEN_EDIT_ACCOUNT)) return TYPE_EDIT_ACCOUNT;
            else if (rundata.getScreen().equals(SCREEN_LOGIN)) return TYPE_LOGIN;
        }

        return TYPE_HOME;
    }

    /**
     * <P>Gets the subtype of the URI (e.g. SUBTYPE_SAVE).</P>
     * returns only the values<BR>
     * <UL>
     * <LI>SUBTYPE_NONE</LI>
     * <LI>SUBTYPE_MAXIMIZE</LI>
     * <LI>SUBTYPE_SAVE</LI>
     * </UL>
     * 
     * @param aPortlet the related portlet
     * @param rundata  the RunData object
     * @return the type
     * @exception JetspeedException
     */
    public static int getURISubType(Portlet aPortlet, RunData rundata)
        throws JetspeedException
    {
        if (rundata.getAction()!=null)
        {
            if (rundata.getAction().equals(ACTION_ACCEPT_LOGIN)) return SUBTYPE_ACCEPT_LOGIN;
            else if (rundata.getAction().equals(ACTION_LOGOUT)) return SUBTYPE_LOGOUT;
        }

        String value = (String)rundata.getRequest().getParameter("type");

        if (value!=null)
        {
            if (value.equalsIgnoreCase("save")) return SUBTYPE_SAVE;
        }

        if (aPortlet==null) throw new JetspeedException( "A portlet is required." );
        
        aPortlet = getRealPortlet(aPortlet);

        if (aPortlet.getName().equals(((JetspeedRunData)rundata).getPortlet()))
        {
            if ((rundata.getScreen()==null) || // no screen
                ( SCREEN_HOME.equals(rundata.getScreen())) ) // or Home-screen
            {
                return SUBTYPE_MAXIMIZE;
            }
        }

        return SUBTYPE_NONE;
    }

    /**
     * Gets the user specific data stored in the URI.
     * 
     * @param rundata the RunData object
     * @return the previous added user data
     * @see #getURI
     */
    public static String getURIUserData(RunData rundata)
    {
        return rundata.getParameters().getString("info");
    }

    /**
     * returns the WebApplication base directory.
     * 
     * @param rundata the rundata object
     * @return the URI
     */
    public static String getWebAppBaseDirURI(RunData rundata)
    {
        String ctxtPath = JetspeedResources.getString( JetspeedResources.CONTENT_ROOT_URL_KEY, "");
        // Add port only if it is not default port for protocol
        String port = "";
        if( "http".equals( rundata.getServerScheme() ) &&
            rundata.getServerPort() != 80 ) {
            port += ":" + rundata.getServerPort();
        }
        if( "https".equals( rundata.getServerScheme() ) &&
            rundata.getServerPort() != 443 ) {
            port += ":" + rundata.getServerPort();
        }
        try {
           ctxtPath = rundata.getRequest().getContextPath()+ctxtPath;
        } catch (Exception e) {
            // not servlet 2.2
        }
        return rundata.getServerScheme()+"://"+
               rundata.getServerName()+
               port + ctxtPath;
    }

    /**
     * Marks the current URI and stores it internally for later usage.
     *
     * @param rundata the RunData object
     */
    public static void markCurrentPage(RunData rundata)
    {
        javax.servlet.http.HttpSession session = rundata.getSession();
        if (session != null) {
            // delete action, if exists
            String uri = replaceTurbineURIParameter(rundata.getRequest().getRequestURI(), "action", null );
            
            session.setAttribute("URILookup_MarkedPage",uri);
// for servlet api 2.0
//            session.putValue("URILookup_MarkedPage",uri);
        }
    }

    /**
     * Marks the URI and stores it internally for later usage.
     *
     * @param aURI    the URI to store
     * @param rundata the RunData object
     */
    public static void markPage(String aURI, RunData rundata)
    {
        javax.servlet.http.HttpSession session = rundata.getSession();
        if (session != null) {
           // delete action, if exists
           aURI = replaceTurbineURIParameter(aURI, "action", null );

            session.setAttribute("URILookup_MarkedPage",aURI);
// for servlet api 2.0
//            session.putValue("URILookup_MarkedPage",aURI);
        }
    }

    /**
     * Gets the previous marked page as relative url.<br>
     * If no page was marked, the Jetspeed Home page is returned.
     * 
     * @return the marked page URI
     */
    public static String getMarkedPage(RunData rundata)
    {
        return getMarkedPage( rundata, true );
    }

    /**
     * Gets the previous marked page.<br>
     * If no page was marked, the Jetspeed Home page is returned.
     * 
     * @param relative specifies whether the returing URI should be relative
     * @return the marked page URI
     */
    public static String getMarkedPage(RunData rundata, boolean relative)
    {
        javax.servlet.http.HttpSession session = rundata.getSession();
        if (session != null) {
            String markedPage = (String)session.getAttribute("URILookup_MarkedPage");
// for servlet api 2.0
//            String markedPage = (String)session.getValue("URILookup_MarkedPage");
            if ((markedPage!=null) && (relative)) {
                // check if the URL is absolute. If so, than make it relative
                int idx = markedPage.indexOf("://");
                if (idx!=-1) { // found it
                    idx = markedPage.indexOf("/",idx+3); // search the next slash
                    if (idx!=-1) { // this is the slash after host and port
                        idx = markedPage.indexOf("/",idx+1); // search the next slash
                        if (idx!=-1) { // this is the slash after context
                            markedPage = markedPage.substring(idx);
                        }
                    }
                }
            }
            return markedPage;
        }
        return null;
    }

    /**
    <p>
    Given a ParameterParser, get a PortletEntry.  This is used so that when you have a
    URI created from PortletURIManager you can get back the PortletEntry that created
    it originally.
    </p>
    <p>
    Return null if we aren't able to figure out the PortletEntry
    </p>
    */
    public static final PortletEntry getEntry( ParameterParser params ) throws Exception
    {

        String name = params.getString("portlet");

        return (PortletEntry)Registry.getEntry(Registry.PORTLET, name );

    }

    /**
    * <p>
    * Checks that a Portlet is not a PortletControl. If it's a Control returns
    * the non-controlled Portlet entry.
    * </p>
    *
    * @return the portlet
    */
    private static Portlet getRealPortlet( Portlet portlet )
    {

        while (portlet instanceof PortletControl) {
            portlet = ((PortletControl)portlet).getPortlet();
        }

        return portlet;
    }

    /**
     * Replaces a turbine-based parameter in the URI.<BR>
     * /paramater/value/paramater/value/...
     * 
     * @param uri       the URI to modify
     * @param parameter the parameter to be replaced
     * @param value     the value
     * @return the new URI
     */
    private static String replaceTurbineURIParameter( String uri, String parameter, String value)
    {
        int idx = uri.indexOf("/" + parameter + "/");
        if (idx!=-1) {
            int idx2 = uri.indexOf("/",idx+parameter.length()+2);
            if (idx2==-1) // end of string
              idx2 = uri.length();
            uri = uri.substring(0,idx) + uri.substring(idx2);
        }
        if (value!=null) {
            if (!uri.endsWith("/")) uri += "/";
            uri += parameter + "/" + value;
        }
        return uri;
    }

    /**
     * removes all parameters of the URI (after the questionmark)<BR>
     * (i.e. http://localhost/jetspeed?type=save to http://localhost/jetspeed)
     * 
     * @param uri    the URI t be modified
     * @return the URI
     */
    private static String resetURIParameter( String uri )
    {
        if (uri.indexOf("?")!=-1) {
            uri = uri.substring(0,uri.indexOf("?"));
        }
        return uri;
    }

    /**
     * appends the parameter/value pair to the URI
     * 
     * @param uri       the URI to be modified
     * @param parameter the parameter to be added
     * @param value     the parameter value
     * @return the modified URI
     */
    private static String addURIParameter( String uri, String parameter, String value)
    {
        parameter = URIEncoder.encode( parameter );
        value = URIEncoder.encode( value );
        if (uri.indexOf("?")!=-1) {
            int idx = uri.indexOf( parameter + "=", uri.indexOf("?"));
            if (idx!=-1) { // parameter already in URI. remove it
                int idx2 = uri.indexOf("&", idx);
                if (idx2==-1) // end of string
                    idx2 = uri.length();
                uri = uri.substring(0,idx) + uri.substring(idx2);
            }
        }
        return addURIParameter( uri, parameter + "=" + value );
    }

    /**
     * appends the parameter/value pair to the URI
     * 
     * @param uri  the URI to be modified
     * @param data the data to be added (has to be the correct format - paramater=value)    
     * @return the modified URI
     */
    private static String addURIParameter( String uri,
                                           String data)
    {
        if (uri.indexOf("?")!=-1) uri += "&";
        else uri += "?";
        uri += data;
        return uri;
    }
    
    private static final String SCREEN_INFO                        = "Info";
    private static final String SCREEN_HOME                        = JetspeedResources.getString( "template.homepage" );
//    private static final String SCREEN_CUSTOMIZE                   = "Customize";
    private static final String SCREEN_CUSTOMIZE                   = JetspeedResources.getString( "customizer.screen" );
    private static final String SCREEN_LOGIN                       = JetspeedResources.getString( "template.login" );
    private static final String SCREEN_NEWACCOUNT                  = "NewAccount";
    private static final String SCREEN_EDIT_ACCOUNT                = "EditAccount";

    private static final String ACTION_CUSTOMIZER                  = JetspeedResources.getString( "customizer.action" );
    private static final String ACTION_MARKPAGE                    = "MarkRefPage";
    private static final String ACTION_LOGOUT                      = JetspeedResources.getString( "action.logout" );
    private static final String ACTION_ACCEPT_LOGIN                = JetspeedResources.getString( "action.login" );
    private static final String ACTION_CUSTOMIZER_SAVE             = "SavePageConfig";
    private static final String ACTION_PREPARE_SCREEN_EDIT_ACCOUNT = "PrepareScreenEditAccount";
}
