/*
 * RHQ Management Platform
 * Copyright (C) 2005-2008 Red Hat, Inc.
 * All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation version 2 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
package org.rhq.enterprise.gui.legacy.util;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.servlet.ServletException;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;

/**
 * Utilities class that provides general convenience methods.
 */
public class ActionUtils {
    /**
     * Return a new <code>ActionForward</code> based on the given one but with the specified parameter name and value
     * added to the new forward's path. NOTE: this method would be unnecessary if Struts allowed us to "unfreeze" the
     * <code>ForwardConfig</code> that is the superclass of the forward.
     *
     * @param     forward the ActionForward on which the new forward is based
     * @param     param   the name of the path parameter to add
     * @param     value   the value of the parameter to add
     *
     * @exception ServletException if encoding the path parameter fails
     */
    public static ActionForward changeForwardPath(ActionForward forward, Map params) throws Exception {
        String newUrl = changeUrl(forward.getPath(), params);
        ActionForward newForward = new ActionForward(forward.getName(), newUrl, forward.getRedirect());
        return newForward;
    }

    public static ActionForward changeForwardPath(ActionForward forward, String param, String value) throws Exception {
        HashMap params = new HashMap(1);
        params.put(param, value);
        return changeForwardPath(forward, params);
    }

    /**
     * Change a url by appending all of the <code>params</code> to it.
     *
     * @param  url    the original URL
     * @param  params the name-value pairs to append
     *
     * @return the new url
     */
    public static String changeUrl(String url, Map params) throws Exception {
        StringBuffer newUrl = new StringBuffer(url);

        if (params != null) {
            int index = url.indexOf('?');
            String separator = (index == -1) ? "?" : "&";

            Iterator i = params.keySet().iterator();
            while (i.hasNext()) {
                Object name = i.next();
                Object value = params.get(name);
                try {
                    if ((value != null) && value.getClass().isArray()) {
                        Object[] arr = (Object[]) value;
                        for (int j = 0; j < arr.length; ++j) {
                            _appendParam(newUrl, separator, name, arr[j]);
                        }
                    } else {
                        _appendParam(newUrl, separator, name, value);
                    }

                    if ("?".equals(separator)) {
                        separator = "&";
                    }
                } catch (UnsupportedEncodingException e) {
                    // how on earth could a jvm not support UTF-8??
                    throw new ServletException(
                        "could not encode ActionForward path parameters because the JVM does not support UTF-8!?", e);
                }
            }
        }

        return newUrl.toString();
    }

    /**
     * Return a URL path that will return control to the current action. This path is generated by adding the specified
     * parameters to the path of the forward specified as the "input" forward for the given mapping.
     *
     * @param     mapping the ActionMapping describing the current action's forwards
     * @param     params  a map containing the path parameters to add
     *
     * @exception ServletException if encoding the path parameter fails or input has not been set
     */
    public static String findReturnPath(ActionMapping mapping, Map params) throws Exception {
        ActionForward inputForward = mapping.getInputForward();
        if (inputForward.getPath() == null) {
            throw new ServletException("input cannot be null for returnPath on url: " + mapping.getPath());
        }

        ActionForward returnForward = ActionUtils.changeForwardPath(inputForward, params);
        return returnForward.getPath();
    }

    public static String findReturnPath(ActionMapping mapping, String param, String value) throws Exception {
        HashMap params = new HashMap(1);
        params.put(param, value);
        return findReturnPath(mapping, params);
    }

    private static void _appendParam(StringBuffer newPath, String separator, Object name, Object value)
        throws UnsupportedEncodingException {
        newPath.append(separator + URLEncoder.encode(name.toString(), "UTF-8"));
        newPath.append("=");
        if (value != null) {
            newPath.append(URLEncoder.encode(value.toString(), "UTF-8"));
        }
    }
}