/**
 * Copyright (c) 2000-present 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.frontend.js.spa.web.internal.servlet.taglib.util;

import com.liferay.frontend.js.spa.web.configuration.SPAConfiguration;
import com.liferay.frontend.js.spa.web.configuration.SPAConfigurationActivator;
import com.liferay.frontend.js.spa.web.configuration.SPAConfigurationUtil;
import com.liferay.petra.string.StringPool;
import com.liferay.portal.kernel.json.JSONArray;
import com.liferay.portal.kernel.json.JSONFactoryUtil;
import com.liferay.portal.kernel.service.PortletLocalService;
import com.liferay.portal.kernel.servlet.BrowserSnifferUtil;
import com.liferay.portal.kernel.servlet.ServletResponseConstants;
import com.liferay.portal.kernel.theme.ThemeDisplay;
import com.liferay.portal.kernel.util.*;

import java.lang.reflect.Field;

import java.util.Locale;
import java.util.Objects;
import java.util.ResourceBundle;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ReferencePolicy;
import org.osgi.service.component.annotations.ReferencePolicyOption;

/**
 * @author Bruno Basto
 */
@Component(
	configurationPid = "com.liferay.frontend.js.spa.web.configuration.SPAConfiguration",
	service = SPAUtil.class
)
public class SPAUtil {

	public long getCacheExpirationTime(long companyId) {
		long cacheExpirationTime = 0;

		SPAConfiguration spaConfiguration =
			_spaConfigurationActivator.getSPAConfiguration();

		cacheExpirationTime = GetterUtil.getLong(
			spaConfiguration.cacheExpirationTime(), cacheExpirationTime);

		if (cacheExpirationTime > 0) {
			cacheExpirationTime *= Time.MINUTE;
		}

		return cacheExpirationTime;
	}

	public String getExcludedPaths() {
		return _SPA_EXCLUDED_PATHS;
	}

	public String getExcludedTargetPortlets() {
		return _spaExcludedTargetPortletsJSONArray;
	}

	/**
	 * @deprecated As of Judson (7.1.x)
	 */
	@Deprecated
	public ResourceBundle getLanguageResourceBundle(Locale locale) {
		return ResourceBundleUtil.getBundle(
			"content.Language", locale, getClass());
	}

	public ResourceBundle getLanguageResourceBundle(
		String servletContextName, Locale locale) {

		ResourceBundleLoader resourceBundleLoader =
			ResourceBundleLoaderUtil.
				getResourceBundleLoaderByServletContextName(servletContextName);

		return resourceBundleLoader.loadResourceBundle(locale);
	}

	public String getLoginRedirect(HttpServletRequest request) {
		return ParamUtil.getString(request, _REDIRECT_PARAM_NAME);
	}

	public String getPortletsBlacklist(ThemeDisplay themeDisplay) {
		StringBundler sb = new StringBundler();

		sb.append(StringPool.OPEN_CURLY_BRACE);

		_portletLocalService.visitPortlets(
			themeDisplay.getCompanyId(),
			portlet -> {
				if (!portlet.isSinglePageApplication() &&
					!portlet.isUndeployedPortlet() && portlet.isActive() &&
					portlet.isReady()) {

					sb.append(StringPool.QUOTE);
					sb.append(portlet.getPortletId());
					sb.append("\":true,");
				}
			});

		if (sb.index() == 1) {
			sb.append(StringPool.CLOSE_CURLY_BRACE);
		}
		else {
			sb.setIndex(sb.index() - 1);

			sb.append("\":true}");
		}

		return sb.toString();
	}

	public int getRequestTimeout() {
		int requestTimeout = 0;

		SPAConfiguration spaConfiguration =
			_spaConfigurationActivator.getSPAConfiguration();

		requestTimeout = GetterUtil.getInteger(
			spaConfiguration.requestTimeout(), requestTimeout);

		return requestTimeout;
	}

	public int getUserNotificationTimeout() {
		int userNotificationTimeout = 0;

		SPAConfiguration spaConfiguration =
			_spaConfigurationActivator.getSPAConfiguration();

		userNotificationTimeout = GetterUtil.getInteger(
			spaConfiguration.userNotificationTimeout(),
			userNotificationTimeout);

		return userNotificationTimeout;
	}

	public String getValidStatusCodes() {
		return _VALID_STATUS_CODES;
	}

	public boolean isClearScreensCache(
		HttpServletRequest request, HttpSession session) {

		boolean singlePageApplicationClearCache = GetterUtil.getBoolean(
			request.getAttribute(WebKeys.SINGLE_PAGE_APPLICATION_CLEAR_CACHE));

		if (singlePageApplicationClearCache) {
			return true;
		}

		String portletId = request.getParameter("p_p_id");

		if (Validator.isNull(portletId)) {
			return false;
		}

		String singlePageApplicationLastPortletId =
			(String)session.getAttribute(
				WebKeys.SINGLE_PAGE_APPLICATION_LAST_PORTLET_ID);

		if (Validator.isNotNull(singlePageApplicationLastPortletId) &&
			!Objects.equals(portletId, singlePageApplicationLastPortletId)) {

			return true;
		}

		return false;
	}

	public boolean isDisabled(HttpServletRequest httpServletRequest) {
		SPAConfiguration spaConfiguration =
			_spaConfigurationActivator.getSPAConfiguration();

		if (BrowserSnifferUtil.isIe(httpServletRequest)) {
			if (spaConfiguration.disableInInternetExplorer()) {
				return true;
			}

			double majorVersion = BrowserSnifferUtil.getMajorVersion(
				httpServletRequest);

			if (majorVersion == 11.0) {
				return spaConfiguration.disableInInternetExplorer11();
			}
		}

		return false;
	}

	@Reference(unbind = "-")
	protected void setPortletLocalService(
		PortletLocalService portletLocalService) {

		_portletLocalService = portletLocalService;
	}

	@Reference(
		cardinality = ReferenceCardinality.OPTIONAL,
		policy = ReferencePolicy.DYNAMIC,
		policyOption = ReferencePolicyOption.GREEDY
	)
	protected void setSPAConfigurationActivator(
		SPAConfigurationActivator spaConfigurationActivator) {

		_spaConfigurationActivator = spaConfigurationActivator;
	}

	protected void unsetSPAConfigurationActivator(
		SPAConfigurationActivator spaConfigurationActivator) {

		_spaConfigurationActivator = null;
	}

	private static final String _REDIRECT_PARAM_NAME;

	private static final String _SPA_EXCLUDED_PATHS;

	private static final String _spaExcludedTargetPortletsJSONArray;

	private static final String _VALID_STATUS_CODES;

	private static String _getExcludedTargetPortletsJSONArray() {
		JSONArray jsonArray = JSONFactoryUtil.createJSONArray();

		for (String excludedTargetsPortlet :
				new String[] {
						PortletKeys.USERS_ADMIN, PortletKeys.SERVER_ADMIN
				}) {

			jsonArray.put(excludedTargetsPortlet);
		}

		return jsonArray.toString();
	}

	static {
		Class<?> clazz = ServletResponseConstants.class;

		JSONArray jsonArray = JSONFactoryUtil.createJSONArray();

		for (Field field : clazz.getDeclaredFields()) {
			try {
				jsonArray.put(field.getInt(null));
			}
			catch (Exception e) {
			}
		}

		_VALID_STATUS_CODES = jsonArray.toJSONString();

		String portletNamespace = PortalUtil.getPortletNamespace(
			PropsUtil.get(PropsKeys.AUTH_LOGIN_PORTLET_NAME));

		_REDIRECT_PARAM_NAME = portletNamespace.concat("redirect");

		jsonArray = JSONFactoryUtil.createJSONArray();

		String[] excludedPaths = StringUtil.split(
			SPAConfigurationUtil.get("spa.excluded.paths"));

		for (String excludedPath : excludedPaths) {
			jsonArray.put(PortalUtil.getPathContext() + excludedPath);
		}

		_SPA_EXCLUDED_PATHS = jsonArray.toString();

		_spaExcludedTargetPortletsJSONArray =
				_getExcludedTargetPortletsJSONArray();
	}

	private PortletLocalService _portletLocalService;
	private SPAConfigurationActivator _spaConfigurationActivator;

}