/*
 * Created on 11 mai 2005
 *
 * TODO To change the template for this generated file go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
package org.injac.indexing.index.webdav;
import org.injac.indexing.Consts;


import java.io.File;
import java.io.IOException;

import java.util.Iterator;
import java.util.ResourceBundle;
import java.util.HashMap;
import java.util.StringTokenizer;

import org.apache.commons.httpclient.HttpURL;
import org.apache.log4j.Logger;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.index.IndexWriter;
import org.apache.webdav.lib.WebdavFile;
import org.apache.webdav.lib.WebdavResource;
import org.injac.indexing.exceptions.ConnectionException;
import org.injac.indexing.exceptions.ExtractMetadataException;
import org.injac.indexing.index.GenericIndexing;
import org.injac.indexing.util.*;
import org.injac.indexing.beans.ReportBean;
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 ca.ulaval.bibl.lius.index.Indexer;
import ca.ulaval.bibl.lius.index.IndexerFactory;

/**
 * Classe executant l'indexation proprement dite
 * d'un fichier WebDav
 * @authors Marius Mirea, François Jannin
 */
public class InjacIndexing extends GenericIndexing {
	static Logger logger = Logger.getLogger("INJAC_INDEX");
	private ResourceBundle resBundle;
	private String indexPath;
	private String indexName;
	private String contextPath;
	private String keywordsMD;
	private int mdMode;
		// file used to configure indexing
	private String liusConfigFile;
	private LiusConfig liusConfig;
	private MetadataExtract mdExtractor;
	private ReportBean reportBean;
	public InjacIndexing(String indexName, String contextPath, int mdMode, WebdavConnection webdavConnection){
		super();
		this.contextPath = contextPath;
		this.indexName = indexName;
		resBundle = ResourceBundle.getBundle("indexation");
		indexPath= resBundle.getString("indexPath");
		descriptionMD = resBundle.getString("descriptionMD");
		titleMD = resBundle.getString("titleMD");
		keywordsMD = resBundle.getString("field.type.keyword");
		liusConfigFile = resBundle.getString("liusConfigFile");
		logger.debug("using liusConfigFile : "+liusConfigFile);
		try{
			liusConfig = LiusConfigBuilder.getSingletonInstance().getLiusConfig(liusConfigFile);
		}catch(Exception e){
			logger.error(e+e.getLocalizedMessage());
		}
		switch(mdMode){
		case MetadataMode.ALL:
			mdExtractor = new MetadataExtract(webdavConnection);
			break;
		case MetadataMode.INJAC:
			mdExtractor = new InjacMetadataExtract(webdavConnection);
			break;
		default:
			mdExtractor=null;
		}
		
		// bean for report
		reportBean = new ReportBean();
		
		
	}
	public void closeReport(){
		String beanReportPath = ReportBean.getPath(indexPath, indexName);
		BeanPhoenix.saveBean(reportBean,beanReportPath);
	}
	/**
	 * Fetch a webdav file and write it on file system in order to LIUS to index it; call actual indexing method
	 * Fonction qui rapatrie un fichier webdav et le crée sur le File System; appelle la fonction d'indexation
	 * proprement dite
	 * @param webdavFile
	 * @param indexName
	 * @throws ConnectionException
	 */
	public boolean index(WebdavFile webdavFile, String indexName) 
						throws ConnectionException{
		boolean result=false;
		try{
			if(!webdavFile.exists()){
				throw new ConnectionException();
				}
		}
		catch(org.apache.webdav.lib.WebdavException we){
			throw new ConnectionException();
			
		}
		
		String webdavName = webdavFile.getName();
		String webdavPath = webdavFile.getAbsolutePath();
		
		String url = webdavPath.substring(0, 
				webdavPath.length() - webdavName.length() - 1);
		boolean indexabil = (webdavName.endsWith(".pdf")||
							webdavName.endsWith(".doc")||
							webdavName.endsWith(".ppt")||
							webdavName.endsWith(".rtf")||
							webdavName.endsWith(".xml")||
							webdavName.endsWith(".html")||
							webdavName.endsWith(".txt")||
							webdavName.endsWith(".htm"))&&
							webdavFile.isFile();
		if(indexabil) {
			File file = new File(indexPath+"/Temp/"+indexName+"/" + webdavName);
			
			try{
				file.createNewFile();
				HttpURL hrl = new HttpURL(webdavPath);
				hrl.setUserinfo(webdavFile.getUser(),webdavFile.getPass());
				WebdavResource wdr = new WebdavResource(hrl);
				wdr.getMethod(file);
			}
			catch(IOException ie){
				logger.error("IO Exception while indexing : "+ie.getLocalizedMessage());
				}
			try{
				HashMap metadatas=null;
				if(mdExtractor!=null){
					// get metadatas from webdavFile as hashmap
					metadatas = mdExtractor.getMetadata(webdavFile);
				}
				result = doIndex(indexName,file.getAbsolutePath(),url,webdavName,metadatas);
			}
			catch(ExtractMetadataException eme){
				logger.error("Error in adding metadata: " + eme.getLocalizedMessage()); 
						
			}
			file.delete();
			return result;
		}
		return result;
	}
	/**
	 * Function d'indexation proprement dite. Elle fait
	 * l'indexation avec le logiciel LIUS d'un fichier
	 * et ajoute aussi a l'index des champs contenant 
	 * les metadonnees sur le fichier
	 * @param filePath
	 * @param url
	 * @param webdavName
	 * @param metadatas
	 */
	private boolean doIndex(String indexName,String filePath, String url,String webdavName, HashMap metadatas){
		//test published state
		String docstate = (String)metadatas.get("document-state");
		if(docstate!=null)
			if(!docstate.equals("published"))
				return false;
		// get now time for duration
		java.util.Date date = new java.util.Date();
		long begin = date.getTime();
		
		String indexDir = indexPath + "/"+ indexName;
		String toIndex=filePath;
		
		Analyzer analyzer = AnalyzerFactory.getAnalyzer(liusConfig);
		IndexWriter writer = null;
		try {
			boolean createIndex = LuceneActions.getSingletonInstance().createIndexValue(liusConfig.getCreateIndex(), indexDir);
			writer = new IndexWriter(indexDir, analyzer, createIndex);
			LuceneActions.getSingletonInstance().setIndexWriterProps(writer,liusConfig);
			Indexer indexer = IndexerFactory.getIndexer(toIndex);
			Document luceneDoc = indexer.createLuceneDocument(toIndex, liusConfigFile);
			luceneDoc.add(Field.Text("url", url));
			luceneDoc.add(Field.Text("name", webdavName));
			
			String rootFileName = null;
			// 	selective indexation of metadatas
			if(metadatas!=null){
				Iterator mdIterator = metadatas.keySet().iterator();
				while(mdIterator.hasNext()){
					String key = (String)mdIterator.next();
					String value = (String)metadatas.get(key);
					if(value==null)
						value="";
					if(keywordsMD.indexOf(key)!=-1){
						luceneDoc.add(Field.Keyword(key, value));
					}else
						luceneDoc.add(Field.Text(key, value));
					
				}
				addCommonFields(metadatas, luceneDoc);
				
				
				//reportBean.addLine(url+"/"+webdavName, "ok",duration);
				rootFileName = (String)metadatas.get("root-file-name");
			}
			LuceneActions.getSingletonInstance().save(luceneDoc, writer, liusConfig);
			writer.close();
			date = new java.util.Date();
			long end = date.getTime();
			int duration = (int)((end - begin) );
			boolean isRoot = webdavName.equals(rootFileName);
			reportBean.addLine(url+"/"+webdavName, "ok",duration,getTitle(metadatas), getDescription(metadatas), isRoot);
			return true;
		}
		catch (IOException e) {
			reportBean.addLine(url, e.getLocalizedMessage(),0);
			logger.error(e.getLocalizedMessage());
			return false;
		}
		catch (ca.ulaval.bibl.lius.Exception.LiusException e) {
			reportBean.addLine(url, e.getLocalizedMessage(),0);
			logger.error(e.getLocalizedMessage());
			return false;
		}
	}
	public void reportAlready(ReportBean.ReportLine line){
		reportBean.getList().add(line);
	}
	
	/**
	 * Hook method for getting title from HashMap metadatas
	 */
	protected String getTitle(Object obj){
		HashMap metadatas =null;
		
		if(obj instanceof HashMap){
			metadatas = (HashMap)obj; 
		}
		else{
			return null;
		}
		
		String result ="";
		StringTokenizer st = new StringTokenizer(titleMD,",");
		while(st.hasMoreTokens()){
			result =(String)metadatas.get(st.nextToken());
			if(result!=null)
				break;
		}
		return result;
	}
	
	/**
	 * Hook method for getting description from HashMap metadatas
	 */
	protected String getDescription(Object obj){
		HashMap metadatas =null;
		
		if(obj instanceof HashMap){
			metadatas = (HashMap)obj; 
		}
		else{
			return null;
		}
		String result ="";
		StringTokenizer st = new StringTokenizer(descriptionMD,",");
		while(st.hasMoreTokens()){
			result =(String)metadatas.get(st.nextToken());
			if(result!=null)
				break;
		}
		return result;
	}
	
}
