/*
 * WebWork, Web Application Framework
 *
 * Distributable under Apache license.
 * See terms of license at opensource.org
 */
package webwork.view.taglib;

import org.apache.commons.logging.*;

import javax.servlet.http.*;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspTagException;
import javax.servlet.jsp.PageContext;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import webwork.util.TextUtil;
import webwork.util.BeanUtil;

/**
 * This tag is used to create a URL. You can use the "param" tag inside the body to provide
 *      additional request parameters.
 *
 * @see ParamTag
 * @author Rickard Öberg (rickard@dreambean.com)
 * @version $Revision: 1.18 $
 */
public class URLTag
      extends WebWorkBodyTagSupport
      implements ParamTag.Parametric {
   // Attributes ----------------------------------------------------
   protected String page;
   protected String valueAttr;
   protected String value;
   protected String includeParamsAttr;
   protected Map params;

   // Public --------------------------------------------------------
   /**
   * The includeParams attribute may have the value 'none', 'get' or 'all'.
   * It is used when the url tag is used without a value or page attribute.
   * If no includeParams is specified then 'all' is used.
   * none - include no parameters in the URL
   * get  - include only GET parameters in the URL
   * all  - include both GET and POST parameters in the URL (default)
   */
   public static final String NONE = "none";
   public static final String GET = "get";
   public static final String ALL = "all";

   public void setPage(String aName) {
      page = aName;
   }

   public void setValue(String aName) {
      valueAttr = aName;
   }
   
   public void setIncludeParams(String aName) {
      includeParamsAttr = aName;
   }

   public void addParameter(String name, Object value) {
      if (params == null)
         params = new HashMap();

      if (value == null)
         params.remove(name);
      else {
         params.put(name, BeanUtil.toStringValue(value));
      }
   }

   // BodyTag implementation ----------------------------------------
   public int doStartTag() throws JspException {
      if (page == null) {
         if (valueAttr != null)
            value = findString(valueAttr);
      } else {
         value = page;
      }
      params = null;

      //no explicit url set so attach params from current url, do
      //this at start so body params can override any of these they wish.
      if (value==null) {
         try {
            if (params==null) {
               params = new HashMap();
            }
            String includeParams = null;
            if (includeParamsAttr != null)
            {
               includeParams = findString(includeParamsAttr);
            }
            
            if (includeParams == null || includeParams.equals(ALL))
            {
               params.putAll(((HttpServletRequest) pageContext.getRequest()).getParameterMap());
            }
            else if (includeParams.equals(GET))
            {
               // Parse the query string to make sure that the parameters come from the query, and not some posted data
               HttpServletRequest req = ((HttpServletRequest) pageContext.getRequest());
               String query = req.getQueryString();
               if (query != null)
               {
                  // Remove possible #foobar suffix
                  int idx = query.lastIndexOf('#');
                  if (idx != -1)
                     query = query.substring(0, idx-1);
                  params.putAll(HttpUtils.parseQueryString(query));
               }
            }
            else if (!includeParams.equals(NONE))
            {
               LogFactory.getLog(this.getClass()).warn("Unknown value for includeParams parameter to URL tag: " + includeParams);           
            }
         } catch (Exception e) {
            LogFactory.getLog(this.getClass()).warn("Unable to put request parameters ("+((HttpServletRequest) pageContext.getRequest()).getQueryString()+") into parameter map.", e);
         }
      }
      return EVAL_BODY_TAG;
   }

   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");
//         String contextPath=(String)request.getAttribute("webwork.context_path");
         if (requestURI == null) requestURI = request.getRequestURI();
//         if(contextPath==null) contextPath=request.getContextPath();
         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) {
               if (value instanceof String) {
                  link.append(name);
                  link.append('=');
                  link.append(URLEncoder.encode((String) value));
               } else {
                  String[] values = (String[]) value;
                  link.append(name);
                  link.append('=');
                  link.append(URLEncoder.encode(values[0]));
               }
            }

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

      String result;
      try {
         //Category.getInstance(this.getClass().getName()).debug(link.toString());
         result = response.encodeURL(link.toString());
      } catch (Exception e) {
         // Could not encode URL for some reason
         // Use it unchanged
         result = link.toString();
      }

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

      return EVAL_PAGE;
   }
}

