/**
 * 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.journal.web.internal.info.display.contributor.portlet;

import com.liferay.asset.display.page.portlet.BaseAssetDisplayPageFriendlyURLResolver;
import com.liferay.journal.exception.NoSuchArticleException;
import com.liferay.journal.model.JournalArticle;
import com.liferay.journal.service.JournalArticleLocalService;
import com.liferay.petra.string.CharPool;
import com.liferay.petra.string.StringBundler;
import com.liferay.petra.string.StringPool;
import com.liferay.petra.string.StringUtil;
import com.liferay.portal.kernel.exception.PortalException;
import com.liferay.portal.kernel.model.LayoutFriendlyURLComposite;
import com.liferay.portal.kernel.model.User;
import com.liferay.portal.kernel.portlet.FriendlyURLResolver;

import com.liferay.portal.kernel.security.auth.PrincipalException;
import com.liferay.portal.kernel.security.permission.ActionKeys;
import com.liferay.portal.kernel.security.permission.PermissionChecker;
import com.liferay.portal.kernel.security.permission.PermissionThreadLocal;
import com.liferay.portal.kernel.service.ServiceContext;
import com.liferay.portal.kernel.service.ServiceContextThreadLocal;
import com.liferay.portal.kernel.service.UserLocalService;
import com.liferay.portal.kernel.util.ArrayUtil;
import com.liferay.portal.kernel.util.FriendlyURLNormalizer;
import com.liferay.portal.kernel.util.GetterUtil;
import com.liferay.portal.kernel.util.Validator;
import com.liferay.portal.kernel.workflow.WorkflowConstants;
import com.liferay.portal.kernel.workflow.permission.WorkflowPermission;
import org.osgi.service.component.annotations.Component;

import java.util.List;
import java.util.Locale;
import java.util.Map;

import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;

/**
 * @author Eudaldo Alonso
 */
@Component(service = FriendlyURLResolver.class)
public class JournalArticleAssetDisplayPageFriendlyURLResolver
	extends BaseAssetDisplayPageFriendlyURLResolver {

	@Override
	public String getURLSeparator() {
		return "/w/";
	}

	@Override
	public LayoutFriendlyURLComposite getLayoutFriendlyURLComposite(
		long companyId, long groupId, boolean privateLayout, String friendlyURL,
		Map<String, String[]> params, Map<String, Object> requestContext)
		throws PortalException {

		_getJournalArticle(
			groupId, friendlyURL, params);

		return super.getLayoutFriendlyURLComposite(companyId, groupId,
			privateLayout, friendlyURL, params, requestContext);
	}


	private String _getFullURLTitle(String friendlyURL) {
		String urlSeparator = getURLSeparator();

		return friendlyURL.substring(urlSeparator.length());
	}

	private long _getId(String friendlyURL) {
		List<String> paths = StringUtil.split(friendlyURL, CharPool.SLASH);

		if (paths.size() <= 2) {
			return 0;
		}

		return GetterUtil.getLong(paths.get(paths.size() - 1));
	}

	private JournalArticle _getJournalArticle(
		long groupId, String friendlyURL, Map<String, String[]> params)
		throws PortalException {

		JournalArticle journalArticle = null;

		String[] versionIds = params.get("version");

		if (ArrayUtil.isNotEmpty(versionIds) && !_isDefaultUser()) {
			long id = GetterUtil.getLong(versionIds[0]);

			journalArticle = _journalArticleLocalService.fetchArticle(id);
		}

		String normalizedUrlTitle =
			_friendlyURLNormalizer.normalizeWithEncoding(
				_getFullURLTitle(friendlyURL));

		if (journalArticle == null) {
			journalArticle =
				_journalArticleLocalService.fetchLatestArticleByUrlTitle(
					groupId, normalizedUrlTitle,
					WorkflowConstants.STATUS_APPROVED);
		}

		if (journalArticle == null) {
			PermissionChecker permissionChecker =
				PermissionThreadLocal.getPermissionChecker();

			journalArticle =
				_journalArticleLocalService.fetchLatestArticleByUrlTitle(
					groupId, normalizedUrlTitle,
					WorkflowConstants.STATUS_PENDING);

			if ((journalArticle != null) &&
				!GetterUtil.getBoolean(
					_workflowPermission.hasPermission(
						permissionChecker, groupId,
						"com.liferay.journal.model.JournalArticle",
						journalArticle.getId(), ActionKeys.VIEW))) {

				throw new PrincipalException();
			}

			journalArticle =
				_journalArticleLocalService.fetchLatestArticleByUrlTitle(
					groupId, normalizedUrlTitle,
					WorkflowConstants.STATUS_DRAFT);
		}

		if (journalArticle == null) {
			normalizedUrlTitle = _friendlyURLNormalizer.normalizeWithEncoding(
				_getURLTitle(friendlyURL));

			double version = _getVersion(friendlyURL);

			if (version > 0) {
				journalArticle =
					_journalArticleLocalService.fetchArticleByUrlTitle(
						groupId, normalizedUrlTitle, version);
			}
			else {
				journalArticle =
					_journalArticleLocalService.fetchLatestArticleByUrlTitle(
						groupId, normalizedUrlTitle,
						WorkflowConstants.STATUS_APPROVED);
			}
		}

		if (journalArticle == null) {
			normalizedUrlTitle = _friendlyURLNormalizer.normalizeWithEncoding(
				_getURLTitle(friendlyURL));

			long id = _getId(friendlyURL);

			if (id > 0) {
				journalArticle = _journalArticleLocalService.fetchArticle(id);
			}
		}

		if (journalArticle == null) {
			PermissionChecker permissionChecker =
				PermissionThreadLocal.getPermissionChecker();

			journalArticle =
				_journalArticleLocalService.getLatestArticleByUrlTitle(
					groupId, normalizedUrlTitle,
					WorkflowConstants.STATUS_PENDING);

			if (!GetterUtil.getBoolean(
				_workflowPermission.hasPermission(
					permissionChecker, groupId,
					"com.liferay.journal.model.JournalArticle",
					journalArticle.getId(), ActionKeys.VIEW))) {

				throw new PrincipalException();
			}
		}

		Map<Locale, String> friendlyURLMap = journalArticle.getFriendlyURLMap();

		if (!friendlyURLMap.containsValue(normalizedUrlTitle)) {
			throw new NoSuchArticleException(
				StringBundler.concat(
					"No latest version of a JournalArticle exists with the key",
					"{groupId=", groupId, ", urlTitle=",
					_getURLTitle(friendlyURL), ", status=",
					WorkflowConstants.STATUS_ANY, "}"));
		}

		return journalArticle;
	}

	private String _getURLTitle(String friendlyURL) {
		String fullURLTitle = _getFullURLTitle(friendlyURL);

		if (!fullURLTitle.contains(StringPool.SLASH)) {
			return fullURLTitle;
		}

		String urlSeparator = getURLSeparator();

		return friendlyURL.substring(
			urlSeparator.length(), friendlyURL.lastIndexOf(StringPool.SLASH));
	}

	private double _getVersion(String friendlyURL) {
		List<String> paths = StringUtil.split(friendlyURL, CharPool.SLASH);

		if (paths.size() <= 2) {
			return 0;
		}

		String lastPath = paths.get(paths.size() - 1);

		List<String> numbers = StringUtil.split(lastPath, CharPool.PERIOD);

		if ((numbers.size() == 2) && Validator.isDigit(numbers.get(0)) &&
			Validator.isDigit(numbers.get(1))) {

			return GetterUtil.getDouble(lastPath);
		}

		return 0;
	}

	private boolean _isDefaultUser() {
		ServiceContext serviceContext =
			ServiceContextThreadLocal.getServiceContext();

		if (serviceContext == null) {
			return true;
		}

		User user = _userLocalService.fetchUser(serviceContext.getUserId());

		if ((user == null) || user.isDefaultUser()) {
			return true;
		}

		return false;
	}

	@Reference
	private FriendlyURLNormalizer _friendlyURLNormalizer;

	@Reference
	private JournalArticleLocalService _journalArticleLocalService;

	@Reference
	private UserLocalService _userLocalService;

	@Reference
	private WorkflowPermission _workflowPermission;
}