/**
 * 
 */
package org.ajax4jsf.portlet.context;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Pattern;

import javax.faces.FacesException;
import javax.faces.render.ResponseStateManager;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.PortletConfig;
import javax.portlet.PortletContext;
import javax.portlet.PortletException;
import javax.portlet.PortletRequest;
import javax.portlet.PortletRequestDispatcher;
import javax.portlet.PortletResponse;
import javax.portlet.PortletURL;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import javax.portlet.faces.Bridge;

import org.ajax4jsf.portlet.application.PortletViewState;

/**
 * @author asmirnov
 * 
 */
public class PortletRenderContextImpl extends PortletContextImpl {

	public String getResponseCharacterEncoding() {
		RenderResponse renderResponse = (RenderResponse) getPortletResponse();
		return renderResponse.getCharacterEncoding();
	}

	public String getResponseContentType() {
		RenderResponse renderResponse = (RenderResponse) getPortletResponse();
		return renderResponse.getContentType();
	}

	public void setRequestCharacterEncoding(String encoding)
			throws UnsupportedEncodingException {
		// Do nothing.
	}

	public String getRequestCharacterEncoding() {
		return null;
	}

	protected String getNamespace() {
		return ((RenderResponse) getPortletResponse()).getNamespace();
	}

	private Map<String, String[]> _requestParameters;

	public PortletRenderContextImpl(PortletContext context,
			PortletRequest request, PortletResponse response) {
		super(context, request, response);
	}

	protected Object getRequestParameter(String name) {
		Object[] values = (Object[]) getRequestParameterValues(name);
		if (null != values) {
			return values[0];
		} else {
			return null;
		}
	}

	protected Enumeration enumerateRequestParameterNames() {
		Map<String, String[]> requestParameters = getSavedRequestParameters();
		if (null != requestParameters) {
			return Collections.enumeration(requestParameters.keySet());
		} else {
			return Collections.enumeration(Collections.EMPTY_LIST);
		}
	}

	@Override
	public void redirect(String url) throws IOException {
		if (null == url) {
			throw new NullPointerException("Path to redirect is null");
		}
		PortalActionURL actionURL = new PortalActionURL(url);
      if((!actionURL.isInContext(getRequestContextPath()) && null == actionURL.getParameter(VIEW_ID_PARAMETER)) || "true".equalsIgnoreCase(actionURL.getParameter(Bridge.DIRECT_LINK))){
//			dispatch(url);

//         throw new IllegalStateException(
//			"Redirect to new url not at action phase");
		} else {
		// HACK - if page is in the context, just treat it as navigation case
			internalRedirect(actionURL);
		}
	}

	@Override
	protected String createActionUrl(Map<String, String> parameters) {
		RenderResponse renderResponse = (RenderResponse) getPortletResponse();
		PortletURL portletURL = renderResponse.createActionURL();
		portletURL.setParameter(AbstractExternalContext.NAMESPACE_PARAMETER,
				renderResponse.getNamespace());
		for (Iterator<Entry<String, String>> param = parameters.entrySet()
				.iterator(); param.hasNext();) {
			Entry<String, String> parameter = param.next();
			portletURL.setParameter(parameter.getKey(), parameter.getValue());
		}
      return portletURL.toString();
	}

	public void dispatch(String path) throws IOException {
		if (null == path) {
			throw new NullPointerException("Path to new view is null");
		}
      PortletRequestDispatcher dispatcher = getPortletContext()
				.getRequestDispatcher(path);
		if (null == dispatcher) {
			throw new IllegalStateException(
					"Dispatcher for render request is not created");
		}
		try {
			RenderRequest renderRequest = (RenderRequest) getPortletRequest();
			RenderResponse portletResponse = (RenderResponse) getPortletResponse();
			dispatcher.include(renderRequest, portletResponse);
		} catch (PortletException e) {
			throw new FacesException(e);
		}
	}

	/**
	 * @return
	 */
	@SuppressWarnings("unchecked")
	private Map<String, String[]> getSavedRequestParameters() {
		if (null == _requestParameters) {
			// Get parameters ( all or a View state only ) restored as requered
			// in the JSR 301 PLT 5.1
			Object preserveRequestAttr = Boolean.FALSE;
			PortletConfig portletConfig = (PortletConfig) getRequestAttribute(PORTLET_CONFIG_ATTRIBUTE);
			if (null != portletConfig) {
				String portletPreserveParamName = Bridge.PORTLET_ATTR_PREFIX
						+ portletConfig.getPortletName()
						+ Bridge.PRESERVE_ACTION_PARAM_ATTR_SUFFIX;
				preserveRequestAttr = getContextAttribute(portletPreserveParamName);
			}
			Map<String, String[]> parameters = (Map<String, String[]>) getRequestAttribute(PortletViewState.REQUEST_PARAMETERS_ATTRIBUTE);
			if (Boolean.TRUE.equals(preserveRequestAttr)) {
				_requestParameters = parameters;
			} else if (null != parameters) {
				_requestParameters = new HashMap<String, String[]>();
				String[] viewState = parameters
						.get(ResponseStateManager.VIEW_STATE_PARAM);
				if (null != viewState) {
					_requestParameters.put(
							ResponseStateManager.VIEW_STATE_PARAM, viewState);

				}
			}
		}
		return _requestParameters;
	}

	protected Object getRequestParameterValues(String name) {
		Map<String, String[]> requestParameters = getSavedRequestParameters();
		if (null != requestParameters) {
			return requestParameters.get(name);
		} else {
			return null;
		}
	}

}
