/**
 * 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.search;

import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.search.DummyIndexer;
import com.liferay.portal.kernel.search.Indexer;
import com.liferay.portal.kernel.search.IndexerRegistry;
import com.liferay.portal.kernel.util.PortalClassLoaderUtil;
import com.liferay.portal.kernel.util.ProxyUtil;
import com.liferay.portal.search.buffer.BufferedIndexerInvocationHandler;
import com.liferay.portal.search.buffer.IndexerRequestBuffer;
import com.liferay.portal.service.PersistedModelLocalServiceRegistry;
import com.liferay.portal.service.PersistedModelLocalServiceRegistryUtil;
import com.liferay.portal.spring.aop.ServiceBeanAopCacheManagerUtil;
import com.liferay.portal.util.PropsValues;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.commons.lang.ClassUtils;

/**
 * @author Raymond Augé
 */
public class IndexerRegistryImpl implements IndexerRegistry {

	@Override
	public Indexer getIndexer(String className) {
		Indexer indexer = _indexers.get(className);

		return proxyIndexer(className, indexer);
	}

	@Override
	public List<Indexer> getIndexers() {
		return new ArrayList<Indexer>(new HashSet<Indexer>(_indexers.values()));
	}

	@Override
	public Indexer nullSafeGetIndexer(String className) {
		Indexer indexer = getIndexer(className);

		if (indexer != null) {
			return indexer;
		}

		if (_log.isInfoEnabled()) {
			_log.info("No indexer found for " + className);
		}

		return _dummyIndexer;
	}

	protected Indexer proxyIndexer(String className, Indexer indexer) {
		if (indexer == null) {
			return null;
		}

		IndexerRequestBuffer indexerRequestBuffer = IndexerRequestBuffer.get();

		if ((indexerRequestBuffer == null) ||
			!PropsValues.INDEX_REQUEST_BUFFER_ENABLED) {

			return indexer;
		}

		Indexer proxiedIndexer = _proxiedIndexers.get(className);

		if (proxiedIndexer == null) {
			List<?> interfaces = ClassUtils.getAllInterfaces(
				indexer.getClass());

			PersistedModelLocalServiceRegistry
				persistedModelLocalServiceRegistry =
					PersistedModelLocalServiceRegistryUtil.
						getPersistedModelLocalServiceRegistry();

			BufferedIndexerInvocationHandler bufferedIndexerInvocationHandler =
				new BufferedIndexerInvocationHandler(
					indexer, persistedModelLocalServiceRegistry);

			proxiedIndexer = (Indexer)ProxyUtil.newProxyInstance(
				PortalClassLoaderUtil.getClassLoader(),
				interfaces.toArray(new Class[interfaces.size()]),
				bufferedIndexerInvocationHandler);

			_proxiedIndexers.put(className, proxiedIndexer);
		}

		return (Indexer)proxiedIndexer;
	}

	@Override
	public void register(String className, Indexer indexerInstance) {
		_indexers.put(className, indexerInstance);

		ServiceBeanAopCacheManagerUtil.reset();
	}

	@Override
	public void unregister(String className) {
		_indexers.remove(className);
	}

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

	private Indexer _dummyIndexer = new DummyIndexer();
	private Map<String, Indexer> _indexers =
		new ConcurrentHashMap<String, Indexer>();

	private final Map<String, Indexer> _proxiedIndexers =
		new ConcurrentHashMap<String, Indexer>();

}