/**
 * 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.portlet.assetpublisher.lar;

import com.liferay.portal.NoSuchGroupException;
import com.liferay.portal.kernel.lar.DataLevel;
import com.liferay.portal.kernel.lar.DefaultConfigurationPortletDataHandler;
import com.liferay.portal.kernel.lar.ExportImportHelperUtil;
import com.liferay.portal.kernel.lar.PortletDataContext;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.util.ArrayUtil;
import com.liferay.portal.kernel.util.GetterUtil;
import com.liferay.portal.kernel.util.StringPool;
import com.liferay.portal.kernel.util.StringUtil;
import com.liferay.portal.kernel.util.Validator;
import com.liferay.portal.kernel.xml.Element;
import com.liferay.portal.model.Company;
import com.liferay.portal.model.Group;
import com.liferay.portal.model.Layout;
import com.liferay.portal.model.Portlet;
import com.liferay.portal.security.auth.PrincipalException;
import com.liferay.portal.security.permission.PermissionThreadLocal;
import com.liferay.portal.service.CompanyLocalServiceUtil;
import com.liferay.portal.service.LayoutLocalServiceUtil;
import com.liferay.portal.service.PortletLocalServiceUtil;
import com.liferay.portal.util.PortalUtil;
import com.liferay.portlet.asset.model.AssetCategory;
import com.liferay.portlet.asset.model.AssetVocabulary;
import com.liferay.portlet.assetpublisher.util.AssetPublisher;
import com.liferay.portlet.assetpublisher.util.AssetPublisherUtil;
import com.liferay.portlet.documentlibrary.model.DLFileEntry;
import com.liferay.portlet.documentlibrary.model.DLFileEntryType;
import com.liferay.portlet.dynamicdatamapping.model.DDMStructure;
import com.liferay.portlet.dynamicdatamapping.service.DDMStructureLocalServiceUtil;
import com.liferay.portlet.dynamicdatamapping.util.DDMIndexer;
import com.liferay.portlet.journal.model.JournalArticle;

import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

import javax.portlet.PortletPreferences;

/**
 * @author Julio Camarero
 */
public class AssetPublisherPortletDataHandler
	extends DefaultConfigurationPortletDataHandler {

	public AssetPublisherPortletDataHandler() {
		setDataLevel(DataLevel.PORTLET_INSTANCE);
		setPublishToLiveByDefault(true);
	}

	@Override
	protected PortletPreferences doProcessExportPortletPreferences(
			PortletDataContext portletDataContext, String portletId,
			PortletPreferences portletPreferences)
		throws Exception {

		return updateExportPortletPreferences(
			portletDataContext, portletId, portletPreferences);
	}

	@Override
	protected PortletPreferences doProcessImportPortletPreferences(
			PortletDataContext portletDataContext, String portletId,
			PortletPreferences portletPreferences)
		throws Exception {

		return updateImportPortletPreferences(
			portletDataContext, portletId, portletPreferences);
	}

	protected void updateExportClassNameIds(
			PortletPreferences portletPreferences, String key)
		throws Exception {

		String[] oldValues = portletPreferences.getValues(key, null);

		if (oldValues == null) {
			return;
		}

		String[] newValues = new String[oldValues.length];

		int i = 0;

		for (String oldValue : oldValues) {
			if (key.equals("anyAssetType") &&
				(oldValue.equals("false") || oldValue.equals("true"))) {

				newValues[i++] = oldValue;

				continue;
			}

			try {
				long classNameId = GetterUtil.getLong(oldValue);

				String className = PortalUtil.getClassName(classNameId);

				newValues[i++] = className;
			}
			catch (Exception e) {
				if (_log.isWarnEnabled()) {
					_log.warn(
						"Unable to get class name ID for class name " +
							oldValue);
				}
			}
		}

		portletPreferences.setValues(key, newValues);
	}

	protected void updateExportDDMStructures(
			PortletDataContext portletDataContext,
			PortletPreferences portletPreferences, String key)
		throws Exception {

		String oldValue = portletPreferences.getValue(key, null);

		if (Validator.isNull(oldValue) ||
			!oldValue.startsWith(
				DDMIndexer.DDM_FIELD_NAMESPACE + StringPool.FORWARD_SLASH)) {

			return;
		}

		String[] oldValueParts = StringUtil.split(
			oldValue, StringPool.FORWARD_SLASH);

		long ddmStructureId = Long.valueOf(oldValueParts[1]);

		DDMStructure ddmStructure =
			DDMStructureLocalServiceUtil.fetchDDMStructure(ddmStructureId);

		if (ddmStructure == null) {
			portletPreferences.reset(key);

			return;
		}

		String newValue = oldValue.replace(
			String.valueOf(ddmStructureId), ddmStructure.getUuid());

		portletPreferences.setValue(key, newValue);
	}

	protected PortletPreferences updateExportPortletPreferences(
			PortletDataContext portletDataContext, String portletId,
			PortletPreferences portletPreferences)
		throws Exception {

		String anyAssetTypeString = portletPreferences.getValue(
			"anyAssetType", null);

		String selectionStyle = portletPreferences.getValue(
			"selectionStyle", null);

		if (Validator.isNotNull(selectionStyle) &&
			selectionStyle.equals("manual")) {

			portletPreferences.reset("anyAssetType");

			anyAssetTypeString = portletPreferences.getValue(
				"anyAssetType", null);
		}
		else if (Validator.isNotNull(anyAssetTypeString) &&
				 anyAssetTypeString.equals("false")) {

			String[] classNameIds = portletPreferences.getValues(
				"classNameIds", StringPool.EMPTY_ARRAY);

			if (classNameIds.length == 1) {
				portletPreferences.setValue("anyAssetType", classNameIds[0]);

				anyAssetTypeString = portletPreferences.getValue(
					"anyAssetType", null);

				portletPreferences.reset("classNameIds");
			}
		}

		String anyAssetTypeClassName = StringPool.BLANK;

		long anyAssetType = GetterUtil.getLong(anyAssetTypeString);

		if (anyAssetType > 0) {
			anyAssetTypeClassName = PortalUtil.getClassName(anyAssetType);
		}

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

		Enumeration<String> enu = portletPreferences.getNames();

		while (enu.hasMoreElements()) {
			String name = enu.nextElement();

			String value = GetterUtil.getString(
				portletPreferences.getValue(name, null));

			if (name.equals("anyAssetType") || name.equals("classNameIds")) {
				if (name.equals("classNameIds") &&
					Validator.isNotNull(anyAssetTypeString) &&
					!anyAssetTypeString.equals("false")) {

					portletPreferences.reset(name);
				}
				else {
					updateExportClassNameIds(portletPreferences, name);
				}
			}
			else if (name.equals(
						"anyClassTypeDLFileEntryAssetRendererFactory") ||
					 (name.equals("classTypeIds") &&
					  anyAssetTypeClassName.equals(
						  DLFileEntry.class.getName())) ||
					 name.equals(
						"classTypeIdsDLFileEntryAssetRendererFactory")) {

				String anyClassTypeDLFileEntryAssetRendererFactory =
					portletPreferences.getValue(
						"anyClassTypeDLFileEntryAssetRendererFactory", null);

				String[] classTypeIdsDLFileEntryAssetRendererFactory =
					portletPreferences.getValues(
						"classTypeIdsDLFileEntryAssetRendererFactory",
						StringPool.EMPTY_ARRAY);

				if (Validator.isNotNull(
						anyClassTypeDLFileEntryAssetRendererFactory) &&
					anyClassTypeDLFileEntryAssetRendererFactory.equals(
						"false") &&
					(classTypeIdsDLFileEntryAssetRendererFactory.length == 1)) {

					portletPreferences.setValue(
						"anyClassTypeDLFileEntryAssetRendererFactory",
						classTypeIdsDLFileEntryAssetRendererFactory[0]);

					portletPreferences.reset(
						"classTypeIdsDLFileEntryAssetRendererFactory");

					anyClassTypeDLFileEntryAssetRendererFactory =
						portletPreferences.getValue(
							"anyClassTypeDLFileEntryAssetRendererFactory",
							null);
				}

				if (!anyAssetTypeClassName.equals(
						DLFileEntry.class.getName()) ||
					(name.equals(
						"classTypeIdsDLFileEntryAssetRendererFactory") &&
					 Validator.isNotNull(
						 anyClassTypeDLFileEntryAssetRendererFactory) &&
					 !anyClassTypeDLFileEntryAssetRendererFactory.equals(
						 "false"))) {

					portletPreferences.reset(name);
				}
				else {
					ExportImportHelperUtil.
						updateExportPortletPreferencesClassPKs(
							portletDataContext, portlet, portletPreferences,
							name, DLFileEntryType.class.getName(),
							portletDataContext.getExportDataRootElement());
				}
			}
			else if (name.equals(
						"anyClassTypeJournalArticleAssetRendererFactory") ||
					 (name.equals("classTypeIds") &&
					  anyAssetTypeClassName.equals(
						  JournalArticle.class.getName())) ||
					 name.equals(
						"classTypeIdsJournalArticleAssetRendererFactory")) {

				String anyClassTypeJournalArticleAssetRendererFactory =
					portletPreferences.getValue(
						"anyClassTypeJournalArticleAssetRendererFactory", null);

				String[] classTypeIdsJournalArticleAssetRendererFactory =
					portletPreferences.getValues(
						"classTypeIdsJournalArticleAssetRendererFactory",
						StringPool.EMPTY_ARRAY);

				if (Validator.isNotNull(
						anyClassTypeJournalArticleAssetRendererFactory) &&
					anyClassTypeJournalArticleAssetRendererFactory.equals(
						"false") &&
					(classTypeIdsJournalArticleAssetRendererFactory.length ==
						1)) {

					portletPreferences.setValue(
						"anyClassTypeJournalArticleAssetRendererFactory",
						classTypeIdsJournalArticleAssetRendererFactory[0]);

					portletPreferences.reset(
						"classTypeIdsJournalArticleAssetRendererFactory");

					anyClassTypeJournalArticleAssetRendererFactory =
						portletPreferences.getValue(
							"anyClassTypeJournalArticleAssetRendererFactory",
							null);
				}

				if (!anyAssetTypeClassName.equals(
						JournalArticle.class.getName()) ||
					(name.equals(
						"classTypeIdsJournalArticleAssetRendererFactory") &&
					 Validator.isNotNull(
						 anyClassTypeJournalArticleAssetRendererFactory) &&
					 !anyClassTypeJournalArticleAssetRendererFactory.equals(
						 "false"))) {

					portletPreferences.reset(name);
				}
				else {
					ExportImportHelperUtil.
						updateExportPortletPreferencesClassPKs(
							portletDataContext, portlet, portletPreferences,
							name, DDMStructure.class.getName(),
							portletDataContext.getExportDataRootElement());
				}
			}
			else if (name.equals("assetVocabularyId")) {
				ExportImportHelperUtil.updateExportPortletPreferencesClassPKs(
					portletDataContext, portlet, portletPreferences, name,
					AssetVocabulary.class.getName(),
					portletDataContext.getExportDataRootElement());
			}
			else if (name.startsWith("orderByColumn")) {
				updateExportDDMStructures(
					portletDataContext, portletPreferences, name);
			}
			else if (name.startsWith("queryName") &&
					 StringUtil.equalsIgnoreCase(value, "assetCategories")) {

				String index = name.substring(9);

				ExportImportHelperUtil.updateExportPortletPreferencesClassPKs(
					portletDataContext, portlet, portletPreferences,
					"queryValues" + index, AssetCategory.class.getName(),
					portletDataContext.getExportDataRootElement());
			}
			else if (name.startsWith("queryName") &&
					 StringUtil.equalsIgnoreCase(value, "assetTags")) {

				String index = name.substring(9);

				String[] assetTagNames = portletPreferences.getValues(
					"queryValues" + index, null);

				if (ArrayUtil.isEmpty(assetTagNames)) {
					continue;
				}

				portletDataContext.addAssetTags(
					AssetPublisher.class.getName(), 0, assetTagNames);
			}
			else if (name.equals("scopeIds")) {
				updateExportScopeIds(
					portletDataContext, portletPreferences, name,
					portletDataContext.getPlid());
			}
		}

		return portletPreferences;
	}

	protected void updateExportScopeIds(
			PortletDataContext portletDataContext,
			PortletPreferences portletPreferences, String key, long plid)
		throws Exception {

		String[] oldValues = portletPreferences.getValues(key, null);

		if (oldValues == null) {
			return;
		}

		Layout layout = LayoutLocalServiceUtil.getLayout(plid);

		String companyGroupScopeId =
			AssetPublisher.SCOPE_ID_GROUP_PREFIX +
				portletDataContext.getCompanyGroupId();

		String[] newValues = new String[oldValues.length];

		for (int i = 0; i < oldValues.length; i++) {
			String oldValue = oldValues[i];

			if (oldValue.startsWith(AssetPublisher.SCOPE_ID_GROUP_PREFIX)) {
				newValues[i] = StringUtil.replace(
					oldValue, companyGroupScopeId,
					"[$COMPANY_GROUP_SCOPE_ID$]");
			}
			else if (oldValue.startsWith(
						AssetPublisher.SCOPE_ID_LAYOUT_PREFIX)) {

				// Legacy preferences

				String scopeIdSuffix = oldValue.substring(
					AssetPublisher.SCOPE_ID_LAYOUT_PREFIX.length());

				long scopeIdLayoutId = GetterUtil.getLong(scopeIdSuffix);

				Layout scopeIdLayout = LayoutLocalServiceUtil.getLayout(
					layout.getGroupId(), layout.isPrivateLayout(),
					scopeIdLayoutId);

				newValues[i] =
					AssetPublisher.SCOPE_ID_LAYOUT_UUID_PREFIX +
						scopeIdLayout.getUuid();
			}
			else {
				newValues[i] = oldValue;
			}
		}

		portletPreferences.setValues(key, newValues);
	}

	protected void updateImportClassNameIds(
			PortletPreferences portletPreferences, String key)
		throws Exception {

		String[] oldValues = portletPreferences.getValues(key, null);

		if (oldValues == null) {
			return;
		}

		String[] newValues = new String[oldValues.length];

		int i = 0;

		for (String oldValue : oldValues) {
			if (key.equals("anyAssetType") &&
				(oldValue.equals("false") || oldValue.equals("true"))) {

				newValues[i++] = oldValue;

				continue;
			}

			try {
				long classNameId = PortalUtil.getClassNameId(oldValue);

				newValues[i++] = String.valueOf(classNameId);
			}
			catch (Exception e) {
				if (_log.isWarnEnabled()) {
					_log.warn(
						"Unable to find class name ID for class name " +
							oldValue);
				}
			}
		}

		portletPreferences.setValues(key, newValues);
	}

	protected void updateImportDDMStructures(
			PortletDataContext portletDataContext,
			PortletPreferences portletPreferences, String key)
		throws Exception {

		String oldValue = portletPreferences.getValue(key, null);

		if (Validator.isNull(oldValue) ||
			!oldValue.startsWith(
				DDMIndexer.DDM_FIELD_NAMESPACE + StringPool.FORWARD_SLASH)) {

			return;
		}

		String[] oldValueParts = StringUtil.split(
			oldValue, StringPool.FORWARD_SLASH);

		String ddmStructureUuid = oldValueParts[1];

		DDMStructure ddmStructure =
			DDMStructureLocalServiceUtil.fetchDDMStructureByUuidAndGroupId(
				ddmStructureUuid, portletDataContext.getScopeGroupId());

		if (ddmStructure == null) {
			ddmStructure =
				DDMStructureLocalServiceUtil.fetchDDMStructureByUuidAndGroupId(
					ddmStructureUuid, portletDataContext.getCompanyGroupId());
		}

		if (ddmStructure == null) {
			Element rootElement = portletDataContext.getImportDataRootElement();

			long companyGroupId = portletDataContext.getCompanyGroupId();

			Element referenceElement = portletDataContext.getReferenceElement(
				rootElement, DDMStructure.class, companyGroupId,
				ddmStructureUuid, PortletDataContext.REFERENCE_TYPE_DEPENDENCY);

			if (referenceElement != null) {
				long referencedClassNameId = PortalUtil.getClassNameId(
					referenceElement.attributeValue("referenced-class-name"));

				String structureKey = referenceElement.attributeValue(
					"structure-key");

				boolean preloaded = GetterUtil.getBoolean(
					referenceElement.attributeValue("preloaded"));

				if (preloaded) {
					ddmStructure = DDMStructureLocalServiceUtil.fetchStructure(
						companyGroupId, referencedClassNameId, structureKey);
				}
			}
		}

		if (ddmStructure == null) {
			return;
		}

		long ddmStructureId = ddmStructure.getStructureId();

		String newValue = oldValue.replace(
			String.valueOf(ddmStructureUuid), String.valueOf(ddmStructureId));

		portletPreferences.setValue(key, newValue);
	}

	protected PortletPreferences updateImportPortletPreferences(
			PortletDataContext portletDataContext, String portletId,
			PortletPreferences portletPreferences)
		throws Exception {

		Company company = CompanyLocalServiceUtil.getCompanyById(
			portletDataContext.getCompanyId());

		Group companyGroup = company.getGroup();

		String anyAssetTypeClassName = portletPreferences.getValue(
			"anyAssetType", StringPool.BLANK);

		Enumeration<String> enu = portletPreferences.getNames();

		while (enu.hasMoreElements()) {
			String name = enu.nextElement();

			String value = GetterUtil.getString(
				portletPreferences.getValue(name, null));

			if (name.equals("anyAssetType") || name.equals("classNameIds")) {
				updateImportClassNameIds(portletPreferences, name);
			}
			else if (name.equals(
						"anyClassTypeDLFileEntryAssetRendererFactory") ||
					 (name.equals("classTypeIds") &&
					  anyAssetTypeClassName.equals(
						  DLFileEntry.class.getName())) ||
					 name.equals(
						"classTypeIdsDLFileEntryAssetRendererFactory")) {

				ExportImportHelperUtil.updateImportPortletPreferencesClassPKs(
					portletDataContext, portletPreferences, name,
					DLFileEntryType.class, companyGroup.getGroupId());
			}
			else if (name.equals(
						"anyClassTypeJournalArticleAssetRendererFactory") ||
					 (name.equals("classTypeIds") &&
					  anyAssetTypeClassName.equals(
						  JournalArticle.class.getName())) ||
					 name.equals(
						"classTypeIdsJournalArticleAssetRendererFactory")) {

				ExportImportHelperUtil.updateImportPortletPreferencesClassPKs(
					portletDataContext, portletPreferences, name,
					DDMStructure.class, companyGroup.getGroupId());
			}
			else if (name.equals("assetVocabularyId")) {
				ExportImportHelperUtil.updateImportPortletPreferencesClassPKs(
					portletDataContext, portletPreferences, name,
					AssetVocabulary.class, companyGroup.getGroupId());
			}
			else if (name.startsWith("orderByColumn")) {
				updateImportDDMStructures(
					portletDataContext, portletPreferences, name);
			}
			else if (name.startsWith("queryName") &&
					 StringUtil.equalsIgnoreCase(value, "assetCategories")) {

				String index = name.substring(9, name.length());

				ExportImportHelperUtil.updateImportPortletPreferencesClassPKs(
					portletDataContext, portletPreferences,
					"queryValues" + index, AssetCategory.class,
					companyGroup.getGroupId());
			}
			else if (name.equals("scopeIds")) {
				updateImportScopeIds(
					portletPreferences, name, companyGroup.getGroupId(),
					portletDataContext.getPlid());
			}
		}

		return portletPreferences;
	}

	protected void updateImportScopeIds(
			PortletPreferences portletPreferences, String key,
			long companyGroupId, long plid)
		throws Exception {

		String[] oldValues = portletPreferences.getValues(key, null);

		if (oldValues == null) {
			return;
		}

		Layout layout = LayoutLocalServiceUtil.getLayout(plid);

		String companyGroupScopeId =
			AssetPublisher.SCOPE_ID_GROUP_PREFIX + companyGroupId;

		List<String> newValues = new ArrayList<String>(oldValues.length);

		for (String oldValue : oldValues) {
			String newValue = StringUtil.replace(
				oldValue, "[$COMPANY_GROUP_SCOPE_ID$]", companyGroupScopeId);

			try {
				if (!AssetPublisherUtil.isScopeIdSelectable(
						PermissionThreadLocal.getPermissionChecker(), newValue,
						companyGroupId, layout, false)) {

					continue;
				}

				newValues.add(newValue);
			}
			catch (NoSuchGroupException nsge) {
				if (_log.isInfoEnabled()) {
					_log.info(
						"Ignoring scope " + newValue + " because the " +
							"referenced group was not found");
				}
			}
			catch (PrincipalException pe) {
				if (_log.isInfoEnabled()) {
					_log.info(
						"Ignoring scope " + newValue + " because the " +
							"referenced parent group no longer allows " +
								"sharing content with child sites");
				}
			}
		}

		portletPreferences.setValues(
			key, newValues.toArray(new String[newValues.size()]));
	}

	private static Log _log = LogFactoryUtil.getLog(
		AssetPublisherPortletDataHandler.class);

}