/**
 * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
 *
 * The contents of this file are subject to the terms of the Liferay Enterprise
 * Subscription License ("License"). You may not use this file except in
 * compliance with the License. You can obtain a copy of the License by
 * contacting Liferay, Inc. See the License for the specific language governing
 * permissions and limitations under the License, including but not limited to
 * distribution rights of the Software.
 *
 *
 *
 */

package com.liferay.portal.layoutconfiguration.util.xml;

import com.liferay.portal.kernel.language.LanguageUtil;
import com.liferay.portal.kernel.portlet.PortletContainerUtil;
import com.liferay.portal.kernel.portlet.PortletLayoutListener;
import com.liferay.portal.kernel.portlet.PortletParameterUtil;
import com.liferay.portal.kernel.servlet.BufferCacheServletResponse;
import com.liferay.portal.kernel.servlet.DynamicServletRequest;
import com.liferay.portal.kernel.util.AutoResetThreadLocal;
import com.liferay.portal.kernel.util.MapUtil;
import com.liferay.portal.kernel.util.PrefixPredicateFilter;
import com.liferay.portal.kernel.util.Validator;
import com.liferay.portal.kernel.xml.Document;
import com.liferay.portal.kernel.xml.Element;
import com.liferay.portal.kernel.xml.SAXReaderUtil;
import com.liferay.portal.model.Portlet;
import com.liferay.portal.model.PortletConstants;
import com.liferay.portal.service.PortletLocalServiceUtil;
import com.liferay.portal.service.PortletPreferencesLocalServiceUtil;
import com.liferay.portal.theme.PortletDisplay;
import com.liferay.portal.theme.ThemeDisplay;
import com.liferay.portal.util.PortletKeys;
import com.liferay.portal.util.WebKeys;
import com.liferay.portlet.PortletPreferencesFactoryUtil;

import java.util.HashMap;
import java.util.Map;
import java.util.Stack;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author Brian Wing Shun Chan
 * @author Douglas Wong
 */
public class PortletLogic extends RuntimeLogic {

	public static final String CLOSE_1_TAG = "</runtime-portlet>";

	public static final String CLOSE_2_TAG = "/>";

	public static final String OPEN_TAG = "<runtime-portlet";

	public PortletLogic(
		HttpServletRequest request, HttpServletResponse response) {

		_request = request;
		_response = response;
	}

	@Override
	public String getClose1Tag() {
		return CLOSE_1_TAG;
	}

	@Override
	public String getOpenTag() {
		return OPEN_TAG;
	}

	@Override
	public String processXML(String xml) throws Exception {
		Document document = SAXReaderUtil.read(xml);

		Element rootElement = document.getRootElement();

		String portletId = rootElement.attributeValue("name");
		String instanceId = rootElement.attributeValue("instance");
		String queryString = rootElement.attributeValue("queryString");

		if (Validator.isNotNull(instanceId)) {
			portletId = PortletConstants.assemblePortletId(
				portletId, instanceId);
		}

		BufferCacheServletResponse bufferCacheServletResponse =
			new BufferCacheServletResponse(_response);

		queryString = PortletParameterUtil.addNamespace(portletId, queryString);

		Map<String, String[]> parameterMap = _request.getParameterMap();

		if (!portletId.equals(_request.getParameter("p_p_id"))) {
			parameterMap = MapUtil.filter(
				parameterMap, new HashMap<String, String[]>(),
				new PrefixPredicateFilter("p_p_"));
		}

		HttpServletRequest request = DynamicServletRequest.addQueryString(
			_request, parameterMap, queryString, false);

		ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
			WebKeys.THEME_DISPLAY);

		Portlet portlet = getPortlet(themeDisplay, portletId);

		PortletDisplay portletDisplay = themeDisplay.getPortletDisplay();

		Stack<String> embeddedPortletIds = _embeddedPortletIds.get();

		if (embeddedPortletIds == null) {
			embeddedPortletIds = new Stack<String>();

			_embeddedPortletIds.set(embeddedPortletIds);
		}

		if (embeddedPortletIds.search(portletDisplay.getId()) >
				-1) {

			String errorMessage = LanguageUtil.get(
				themeDisplay.getLocale(),
				"the-application-cannot-include-itself");

			request.setAttribute(
				"liferay-portlet:runtime:errorMessage", errorMessage);

			ServletContext servletContext =
				(ServletContext)request.getAttribute(WebKeys.CTX);

			RequestDispatcher requestDispatcher =
				servletContext.getRequestDispatcher(_ERROR_PAGE);

			requestDispatcher.include(request, bufferCacheServletResponse);

			return bufferCacheServletResponse.getString();
		}

		embeddedPortletIds.push(portletId);

		PortletContainerUtil.render(
			request, bufferCacheServletResponse, portlet);

		embeddedPortletIds.pop();

		return bufferCacheServletResponse.getString();
	}

	/**
	 * @see com.liferay.portal.model.impl.LayoutTypePortletImpl#getStaticPortlets(
	 *      String)
	 */
	protected Portlet getPortlet(ThemeDisplay themeDisplay, String portletId)
		throws Exception {

		Portlet portlet = PortletLocalServiceUtil.getPortletById(
			themeDisplay.getCompanyId(), portletId);

		// See LayoutTypePortletImpl#getStaticPortlets for why we only clone
		// non-instanceable portlets

		if (PortletPreferencesLocalServiceUtil.getPortletPreferencesCount(
				PortletKeys.PREFS_OWNER_TYPE_LAYOUT, themeDisplay.getPlid(),
				portletId) < 1) {

			PortletPreferencesFactoryUtil.getPortletSetup(_request, portletId);

			PortletLayoutListener portletLayoutListener =
				portlet.getPortletLayoutListenerInstance();

			if (portletLayoutListener != null) {
				portletLayoutListener.onAddToLayout(
					portletId, themeDisplay.getPlid());
			}
		}

		if (!portlet.isInstanceable()) {
			portlet = (Portlet)portlet.clone();
		}

		portlet.setStatic(true);

		return portlet;
	}

	private static final String _ERROR_PAGE =
		"/html/taglib/portlet/runtime/error.jsp";

	private static final ThreadLocal<Stack<String>> _embeddedPortletIds =
		new AutoResetThreadLocal<Stack<String>>(
			PortletLogic.class + "._embeddedPortletIds");

	private HttpServletRequest _request;
	private HttpServletResponse _response;

}