/**
 * 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.portal.service.impl;

import com.liferay.petra.reflect.ReflectionUtil;
import com.liferay.petra.string.StringPool;
import com.liferay.portal.kernel.dao.orm.DynamicQuery;
import com.liferay.portal.kernel.dao.orm.EntityCacheUtil;
import com.liferay.portal.kernel.dao.orm.RestrictionsFactoryUtil;
import com.liferay.portal.kernel.exception.AvailableLocaleException;
import com.liferay.portal.kernel.exception.NoSuchVirtualHostException;
import com.liferay.portal.kernel.exception.PortalException;
import com.liferay.portal.kernel.language.LanguageUtil;
import com.liferay.portal.kernel.model.Company;
import com.liferay.portal.kernel.model.Group;
import com.liferay.portal.kernel.model.LayoutSet;
import com.liferay.portal.kernel.model.VirtualHost;
import com.liferay.portal.kernel.transaction.TransactionCommitCallbackUtil;
import com.liferay.portal.kernel.util.LocaleUtil;
import com.liferay.portal.kernel.util.TreeMapBuilder;
import com.liferay.portal.kernel.util.Validator;
import com.liferay.portal.model.impl.LayoutSetImpl;
import com.liferay.portal.model.impl.LayoutSetModelImpl;
import com.liferay.portal.service.base.VirtualHostLocalServiceBaseImpl;
import com.liferay.portal.util.PropsValues;

import java.net.IDN;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.TreeMap;

/**
 * @author Alexander Chow
 * @author Raymond Augé
 */
public class VirtualHostLocalServiceImpl
	extends VirtualHostLocalServiceBaseImpl {

	/**
	 * @deprecated As of Mueller (7.2.x), replaced by {@link
	 *             #getVirtualHosts(long, long)}
	 */
	@Deprecated
	@Override
	public VirtualHost fetchVirtualHost(long companyId, long layoutSetId) {
		return virtualHostPersistence.fetchByC_L(companyId, layoutSetId);
	}

	@Override
	public VirtualHost fetchVirtualHost(String hostname) {
		VirtualHost virtualHost = virtualHostPersistence.fetchByHostname(
			hostname);

		if ((virtualHost == null) && hostname.contains("xn--")) {
			virtualHost = virtualHostPersistence.fetchByHostname(
				IDN.toUnicode(hostname));
		}

		return virtualHost;
	}

	/**
	 * @deprecated As of Mueller (7.2.x), replaced by {@link
	 *             #getVirtualHosts(long, long)}
	 */
	@Deprecated
	@Override
	public VirtualHost getVirtualHost(long companyId, long layoutSetId)
		throws PortalException {

		return virtualHostPersistence.findByC_L(companyId, layoutSetId);
	}

	@Override
	public VirtualHost getVirtualHost(String hostname) throws PortalException {
		try {
			return virtualHostPersistence.findByHostname(hostname);
		}
		catch (NoSuchVirtualHostException noSuchVirtualHostException) {
			if (hostname.contains("xn--")) {
				return virtualHostPersistence.findByHostname(
					IDN.toUnicode(hostname));
			}

			throw noSuchVirtualHostException;
		}
	}

	@Override
	public List<VirtualHost> getVirtualHosts(long companyId, long layoutSetId)
		throws PortalException {

		return _getVirtualHosts(companyId, layoutSetId);
	}

	/**
	 * @deprecated As of Mueller (7.2.x), replaced by {@link
	 *             #updateVirtualHosts(long, long, TreeMap)}
	 */
	@Deprecated
	@Override
	public VirtualHost updateVirtualHost(
		long companyId, final long layoutSetId, String hostname) {

		List<VirtualHost> virtualHosts = updateVirtualHosts(
			companyId, layoutSetId,
			TreeMapBuilder.put(
				hostname, StringPool.BLANK
			).build());

		if (virtualHosts.isEmpty()) {
			return null;
		}

		return virtualHosts.get(0);
	}

	@Override
	public List<VirtualHost> updateVirtualHosts(
		long companyId, final long layoutSetId,
		TreeMap<String, String> hostnames) {

		LayoutSet layoutSet = layoutSetPersistence.fetchByPrimaryKey(
			layoutSetId);

		Set<Locale> availableLocales = LanguageUtil.getAvailableLocales();

		if (layoutSet != null) {
			availableLocales = LanguageUtil.getAvailableLocales(
				layoutSet.getGroupId());
		}

		List<VirtualHost> virtualHosts = new ArrayList<>(
			_getVirtualHosts(companyId, layoutSetId));

		boolean first = true;

		for (String curHostname : hostnames.navigableKeySet()) {
			VirtualHost virtualHost = null;

			for (VirtualHost curVirtualHost : virtualHosts) {
				if (curHostname.equals(curVirtualHost.getHostname())) {
					virtualHost = curVirtualHost;

					break;
				}
			}

			if (virtualHost == null) {
				long virtualHostId = counterLocalService.increment();

				virtualHost = virtualHostPersistence.create(virtualHostId);

				virtualHost.setCompanyId(companyId);
				virtualHost.setLayoutSetId(layoutSetId);
				virtualHost.setHostname(curHostname);

				virtualHosts.add(virtualHost);
			}

			String languageId = hostnames.get(curHostname);

			Locale locale = LocaleUtil.fromLanguageId(languageId, true, false);

			if (locale == null) {
				locale = LocaleUtil.getSiteDefault();
			}

			if (!availableLocales.contains(locale)) {
				ReflectionUtil.throwException(
					new AvailableLocaleException(languageId));
			}

			virtualHost.setDefaultVirtualHost(first);
			virtualHost.setLanguageId(languageId);

			first = false;

			virtualHostPersistence.update(virtualHost);
		}

		Iterator<VirtualHost> itr = virtualHosts.iterator();

		while (itr.hasNext()) {
			VirtualHost virtualHost = itr.next();

			if (!hostnames.containsKey(virtualHost.getHostname())) {
				itr.remove();

				virtualHostPersistence.remove(virtualHost);
			}
		}

		virtualHostPersistence.cacheResult(virtualHosts);

		final Company company = companyPersistence.fetchByPrimaryKey(companyId);

		if (company != null) {
			TransactionCommitCallbackUtil.registerCallback(
				() -> {
					EntityCacheUtil.removeResult(
						company.isEntityCacheEnabled(), company.getClass(),
						company.getPrimaryKeyObj());

					return null;
				});

			companyPersistence.clearCache(company);
		}

		if ((layoutSet == null) &&
			Validator.isNotNull(PropsValues.VIRTUAL_HOSTS_DEFAULT_SITE_NAME)) {

			Group group = groupPersistence.fetchByC_GK(
				companyId, PropsValues.VIRTUAL_HOSTS_DEFAULT_SITE_NAME);

			if (group != null) {
				layoutSet = layoutSetPersistence.fetchByG_P_Head(
					group.getGroupId(), false, false);
			}
		}

		if (layoutSet != null) {
			layoutSetPersistence.clearCache(layoutSet);

			TransactionCommitCallbackUtil.registerCallback(
				() -> {
					EntityCacheUtil.removeResult(
						LayoutSetModelImpl.ENTITY_CACHE_ENABLED,
						LayoutSetImpl.class, layoutSetId);

					return null;
				});
		}

		return virtualHosts;
	}

	private List<VirtualHost> _getVirtualHosts(
		long companyId, long layoutSetId) {

		DynamicQuery dynamicQuery = dynamicQuery();

		dynamicQuery.add(RestrictionsFactoryUtil.eq("companyId", companyId));
		dynamicQuery.add(
			RestrictionsFactoryUtil.eq("layoutSetId", layoutSetId));

		return virtualHostPersistence.findWithDynamicQuery(dynamicQuery);
	}

}