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

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import javax.faces.FacesException;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.PortletContext;
import javax.portlet.PortletException;
import javax.portlet.PortletRequest;
import javax.portlet.PortletRequestDispatcher;
import javax.portlet.PortletResponse;
import javax.portlet.PortletSession;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;

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

	private String namespace;

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

	public void setResponseCharacterEncoding(String encoding) {
		// Do nothing
	}

	public String getResponseCharacterEncoding() {
		PortletResponse portletResponse = getPortletResponse();
		if (portletResponse instanceof RenderResponse) {
			RenderResponse renderResponse = (RenderResponse) portletResponse;
			return renderResponse.getCharacterEncoding();
		} else {
			return null;
		}
	}

	public String getResponseContentType() {
		PortletResponse portletResponse = getPortletResponse();
		if (portletResponse instanceof RenderResponse) {
			RenderResponse renderResponse = (RenderResponse) portletResponse;
			return renderResponse.getContentType();
		} else {
			return null;
		}
	}

	public void setRequestCharacterEncoding(String encoding)
			throws UnsupportedEncodingException {
		PortletRequest portletRequest = getPortletRequest();
		if (portletRequest instanceof ActionRequest) {
			try {
				ActionRequest actionRequest = (ActionRequest) portletRequest;
				actionRequest.setCharacterEncoding(encoding);

			} catch (IllegalStateException e) {
				// TODO: handle exception
			}
		}
	}

	public String getRequestCharacterEncoding() {
		PortletRequest portletRequest = getPortletRequest();
		if (portletRequest instanceof ActionRequest) {
			ActionRequest actionRequest = (ActionRequest) portletRequest;
			return actionRequest.getCharacterEncoding();
		} else {
			return null;
		}
	}

	public String getRequestContentType() {
		return null;
	}

	private PortletContext getPortletContext() {
		return (PortletContext) getContext();
	}

	private PortletRequest getPortletRequest() {
		return (PortletRequest) getRequest();
	}

	private PortletResponse getPortletResponse() {
		return (PortletResponse) getResponse();
	}

	public String getInitParameter(String name) {
		return getPortletContext().getInitParameter(name);
	}

	protected String getNamespace() {
		if (null == namespace) {
			if (getResponse() instanceof RenderResponse) {
				namespace = ((RenderResponse) getResponse()).getNamespace();
			} else {
				throw new IllegalStateException(
						"Portlet namespace not availible in processAction phase");
			}
		}
		return namespace;
	}

	public URL getResource(String path) throws MalformedURLException {
		return getPortletContext().getResource(path);
	}

	public InputStream getResourceAsStream(String path) {
		return getPortletContext().getResourceAsStream(path);
	}

	public Set getResourcePaths(String path) {
		return getPortletContext().getResourcePaths(path);
	}

	protected Enumeration enumerateRequestParameterNames() {
		return getPortletRequest().getParameterNames();
	}

	protected Object getContextAttribute(String name) {
		return getPortletContext().getAttribute(name);
	}

	protected Enumeration getContextAttributeNames() {
		return getPortletContext().getAttributeNames();
	}

	protected Enumeration getInitParametersNames() {
		return getPortletContext().getInitParameterNames();
	}

	protected Object getRequestAttribute(String name) {
		return getPortletRequest().getAttribute(name);
	}

	protected Enumeration getRequestAttributeNames() {
		return getPortletRequest().getAttributeNames();
	}

	public Map getRequestParameterValuesMap() {
		return getPortletRequest().getParameterMap();
	}

	protected Object getRequestParameterValues(String name) {
		return getPortletRequest().getParameterValues(name);
	}

	protected Object getRequestHeader(String name) {
		return getPortletRequest().getProperty(name);
	}

	protected Enumeration getRequestHeaderNames() {
		return getPortletRequest().getPropertyNames();
	}

	protected String[] getRequestHeaderValues(String name) {
		Enumeration properties = getPortletRequest().getProperties(name);
		List values = new ArrayList();
		while (properties.hasMoreElements()) {
			Object value = (Object) properties.nextElement();
			values.add(value);
		}
		return (String[]) values.toArray(EMPTY_STRING_ARRAY);
	}

	protected Object getRequestParameter(String name) {
		return getPortletRequest().getParameter(name);
	}

	protected Object getSessionAttribute(String name) {
		return getPortletRequest().getPortletSession(true).getAttribute(name,
				PortletSession.PORTLET_SCOPE);
	}

	protected Enumeration getSessionAttributeNames() {
		return getPortletRequest().getPortletSession(true).getAttributeNames(
				PortletSession.PORTLET_SCOPE);
	}

	protected void removeContextAttribute(String name) {
		getPortletContext().removeAttribute(name);
	}

	protected void removeRequestAttribute(String name) {
		getPortletRequest().removeAttribute(name);
	}

	protected void removeSessionAttribute(String name) {
		getPortletRequest().getPortletSession(true).removeAttribute(name,
				PortletSession.PORTLET_SCOPE);
	}

	protected void setContextAttribute(String name, Object value) {
		getPortletContext().setAttribute(name, value);
	}

	protected void setRequestAttribute(String name, Object value) {
		getPortletRequest().setAttribute(name, value);
	}

	protected void setSessionAttribute(String name, Object value) {
		getPortletRequest().getPortletSession(true).setAttribute(name, value,
				PortletSession.PORTLET_SCOPE);
	}

	public void dispatch(String path) throws IOException {
		if (null == path) {
			throw new NullPointerException("Path to new view is null");
		}
		if (!(getRequest() instanceof RenderRequest && getResponse() instanceof RenderResponse)) {
			throw new IllegalStateException(
					"Dispatch to new view not at render phase");
		}
		PortletRequestDispatcher dispatcher = getPortletContext()
				.getRequestDispatcher(path);
		if (null == dispatcher) {
			throw new IllegalStateException(
					"Dispatcher for render request is not created");
		}
		try {
			dispatcher.include((RenderRequest) getRequest(),
					(RenderResponse) getResponse());
		} catch (PortletException e) {
			throw new FacesException(e);
		}
	}

	public String encodeActionURL(String url) {
		if (null == url) {
			throw new NullPointerException();
		}
		return url;
	}

	public String encodeResourceURL(String url) {
		return getPortletResponse().encodeURL(url);
	}

	public String getAuthType() {
		return getPortletRequest().getAuthType();
	}

	public String getRemoteUser() {
		return getPortletRequest().getRemoteUser();
	}

	public String getRequestContextPath() {
		return getPortletRequest().getContextPath();
	}

	public Locale getRequestLocale() {
		return getPortletRequest().getLocale();
	}

	public Iterator getRequestLocales() {
		return new EnumerationIterator(getPortletRequest().getLocales());
	}

	public String getRequestPathInfo() {
		String pathInfo = (String) getRequestParameter(VIEW_ID_PARAMETER);
		if (null == pathInfo) {
			pathInfo = (String) getRequestAttribute(VIEW_ID_PARAMETER);
		}
		return pathInfo;
	}

	public String getRequestServletPath() {
		return null;
	}

	public Object getSession(boolean create) {
		return getPortletRequest().getPortletSession();
	}

	public Principal getUserPrincipal() {
		return getPortletRequest().getUserPrincipal();
	}

	public boolean isUserInRole(String role) {
		return getPortletRequest().isUserInRole(role);
	}

	public void log(String message) {
		getPortletContext().log(message);
	}

	public void log(String message, Throwable exception) {
		getPortletContext().log(message, exception);
	}

	public void redirect(String url) throws IOException {
		if (null == url) {
			throw new NullPointerException("Path to redirect is null");
		}
		if (!(getRequest() instanceof ActionRequest && getResponse() instanceof ActionResponse)) {
			throw new IllegalStateException(
					"Redirect to new url not at action phase");
		}
		((ActionResponse) getResponse()).sendRedirect(url);
	}
}
