package org.injac.indexing.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.MissingResourceException;
import java.util.ResourceBundle;

import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.digester.Digester;
import org.apache.log4j.Logger;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.store.*;
import org.xml.sax.InputSource;

import ca.ulaval.bibl.lius.Lucene.AnalyzerFactory;
import ca.ulaval.bibl.lius.Lucene.LuceneActions;
import ca.ulaval.bibl.lius.config.LiusConfig;
import ca.ulaval.bibl.lius.config.LiusConfigBuilder;
import org.apache.lucene.analysis.Analyzer;
import org.injac.indexing.beans.IndexListBean;
public class MergeIndex {
	protected ResourceBundle resBundle;
	protected String mergeConf;
	private boolean initialized = false;
	private ArrayList indexList;
	static Logger logger = Logger.getLogger(MergeIndex.class);
	private String create="false";
	private String fusionName;
	private String password;
	private String login;
	private LiusConfig liusConfig;
	private IndexWriter indexWriter = null;
	public String getFusionName() {
		return fusionName;
	}

	public void setFusionName(String fusionName) {
		this.fusionName = fusionName;
	}

	public String getLogin() {
		return login;
	}

	public void setLogin(String login) {
		this.login = login;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public MergeIndex(String confFile){
		mergeConf = confFile;
		initialized = init(confFile);
	}

	public MergeIndex(){
		resBundle = ResourceBundle.getBundle("indexation");
		String confFile = null;
		try {
			confFile = resBundle.getString("merge.config");
			
		} catch (MissingResourceException e) {
			confFile = null;
			logger.error("Missing harvest.config propertie :" +e.getLocalizedMessage());
		}
		initialized = init(confFile);
		
	}	
	private boolean init(String confFile){
		logger.debug("conf file :"+confFile);
		
		boolean result = false;
		
		indexList = new ArrayList();

		Digester digester = new Digester();
		digester.push(this);
		
		digester.addSetProperties("merge");
		digester.addCallMethod("merge/index","addIndex",1);
		digester.addCallParam("merge/index", 0, "name");
		
		try{
			
			InputSource is = new InputSource( new FileInputStream(confFile));
			
			digester.parse(is);
			result = true;
		}catch(Exception e){
			logger.error(e + " : "+ e.getLocalizedMessage()+" file : "+ confFile);
			
		}
		return result;
	}
	
	public void addIndex(String name){
		indexList.add(name);
		
	}
	public void process(){
		// create directory
		String indexPath = resBundle.getString("indexPath");
		String fusionPath = indexPath + "/" + fusionName;
		String liusConfigFile = resBundle.getString("merge.liusConfig");
		// create or get existing directory
		File index = createIndexDirectory(fusionPath, create.equalsIgnoreCase("true"));
		if (!index.exists()) {
			logger.error("Can't create fusion index : "+ indexPath + "/" + fusionName);
		}else{
			liusConfig = LiusConfigBuilder.getSingletonInstance()
			.getLiusConfig(liusConfigFile);
			try{
				// merge all indexes
				if(open(fusionPath)){
					indexWriter.addIndexes(getDirectories(indexPath));
					close();
				}
				// save into bean
				int newIndex = saveBean(indexPath,fusionName,"merge index "+fusionName, login,password,1);
				if(newIndex==-1){
					logger.error("can't access indexListBean");
					
				}	
			}catch(Exception e){
				logger.error(e + " : "+ e.getLocalizedMessage());
				close();
			}
		}
	}
	
	protected int saveBean(String indexPath,String indexName, String url, String user, String password,
			int mdMode) {

		String beanPath = indexPath + "/" + IndexListBean.class.getName()
				+ ".ser";
		IndexListBean	indexListBean = (IndexListBean) BeanPhoenix.loadBean(beanPath);
		
		
		int newIndex = -1;
		if (indexListBean != null) {
			newIndex = indexListBean.addIndex(indexName, url, user, password,
					mdMode);
			if (newIndex == -1) {
				return -1;
			}
			// save bean
			BeanPhoenix.saveBean(indexListBean, beanPath);
		} else {
			return -1;
		}
		return newIndex;

	}
	
	private Directory[] getDirectories(String indexPath){
		Directory[] dirs = new Directory[indexList.size()];
		for(int i=0;i<dirs.length;i++){
			String indexName = (String)indexList.get(i);
			try{
				Directory dir = FSDirectory.getDirectory(indexPath + "/" + indexName,false);
				dirs[i]= dir;
			}catch(IOException ioe){
				logger.error("Can't add "+ indexPath + "/" + indexName + "index - "+ ioe.getLocalizedMessage());
			}
		}
		
		return dirs;
	}
	protected File createIndexDirectory(String indexPath, boolean create) {
		File index = new File(indexPath );
		if (!index.exists()) {
			if (index.mkdirs()) {
				logger.debug("creating " + indexPath 
						+ " for merging index");
			} else {
				return null;
			}
		}
		if (create == true) {
			// clear dir
			FileTools.clearDir(index);
		}

		return index;
	}
	/**
	 * Create index Writer
	 *
	 */
	public boolean open(String indexDir){
		
		try{
			boolean createIndex = LuceneActions.getSingletonInstance()
					.createIndexValue(liusConfig.getCreateIndex(), indexDir);

			Analyzer analyzer = AnalyzerFactory.getAnalyzer(liusConfig);
			indexWriter = new IndexWriter(indexDir, analyzer, createIndex);

			LuceneActions.getSingletonInstance().setIndexWriterProps(indexWriter,
					liusConfig);
		}catch(Exception e){
			logger.error(e + " : "+ e.getLocalizedMessage());
			return false;
		}
		return true;
	}
	/**
	 * Close index Writer
	 *
	 */
	public void close(){
		try{
			indexWriter.optimize();
			indexWriter.close();
		}catch(Exception e){
			logger.error(e + " : "+ e.getLocalizedMessage());
		}	
	}
// STATIC METHODS	
	
public static void main(String[] args){
	
	boolean result = false;
	long start = System.currentTimeMillis();
	logger.debug("args : "+args + "length :"+ args.length);
	if(null == args || args.length < 2) {
		// start from properties with reload option to false by default
		result = startFromProperties();
	}else
	{	
		// start from arguments provided along command line
		result = startFromCommandLineArgs(args);
	}
	String msg;
	if(result){
		msg ="merging process ok";
	}else{
		msg="merging process aborted";
	}
	long elapsed = System.currentTimeMillis() - start;
	drawDiagnostic(elapsed, msg);
}
	public static boolean startFromProperties(){
		logger.debug("startFromProperties");
		
		boolean result = false;
		MergeIndex merge = new MergeIndex();
		try{
			merge.process();
			result=true;
		}catch(Exception e){
			logger.error(e + " : "+ e.getLocalizedMessage());
			result= false;
		}
		return result;
	}
	public static boolean startFromCommandLineArgs(String []args){
		logger.debug("startFromCommandLineArgs");
		boolean result = false;
		MergeIndex merge = new MergeIndex(args[0]);
		try{
			merge.process();
			result=true;
		}catch(Exception e){
			logger.error(e + " : "+ e.getLocalizedMessage());
			result= false;
		}
		return result;
	}
	
	
protected static void drawDiagnostic(long timeInMillis, String msg){
	int days = (int) ( timeInMillis / ( 24L * 60 * 60 * 1000 ) );

	int remdr = (int) ( timeInMillis % ( 24L * 60 * 60 * 1000 ));

	int hours = remdr / ( 60 * 60 * 1000 );

	remdr = remdr % ( 60 * 60 * 1000 );

	int minutes = remdr / ( 60 * 1000 );

	remdr = remdr % ( 60 * 1000 );

	int seconds = remdr / 1000;

	int ms = remdr % 1000;
	System.out.println(msg +timeInMillis+ " ms");
	System.out.println("( "+days+" days "+ hours+" hours " +minutes+" minutes "+seconds+" seconds "+ms+" ms"+")");
	
}

public String getCreate() {
	return create;
}

public void setCreate(String create) {
	this.create = create;
}

}	
	