package eu.dnetlib.functionality.index.solr;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Set;

import org.apache.commons.io.IOUtils;
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.embedded.EmbeddedSolrServer;
import org.apache.solr.core.CoreContainer;
import org.apache.solr.schema.IndexSchema;

import com.google.common.collect.Sets;

import eu.dnetlib.data.index.IndexServiceException;
import eu.dnetlib.functionality.index.solr.utils.MetadataReference;

/**
 * LocalIndexServer holds the references to the actual index filesystem structures an the mapping with the data
 * structure ids registered in the IS.
 * 
 * @author claudio
 * 
 */
public class LocalIndexServer {

	/**
	 * logger.
	 */
	private static final Log log = LogFactory.getLog(LocalIndexServer.class); // NOPMD by marko on 11/24/08 5:02 PM

	/**
	 * CoreContainer.
	 */
	private transient CoreContainer container;

	/**
	 * Solr index server.
	 */
	private final transient SolrServer server;

	/**
	 * #{@link eu.dnetlib.functionality.index.solr.utils.MetadataReference}.
	 */
	private final transient MetadataReference mdRef;

	/**
	 * The index ds ids associated with this index.
	 */
	private final transient Set<String> dsIds;

	/**
	 * Index schema representing the index field configuration and types.
	 */
	private IndexSchema schema;

	/**
	 * Constructor for LocalIndexServer.
	 * 
	 * @param mdRef
	 *            MetadataReference.
	 * @param dsIds
	 *            dsIds
	 * @param solrDataDir
	 *            server data directory
	 * @param schema
	 *            index schema
	 * @throws IndexServiceException
	 *             could happen
	 */
	public LocalIndexServer(final MetadataReference mdRef, final List<String> dsIds, final String solrDataDir, final IndexSchema schema)
			throws IndexServiceException {

		this.mdRef = mdRef;
		this.schema = schema;
		this.dsIds = Collections.synchronizedSet(Sets.newHashSet(dsIds));

		server = newEmbeddedSolrServer(solrDataDir);
	}

	/**
	 * Helper method.
	 * 
	 * @param solrDataDir
	 *            server data directory
	 * @return a new SolrServer instance.
	 * @throws IndexServiceException
	 *             could happen
	 */
	private SolrServer newEmbeddedSolrServer(final String solrDataDir) throws IndexServiceException {
		final File home = new File(solrDataDir + IOUtils.DIR_SEPARATOR_UNIX + mdRef.toString());

		container = new CoreContainer(home.getAbsolutePath());
		try {
			container.load(home.getAbsolutePath(), new File(home, "solr.xml"));
		} catch (FileNotFoundException e) {
			throw new IndexServiceException(e);
		}

		return new EmbeddedSolrServer(container, mdRef.toString());
	}

	/**
	 * Merges a list of indicies, identified by their path on the filesystem, into this one.
	 * 
	 * @param paths
	 *            index paths
	 * @throws IOException
	 *             could happen
	 */
	public void mergeIndexes(final List<String> paths) throws IOException {

		log.info("NOT IMPLEMENTED merging PATHS: " + paths);

		//		container.getCore(mdRef.toString()).getUpdateHandler().mergeIndexes(
		//			new MergeIndexesCommand(Iterables.toArray(
		//				new MappedCollection<IndexReader, String>(
		//					paths, 
		//					new UnaryFunction<IndexReader, String>() {
		//						@Override
		//						public IndexReader evaluate(final String path) {
		//							try {
		//								return IndexReader.open(new SimpleFSDirectory(new File(path)), true);
		//							} catch (IOException e) {
		//								throw new RuntimeException(e);	//NOPMD
		//							}
		//						}
		//					}), IndexReader.class)));
		log.info("DONE merging DIRS");
	}

	/**
	 * Restarts the index core.
	 * 
	 * @throws IndexServiceException
	 *             could happen.
	 */
	public void restartCore() throws IndexServiceException {
		log.info("restarting core: " + mdRef.toString());
		getContainer().reload(mdRef.toString());
	}

	public SolrServer getServer() {
		return server;
	}

	public IndexSchema getSchema() {
		return schema;
	}

	public void setSchema(final IndexSchema schema) {
		this.schema = schema;
	}

	public Set<String> getDsIds() {
		return dsIds;
	}

	public CoreContainer getContainer() {
		return container;
	}

}
