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

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLDecoder;
import java.nio.charset.CharsetDecoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.ResourceBundle;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.ServletException;
import org.apache.log4j.Logger;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.injac.indexing.Consts;
import org.injac.indexing.util.PathManager;

/**
 * Classe de recherche générique utilisant le design pattern Template
 * Generic search class using Template design pattern
 * @author François Jannin
 */
abstract public class GenericSearchServlet extends HttpServlet {

	static Logger logger = Logger.getLogger(GenericSearchServlet.class);

	protected ResourceBundle resBundle;

	protected String resultMD;

	protected java.util.List mdList;

	protected String upnode;

	protected String renderURL;

	protected String intDocs;

	protected String indexPath;

	protected String errorMsg;

	protected File index;
	
	protected boolean hitsOnly;

	public GenericSearchServlet() {
		super();
		resBundle = ResourceBundle.getBundle("indexation");

	}

	/**
	 * template method for building search response
	 */
	public void service(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		hitsOnly = false;
		String hitsOnlyStr = request.getParameter("hitsOnly");
		if((hitsOnlyStr != null) && (hitsOnlyStr.equalsIgnoreCase("true"))){
			hitsOnly=true;
		}
		
		String query = request.getParameter("query");

		resultMD = request.getParameter("resultMD");

		if (resultMD == null) {
			resultMD = resBundle.getString("resultMD");
		}

		// split md list string and put it into arrayList
		String[] array = resultMD.split(",");
		mdList = Arrays.asList(array);

		String indexName = request.getParameter("name");
		upnode = request.getParameter("upnode");
		renderURL = request.getParameter("renderURL");
		intDocs = resBundle.getString("intDocs");
		if (upnode == null) {
			upnode = resBundle.getString("upnode");
		}
		if (renderURL == null) {
			renderURL = resBundle.getString("renderURL");
		}
		indexPath = resBundle.getString("indexPath");
		// template sequence for building response
		PrintWriter writer = startResponse(query, response);
		if (validateQuery(indexName, query)) {
			try {
				doSearch(query, writer);
			} catch (Exception e) {
				errorMsg = e + " : " + e.getLocalizedMessage();
				errorMsg(request, writer);
			}
		} else
			errorMsg(request, writer);
		endResponse(writer);

	}

	/**
	 * Primitives called by template : do nothing in this generic class (must be overload in subclasses)
	 */
	abstract protected PrintWriter startResponse(String query,
			HttpServletResponse response) throws ServletException, IOException ;

	abstract protected void endResponse(PrintWriter writer) throws ServletException,
			IOException ;

	abstract protected void doSearch(String query, PrintWriter writer)
			throws ServletException, IOException ;

	abstract protected void errorMsg(HttpServletRequest request, PrintWriter writer) ;

/*----
	 * Generic methods *
	 *----/

	/**
	 * Tests params and try to create index File object
	 * 
	 * @param indexName
	 * @param query
	 * @return true if successfull
	 */
	protected boolean validateQuery(String indexName, String query) {
		boolean result = (query != null) && (indexName != null);
		if (!result) {
			errorMsg = "<msg>Error: missing request properties ! both \"name\" and \"query\" must be provided.</msg>";
		}
		try {
			index = new File(indexPath + "/" + indexName);
			if (!index.exists()) {
				errorMsg = "<tr><td>Error: index not created yet ! "
						+ "Please create index first and try again.</td></tr>";
				return false;
			}

		} catch (Exception e) {
			errorMsg = "";
			return false;
		}
		return result;

	}
	/**
	 * Encode URL 
	 * @param path : url to encode
	 * @return encoded url
	 */
	protected String processURL(String path) {
		return PathManager.encodeURL(path);
	}
	/**
	 * Modif exist hook
	 * @param doc
	 * @return
	 */
	
	protected String getRenderURL(Document doc){
		 String url=  doc.get("renderURL");
	     if(url==null){
	    	String filename = doc.get("name");
	       	url= processURL(getRenderURL(doc.get("url"),filename));
	     }
	     return url;
	}
	protected String getDocName(Document doc){
		String url=  doc.get("renderURL");
	     if(url==null){
	     // return value of field indexed by webdav.InjacIndexing	 
	    	 return doc.get("name");
	     }
	     else
	     {
	    	 // return value of field indexed by exist.ExistIndexing
	    	 int i = url.lastIndexOf("?file=");
	    	 if(i!=-1){
	    		 return url.substring(i+"?file=".length());
	    	 }
	    	 i=url.lastIndexOf('/');
	    	 if(i!=-1){
	    		 return url.substring(i+1);
	    	 }else
	    		 return "";
	    	 
	     }
		
	}
	
	/**
	 * Translate WEBDAV URL and filename into rendering URL
	 * @param path : webdav url
	 * @param file : file name
	 * @return rendering URL
	 */
	private String getRenderURL(String path, String file) {
		if (upnode.equals("") || renderURL.equals("")) {
			return path;
		} else {
			String subPath = path.substring(path.indexOf(upnode)
					+ upnode.length());
			String renderURI = "/ext";
			String suffix = null;
			int index = file.lastIndexOf('.');
			if (index != -1) {
				suffix = file.substring(index + 1);

			}
			if ((suffix != null) && (intDocs.indexOf(suffix) != -1)) {
				renderURI = "/nav";
				path = renderURL + renderURI + subPath + "?file="+file;
			} else {
				path = renderURL + renderURI + subPath + "/" + file;
			}

			return path;
		}

	}

	/**
	 * Select fields with resultMD param elements
	 * 
	 * @param doc Lucene document
	 * @return list of selected fields
	 */
	protected ArrayList getResultFields(Document doc) {

		java.util.Enumeration fields = doc.fields();
		ArrayList result = new ArrayList();
		while (fields.hasMoreElements()) {
			Field field = (Field) fields.nextElement();
			// include asked metadatas only
			if (mdList.contains(field.name())) {
				result.add(field);
			}
		}
		return result;
	}
	
	protected String getNamespace(Document doc){
		String namespace = doc.get(Consts.INDEX_NAMESPACE);
        if(namespace==null){
        	namespace = Consts.NONAMESPACE;
        }
        return namespace;
	}
	
}
