/*

Lucene-Highlighting Lucene utilities to highlight terms in texts
Copyright (C) 2001 Maik Schreiber

This library is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.

This library is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

*/

package fr.gouv.culture.sdx.utils.lucene;

import java.io.IOException;
import java.util.Hashtable;

import org.apache.lucene.index.Term;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.PhraseQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;

import fr.gouv.culture.sdx.utils.Utilities;


/**
 * Contains miscellaneous utility methods for use with Lucene.
 *
 * @version $Id: LuceneTools.java,v 1.2 2008/01/07 10:49:39 malo_pichot Exp $
 * @author Maik Schreiber (mailto: bZ@iq-computing.de)
 */
public class LuceneTools {
    /** LuceneTools must not be instantiated directly. */
    protected LuceneTools() {
    }


    /**
     * Extracts all term texts of a given Query. Term texts will be returned in lower-case.
     *
     * @param query      Query to extract term texts from
     * @param terms      HashTable where extracted term texts should be put into (see below for Hashtable storage format)
     * @param prohibited <code>true</code> to extract "prohibited" terms, too
     *
     * Terms texts will be stored as values in the provided hashtable with the keys in the format
     * fieldName_termText as multiple terms can come from one field and multiple fields can have the same term
     * @throws IOException
     * @see #getFieldNameFromKey A utility method for getting a field name from a key of the hashtable for a value/term text
     *
     */
    public static final void getTerms(Query query, Hashtable terms, boolean prohibited)
            throws IOException {
        if (query instanceof BooleanQuery)
            getTermsFromBooleanQuery((BooleanQuery) query, terms, prohibited);
        else if (query instanceof PhraseQuery)
            getTermsFromPhraseQuery((PhraseQuery) query, terms);
        else if (query instanceof TermQuery)
            getTermsFromTermQuery((TermQuery) query, terms);
        /*    else if (query instanceof PrefixQuery)
                getTermsFromPrefixQuery((PrefixQuery) query, terms, prohibited);
            else if (query instanceof RangeQuery)
                getTermsFromRangeQuery((RangeQuery) query, terms, prohibited);
            else if (query instanceof MultiTermQuery)
                getTermsFromMultiTermQuery((MultiTermQuery) query, terms, prohibited);
        */
    }

    /**
     * Extracts all term texts of a given BooleanQuery. Term texts will be returned in lower-case.
     *
     * @param query      BooleanQuery to extract term texts from
     * @param terms      HashSet where extracted term texts should be put into (Elements: String)
     * @param prohibited <code>true</code> to extract "prohibited" terms, too
     */
    protected static final void getTermsFromBooleanQuery(BooleanQuery query, Hashtable terms,
                                                         boolean prohibited) throws IOException {
        BooleanClause[] queryClauses = query.getClauses();
        int i;

        for (i = 0; i < queryClauses.length; i++) {
        	// MAJ Lucene 2.1.0
//            if (prohibited || !queryClauses[i].prohibited)
//                getTerms(queryClauses[i].query, terms, prohibited);
            if (prohibited || !queryClauses[i].getOccur().equals( BooleanClause.Occur.MUST_NOT ))
                getTerms(queryClauses[i].getQuery(), terms, prohibited);
        }
    }

    /**
     * Extracts all term texts of a given PhraseQuery. Term texts will be returned in lower-case.
     *
     * @param query PhraseQuery to extract term texts from
     * @param terms HashSet where extracted term texts should be put into (Elements: String)
     */
    protected static final void getTermsFromPhraseQuery(PhraseQuery query, Hashtable terms) {
        Term[] queryTerms = query.getTerms();
        int i;

//	    for (i = 0; i < queryTerms.length; i++)
//	    	getTermsFromTerm(queryTerms[i], terms);

        /* On recupere le "slop" de la phraseQuery. S'il est superieur a 0, on
         * ne renvoie rien. Sinon, on concatene les termes separes par une espace.
         * Cela nous permet de surligner (sdx:hilite) les expressions recherchees.
         * (cf. LuceneTermHighlighter.highlightTerms())
         */
        if(query.getSlop()>0) return;
        else{
          StringBuffer mTerms = new StringBuffer();
          for (i = 0; i < queryTerms.length; i++){
            if(i!=0) mTerms.append(" ");
            mTerms.append(queryTerms[i].text());
          }
          terms.put(queryTerms[0].field() + "_" + mTerms.toString(),
                    mTerms.toString());
        }
    }

    /**
     * Extracts all term texts of a given TermQuery. Term texts will be returned in lower-case.
     *
     * @param query TermQuery to extract term texts from
     * @param terms HashSet where extracted term texts should be put into (Elements: String)
     */
    protected static final void getTermsFromTermQuery(TermQuery query, Hashtable terms) {
        getTermsFromTerm(query.getTerm(), terms);
    }

    /**
     * Extracts all term texts of a given MultiTermQuery. Term texts will be returned in lower-case.
     *
     * @param query      MultiTermQuery to extract term texts from
     * @param terms      HashSet where extracted term texts should be put into (Elements: String)
     * @param prohibited <code>true</code> to extract "prohibited" terms, too
     */
/*
    protected static final void getTermsFromMultiTermQuery(MultiTermQuery query, Hashtable terms,
                                                           boolean prohibited) throws IOException {
        getTerms(query.getTerm(), terms, prohibited);
    }
*/

    /**
     * Extracts all term texts of a given PrefixQuery. Term texts will be returned in lower-case.
     *
     * @param query      PrefixQuery to extract term texts from
     * @param terms      HashSet where extracted term texts should be put into (Elements: String)
     * @param prohibited <code>true</code> to extract "prohibited" terms, too
     */
    /*protected static final void getTermsFromPrefixQuery(PrefixQuery query, Hashtable terms,
                                                        boolean prohibited) throws IOException {
        getTerms(query.getHiLiteQuery(), terms, prohibited);
    }*/

    /**
     * Extracts all term texts of a given RangeQuery. Term texts will be returned in lower-case.
     *
     * @param query      RangeQuery to extract term texts from
     * @param terms      HashSet where extracted term texts should be put into (Elements: String)
     * @param prohibited <code>true</code> to extract "prohibited" terms, too
     */
/*
    protected static final void getTermsFromRangeQuery(RangeQuery query, Hashtable terms,
                                                       boolean prohibited) throws IOException {
        getTerms(query.getHiLiteQuery(), terms, prohibited);
    }
*/

    /**
     * Extracts the term of a given Term. The term will be returned in lower-case.
     *
     * @param term Term to extract term from
     * @param terms The hashtable to which the term information should be added, ie the field name and term value
     *
     *
     */
    /* private static void getTermsFromTerm(Term term, Hashtable terms) {
         //we must do this because we can have multiple terms from the same field and
         //we can have the different fields field with the same terms
         terms.put(term.field() + "_" + term.text().toLowerCase(), term.text().toLowerCase());
 //        return term.text().toLowerCase();
     }*/

    /**
     * Extracts the term of a given Term. The term will be returned in lower-case.
     *
     * @param term Term to extract term from
     * @param terms The hashtable to which the term information should be added, ie the field name and text for the term
     *TODO: is it here we have to control the field to decode a date ? [MP]
     */
    protected static void getTermsFromTerm(Term term, Hashtable terms) {
        terms.put(term.field() + "_" + term.text(), term.text());
//        return term.text().toLowerCase();
    }

    public static String getFieldNameFromKey(String key) {
        String fieldName = "";
        if (Utilities.checkString(key))
            fieldName = key.substring(0, key.indexOf("_"));
        return fieldName;
    }
}
