package eu.dnetlib.functionality.index.solr;

import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.solr.client.solrj.SolrServer;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.CloudSolrServer;
import org.apache.solr.common.cloud.SolrZkClient;
import org.apache.solr.common.util.NamedList;
import org.dom4j.Document;

import com.google.common.collect.Maps;

import eu.dnetlib.data.index.IndexServiceException;
import eu.dnetlib.functionality.index.solr.admin.RemoteSolrAdministration;
import eu.dnetlib.functionality.index.solr.admin.SolrAdministration;
import eu.dnetlib.functionality.index.solr.server.HttpServers;
import eu.dnetlib.functionality.index.solr.server.SolrServers;
import eu.dnetlib.functionality.index.solr.utils.MetadataReference;
import eu.dnetlib.functionality.index.solr.utils.ServiceTools;
import eu.dnetlib.functionality.index.solr.utils.SolrProperties;
import eu.dnetlib.functionality.index.solr.utils.SolrUtils;

/**
 * The SolrManager class.
 */
public class SolrManager {

	/**
	 * The log.
	 */
	private static final Log log = LogFactory.getLog(SolrManager.class); // NOPMD by marko on 11/24/08 5:02 PM

	/**
	 * creator and holder for one {@link SolrServers} per core.
	 */
	private SolrServers servers;

	private SolrAdministration administration;

	@Resource
	private SolrUtils solrUtils;

	@Resource
	private ServiceTools serviceTools;

	public void init() {

		log.info("Starting SolrManager ...");

		final SolrProperties properties = solrUtils.getProperties();
		try {
			//CloudSolrServer cloudServer = new CloudSolrServer(properties.getZkUrl(), new LBHttpSolrServer(solrUtils.getUrlListArray()));
			CloudSolrServer cloudServer = new CloudSolrServer(properties.getZkUrl());
			cloudServer.connect();

			servers = new HttpServers(solrUtils);
			administration = new RemoteSolrAdministration(servers, cloudServer.getZkStateReader(), solrUtils);

			for (String coreName : administration.getCoreNames()) {
				servers.registerSolrServer(coreName);
			}
		} catch (Exception e) {
			log.error("Error while initialize SolrManager", e);
		}
	}

	/**
	 * Get the SolrProperties.
	 * 
	 * @return the SolrProperties.
	 */
	public SolrProperties getSolrProperties() {
		return solrUtils.getProperties();
	}

	/**
	 * Get core names.
	 * 
	 * @return the core names.
	 */
	public Collection<String> getCoreNames() {
		try {
			return administration.getCoreNames();
		} catch (Exception ex) {
			log.error("Error getting core names from Solr", ex);
			return Collections.emptyList();
		}
	}

	/**
	 * Get a SolrServer by core name.
	 * 
	 * @param coreName
	 *            the core name.
	 * @return the SolrServer.
	 * @throws SolrServerException
	 *             SolrServerException if no core by this name is alive
	 * @throws IOException
	 *             IOException.
	 */
	public SolrServer getSolrServer(MetadataReference mdRef) throws SolrServerException, IOException {
		return servers.getSolrServer(mdRef.toString());
	}

	public void registerServer(String coreName, Document fields) throws SolrServerException, IndexServiceException {
		final SolrProperties properties = solrUtils.getProperties();

		try {
			Map<String, String[]> params = Maps.newHashMap();
			params.put("numShards", new String[] { properties.getNumShards() + "" });
			if (properties.getReplicationFactor() > 0) {
				params.put("replicationFactor", new String[] { properties.getReplicationFactor() + "" });
			}

			uploadZkConfig(coreName, fields, false);
			NamedList<Object> rsp = administration.create(coreName, coreName, params);
			if (log.isDebugEnabled()) {
				log.debug(rsp.toString());
			}
			servers.registerSolrServer(coreName);
		} catch (Exception e) {
			throw new IndexServiceException(e);
		}
	}

	public void uploadZkConfig(String coreName, Document fields, boolean overwrite) {
		SolrZkClient zkClient = ((RemoteSolrAdministration) administration).getZkStateReader().getZkClient();
		solrUtils.uploadZookeperConfig(zkClient, coreName, fields, overwrite);
	}

	public boolean isRegistered(MetadataReference mdRef) {
		return servers.isRegistered(mdRef.toString());
	}

	public SolrAdministration getSolrAdministration() {
		return administration;
	}

}
