package com.owlpad.service.impl.index;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.UserPrincipal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.io.FileUtils;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequestBuilder;
import org.elasticsearch.action.bulk.BulkRequestBuilder;
import org.elasticsearch.action.index.IndexRequestBuilder;
import org.elasticsearch.client.node.NodeClient;
import org.elasticsearch.indices.IndexAlreadyExistsException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import static org.elasticsearch.common.xcontent.XContentFactory.*;

import com.google.common.base.Preconditions;
import com.owlpad.domain.index.IndexRequest;
import com.owlpad.domain.index.IndexResponse;
import com.owlpad.domain.search.StatusType;
import com.owlpad.service.elasticsearch.client.NodeClientFactoryBean;
import com.owlpad.service.index.IndexService;

/**
 * Elasticsearch indexService implementation.
 * 
 * @author Jay Paulynice
 *
 */
@Service("indexService")
public class ESIndexServiceImpl implements IndexService {
	private NodeClientFactoryBean nodeClientFactoryBean;
	private NodeClient client;
	private static final Logger logger = LoggerFactory.getLogger(ESIndexServiceImpl.class);
	
	@Autowired
	public ESIndexServiceImpl(NodeClientFactoryBean nodeClientFactoryBean) throws Exception{
		this.nodeClientFactoryBean = nodeClientFactoryBean;
		this.client = this.nodeClientFactoryBean.getObject();
	}

	/*
	 * (non-Javadoc)
	 * @see com.owlpad.service.index.IndexService#index(com.owlpad.domain.index.IndexRequest)
	 */
	@Override
	public IndexResponse index(IndexRequest indexRequest) {
		Preconditions.checkNotNull(indexRequest.getDirectoryToIndex(),"No directory specified for indexing...");
		
		IndexResponse response = new IndexResponse();
		String suffix = indexRequest.getSuffix();
		String dataDirPath = indexRequest.getDirectoryToIndex();
		File dataDir = new File(dataDirPath);

		try {
			response.setDocumentsIndexed(indexDir(dataDir, suffix));
			response.setStatus(StatusType.SUCCESS);
		}
		catch (Exception e) {
			response.setStatus(StatusType.FAIL);
			response.setErrorMessage(e.toString());
			logger.info("Exception while calling index.  Exception" + e);
		}

		return response;
	}

	/**
	 * Entry point for directory indexing 
	 * 
	 * @param dataDir
	 * @param suffix
	 * @return
	 * @throws Exception 
	 */
	private int indexDir(File dataDir, String suffix) throws Exception {
		try {
			CreateIndexRequestBuilder createIndexRequestBuilder = client.admin().indices().prepareCreate("owlpad-index");
			createIndexRequestBuilder.execute().actionGet();
		} catch (IndexAlreadyExistsException e) {
			logger.info("Could not create index because it exists already.",e);
		}

		BulkRequestBuilder bulkRequest = client.prepareBulk();

		List<File> filesToIndex = new ArrayList<File>();
		getFilesFromDirectory(dataDir, filesToIndex,suffix);
		addDocumentsToBulkRequest(bulkRequest, filesToIndex);
		if (filesToIndex.size() > 0) {
			bulkRequest.execute().actionGet();
		}

		return filesToIndex.size();
	}

	/**
	 * Get files from a directory
	 * 
	 * @param dataDir
	 * @param filesToIndex
	 * @throws IOException 
	 */
	private void getFilesFromDirectory(File dataDir, List<File> filesToIndex,String suffix) throws IOException {
		File[] files = dataDir.listFiles();
		for (File f : files) {
			if (f.isDirectory()) {
				getFilesFromDirectory(f, filesToIndex,suffix);
			} else {
				if(suffix == null || f.getCanonicalPath().endsWith(suffix)){
					filesToIndex.add(f);
				}
			}
		}
	}

	/**
	 * Build up {@link BulkRequestBuilder} object 
	 * 
	 * @param client
	 * @param bulkRequest
	 * @param filesToIndex
	 * @param suffix
	 * @throws Exception 
	 */
	private void addDocumentsToBulkRequest(BulkRequestBuilder bulkRequest, List<File> filesToIndex) throws Exception {
		for (File f : filesToIndex) {
			IndexRequestBuilder requestBuilder = createIndexRequestBuilderFromFile(f);
			if(requestBuilder != null){
				bulkRequest.add(requestBuilder);				
			}
		}
	}

	/**
	 * Create an indexRequestBuilder object give the client, file, id,and content
	 * 
	 * @param client
	 * @param f
	 * @param id
	 * @param content
	 * @return {@link IndexRequestBuilder} object
	 * @throws Exception 
	 */
	private IndexRequestBuilder createIndexRequestBuilderFromFile(File f) throws Exception{
		
		boolean unReadable = f.isHidden() || f.isDirectory() || !f.canRead() || !f.exists();
		if (!unReadable) {
			String content = FileUtils.readFileToString(f);
			Path path = Paths.get(f.getCanonicalPath());
			UserPrincipal owner = Files.getOwner(path);
			String author = owner.getName();
			BasicFileAttributes attr = Files.readAttributes(path, BasicFileAttributes.class);
			String fileName = f.getCanonicalPath();
			int indexOfDot = fileName.indexOf(".");
			String docType = fileName.substring(indexOfDot+1);
			
			return client.prepareIndex("owlpad-index", "docs")
					.setSource(jsonBuilder().startObject()
							.field("contents", content)
							.field("filepath",fileName)
							.field("filename", f.getName())
							.field("author", author)
							.field("created", new SimpleDateFormat("MM/dd/yyyy HH:mm:ss").format((attr.creationTime().toMillis())))
							.field("lastModified", new SimpleDateFormat("MM/dd/yyyy HH:mm:ss").format((attr.lastModifiedTime().toMillis())))
							.field("size", String.valueOf(attr.size()))
							.field("docType",docType)
							.endObject());
		}
		return null;
	}
}

@@ -5086,20 +5086,20 @@
 ing file
-Name
+Path
  = f.get
@@ -5139,20 +5139,20 @@
 t = file
-Name
+Path
 .indexOf
@@ -5182,20 +5182,20 @@
 e = file
-Name
+Path
 .substri
@@ -5211,10 +5211,8 @@
 fDot
-+1
 );%0A%09
@@ -5376,20 +5376,20 @@
 th%22,file
-Name
+Path
 )%0A%09%09%09%09%09%09

clean up