/*
 * Copyright (c) 2002-2003 by OpenSymphony
 * All rights reserved.
 */
package com.opensymphony.webwork.views.jsp;

import com.opensymphony.xwork.ActionContext;
import com.opensymphony.xwork.util.OgnlValueStack;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.io.IOException;

import java.net.URLEncoder;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpUtils;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.TagSupport;


/**
 * This tag is used to create a URL. You can use the "param" tag inside the
 * body to provide additional request parameters.
 *
 * @author Rickard Öberg (rickard@dreambean.com)
 * @author Brock Bulger (brockman_bulger@hotmail.com)
 * @version $Revision: 1.1 $
 */
public class URLTag extends TagSupport implements ParameterizedTag {
    //~ Static fields/initializers /////////////////////////////////////////////

    private static final Log log = LogFactory.getLog(URLTag.class);

    //~ Instance fields ////////////////////////////////////////////////////////

    protected Map params;
    protected String value;

    //~ Methods ////////////////////////////////////////////////////////////////

    public Map getParams() {
        return params;
    }

    public void setValue(String value) {
        this.value = value;
    }

    public void addParam(String key, Object value) {
        if (params == null) {
            params = new HashMap();
        }

        if (value == null) {
            params.remove(key);
        } else {
            params.put(key, value);
        }
    }

    public int doEndTag() throws JspException {
        HttpServletRequest request = (HttpServletRequest) pageContext.getRequest();
        HttpServletResponse response = (HttpServletResponse) pageContext.getResponse();
        StringBuffer link = new StringBuffer();

        if (value != null) {
            // Check if context path needs to be added
            // Add path to absolute links
            if (value.startsWith("/")) {
                link.append(request.getContextPath());
            }

            // Add page
            link.append(value);
        } else {
            // Go to "same page"
            String requestURI = (String) request.getAttribute("webwork.request_uri");

            if (requestURI == null) {
                requestURI = request.getRequestURI();
            }

            link.append(requestURI);
        }

        //if the value was not explicitly set grab the params from the request
        if ((params != null) && (params.size() > 0)) {
            if (link.toString().indexOf("?") == -1) {
                link.append("?");
            } else {
                link.append("&amp;");
            }

            // Set parameters
            Iterator enum = params.entrySet().iterator();

            while (enum.hasNext()) {
                Map.Entry entry = (Map.Entry) enum.next();
                String name = (String) entry.getKey();
                Object value = entry.getValue();

                if (value != null) {
                    link.append(name);
                    link.append('=');
                    link.append(URLEncoder.encode(value.toString()));
                }

                if (enum.hasNext()) {
                    link.append("&amp;");
                }
            }
        }

        String result;

        try {
            result = response.encodeURL(link.toString());
        } catch (Exception ex) {
            // Could not encode the URL for some reason
            // Use it unchanged
            result = link.toString();
        }

        String id = getId();

        if (id != null) {
            pageContext.setAttribute(id, value);
            pageContext.setAttribute(id, value, PageContext.REQUEST_SCOPE);
        } else {
            try {
                pageContext.getOut().print(result);
            } catch (IOException ex) {
                throw new JspException("IOError: " + ex.getMessage());
            }
        }

        return EVAL_PAGE;
    }

    public int doStartTag() throws JspException {
        OgnlValueStack vs = ActionContext.getContext().getValueStack();

        if ((vs != null) && (value != null)) {
            Object o = vs.findValue(value);

            if (o != null) {
                value = o.toString();
            }
        }

        params = null;

        if (value == null) {
            try {
                params = new HashMap();

                HttpServletRequest req = (HttpServletRequest) pageContext.getRequest();
                String query = req.getQueryString();

                if (query != null) {
                    int idx = query.lastIndexOf('#');

                    if (idx != -1) {
                        query = query.substring(0, idx - 1);
                    }

                    params.putAll(HttpUtils.parseQueryString(query));
                }
            } catch (Exception ex) {
                log.warn("Unable to put request parameters (" + ((HttpServletRequest) pageContext.getRequest()).getQueryString() + ") into parameter map.", ex);
            }
        }

        return EVAL_BODY_INCLUDE;
    }
}
