/*
Copyright (C) 2000-2010  Ministere de la culture et de la communication (France), AJLSM
See LICENCE file
*/

package fr.gouv.culture.sdx.search.lucene.query;

import fr.gouv.culture.sdx.exception.SDXException;
import fr.gouv.culture.sdx.exception.SDXExceptionCode;
import fr.gouv.culture.sdx.framework.Framework;
import fr.gouv.culture.sdx.search.lucene.Field;
import fr.gouv.culture.sdx.search.lucene.analysis.Analyzer;
import fr.gouv.culture.sdx.search.lucene.queryparser.ParseException;
import fr.gouv.culture.sdx.search.lucene.queryparser.QueryParser;
import fr.gouv.culture.sdx.search.lucene.queryparser.TokenMgrError;
import fr.gouv.culture.sdx.utils.Utilities;
import fr.gouv.culture.sdx.utils.constants.Node;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;


/**
 *	A simple query.
 *
 * <p>
 * A simple query is passed directly to Lucene. It is supposed to use the Lucene query syntax.
 */
public class SimpleQuery extends AbstractQuery {

    /** The given query string. */
    // private String queryText;

    /** The given operator. */
    private int op;

    /**Creates a query
     *
     * <p>
     * A super.getLog() must be set and then this query must be setUp.
     *
     * @see #enableLogging
     * @see #setUp
     */
    public SimpleQuery() {
    }

    /**
     *	Builds a simple query.
     *
     *  @param	sLocs	The SearchLocations object (indices to be searched).
     *	@param	q		The query string.
     */
    public void setUp(SearchLocations sLocs, String defaultField, String q) throws SDXException {
        setUp(sLocs, defaultField, q, QueryParser.DEFAULT_OPERATOR);
    }

    /**
     public void setUp(SearchLocations sLocs, String q) throws SDXException {
     setUp(sLocs, q, true);
     }
     */

    /**
     *	Builds a simple query.
     *
     *  @param	sLocs	The SearchLocations object (indices to be searched).
     *	@param	q		The query string.
     *	@param	parse	Tells if the query parser should be used.
     */

    /**
     public void setUp(SearchLocations sLocs, String q, boolean parse) throws SDXException {

     super.setSearchLocations(sLocs);

     if (q == null) throw new SDXException(null, SDXExceptionCode.ERROR_QUERY_NULL, null, null);

     this.queryText = q;

     if (parse) {
     try {

     //luceneQuery = QueryParser.parse(parseWildcards(null, escapeQuery(q)), db.getDefaultField(), db.getAnalyzer());
     //luceneQuery = QueryParser.parse(q, index.getDefaultField().getCode(), (Analyzer) index.getDefaultField().getAnalyzer());
     //luceneQuery = QueryParser.parse(q, index.getDefaultField().getCode(), new DefaultAnalyzer());
     //luceneQuery = QueryParser.parse(q, searchLocations.getDefaultField().getCode(), searchLocations.getMetaAnalyzer());
     luceneQuery = QueryParser.parse(q, searchLocations.getDefaultField().getCode(), searchLocations.getDefaultField().getAnalyzer());

     } catch (ParseException e) {
     String[] args = new String[1];
     args[0] = q;
     throw new SDXException(super.getLog(), SDXExceptionCode.ERROR_QUERY_UNPARSABLE, args, e);
     }
     } else {
     int colonIndex = queryText.indexOf(':');
     String fieldName = "";
     String queryTerm = queryText;
     if (colonIndex != -1) {
     fieldName = queryText.substring(0, colonIndex);
     try {
     queryTerm = queryText.substring(colonIndex + 1);
     } catch (IndexOutOfBoundsException e) {
     fieldName = "";
     }
     }
     if (!Utilities.checkString(fieldName)) fieldName = searchLocations.getDefaultField().getCode();
     Field theField = searchLocations.getField(fieldName);
     if (theField == null) theField = searchLocations.getDefaultField();
     luceneQuery = new TermQuery(new Term(theField.getCode(), queryTerm));
     }
     }*/

    /**
     *	Builds a simple query.
     *
     *  @param	sLocs	The SearchLocations object (indices to be searched).
     *	@param	q		The query string.
     *	@param	operator    The operator for the query (ie AND or OR).
     *  @see fr.gouv.culture.sdx.search.lucene.queryparser.QueryParser#DEFAULT_OPERATOR
     *  @see fr.gouv.culture.sdx.search.lucene.queryparser.QueryParser#OPERATOR_AND
     *  @see fr.gouv.culture.sdx.search.lucene.queryparser.QueryParser#OPERATOR_OR
     */
    public void setUp(SearchLocations sLocs, String defaultField, String q, int operator) throws SDXException {

        this.op = operator;
        //checks for null and set's the class field
        super.setSearchLocations(sLocs);

        if (q == null) throw new SDXException(null, SDXExceptionCode.ERROR_QUERY_NULL, null, null);

        Field df = null;
        if (!Utilities.checkString(defaultField)) {
            df = this.searchLocations.getDefaultField();
            if (df != null) defaultField = df.getCode();
        }

        super.queryText = q;

        try {
            QueryParser qp = searchLocations.getQueryParser();
            if (qp == null)
                throw new SDXException(super.getLog(), SDXExceptionCode.ERROR_QUERY_PARSER_NULL, null, null);
            if (df == null)
                df = searchLocations.getField(defaultField);
            Analyzer fa = null;//TODO: pourquoi chercher l'analyseur du champ par defaut alors qu'on a pu le definir dans le QueryParser du SearchLocations [MP 2007-09-19]
            if (df != null)
                fa = df.getAnalyzer();
            if (fa != null) {
                qp.setUp(defaultField, fa, searchLocations, qp.getPhraseSlop(), operator);
                //qp.setUp(defaultField, fa);
                qp.setOperator(operator);
                // qp.setSearchLocations(searchLocations);
                luceneQuery = qp.parse(q);
            }
            //TODOException?:but what if the analyzer for the field is null?
            //luceneQuery = QueryParser.parse(q, searchLocations.getDefaultField().getCode(), searchLocations.getDefaultField().getAnalyzer());

        } catch (ParseException e) {
            String[] args = new String[1];
            args[0] = q;
            throw new SDXException(super.getLog(), SDXExceptionCode.ERROR_QUERY_UNPARSABLE, args, e);
        } catch (TokenMgrError e) {
            String[] args = new String[1];
            args[0] = q;
            throw new SDXException(super.getLog(), SDXExceptionCode.ERROR_QUERY_UNPARSABLE, args, e);
        }

    }



    /**
     *	Returns a DOM representation for this query
     *
     *	@param	factory	The Document
     */
    /*
    public Element toDOM(Document factory) throws SDXException
    {
        if ( queryElement == null )
        {
            //Let's build the query representation
            queryElement = factory.createElementNS(Utilities.getSDXNamespaceURI(), Utilities.getSDXNamespacePrefix() + ":query");
            queryElement.setAttribute("xmlns:" + Utilities.getSDXNamespacePrefix(), Utilities.getSDXNamespaceURI());
            queryElement.setAttribute("type", "simple");
            queryElement.setAttribute("luceneQuery", luceneQuery.toString(dbInfo.toString()));
            queryElement.setAttribute("text", queryText);

            //Then add the filter
            if ( filter != null ) queryElement.appendChild(filter.toDOM(factory));

            //Then add the base query
            if ( baseQuery != null )
            {
                Element baseQueryEl = factory.createElementNS(Utilities.getSDXNamespaceURI(), Utilities.getSDXNamespacePrefix() + ":baseQuery");
                baseQueryEl.setAttribute("xmlns:" + Utilities.getSDXNamespacePrefix(), Utilities.getSDXNamespaceURI());
                baseQueryEl.appendChild(baseQuery.toDOM(factory));
                queryElement.appendChild(baseQueryEl);
            }

            return queryElement;
        }
        else
        {
            //Already got it
            return (Element)factory.importNode(queryElement, true);
        }
    }
    */

    /**
     *	Returns a SAX representation of this query.
     *
     *	@param	hdl		The ContentHandler to feed with events.
     */
    public void toSAX(ContentHandler hdl) throws SAXException {

        String sdxNsUri = Framework.SDXNamespaceURI;
        String sdxNsPrefix = Framework.SDXNamespacePrefix;
        String localName = Node.Name.QUERY;
        String qName = sdxNsPrefix + ":" + localName;

        AttributesImpl atts = new AttributesImpl();
        atts.addAttribute("", Node.Name.TYPE, Node.Name.TYPE, Node.Type.CDATA, Node.Name.SIMPLE_QUERY);
        atts.addAttribute("", Node.Name.QUERYPARSER_CLASS, Node.Name.QUERYPARSER_CLASS, Node.Type.CDATA, searchLocations.getQueryParser().getClass().getName());
        atts = super.addAttributesLucene(atts);
        atts = super.addAttributesText(atts);
        switch (this.op) {
            case AbstractQuery.OPERATOR_AND:
                atts.addAttribute("", Node.Name.OP, Node.Name.OP, Node.Type.CDATA, "and"); //TODO : remove hard-coded
                break;
            case AbstractQuery.OPERATOR_OR:
                atts.addAttribute("", Node.Name.OP, Node.Name.OP, Node.Type.CDATA, "or"); //TODO : remove hard-coded
                break;
            case AbstractQuery.OPERATOR_NOT:
                atts.addAttribute("", Node.Name.OP, Node.Name.OP, Node.Type.CDATA, "not"); //TODO : remove hard-coded
                break;
        }
        //Let's build the query representation
        hdl.startElement(sdxNsUri, localName, qName, atts);

        //Then add the search locations
        this.getSearchLocations().toSAX(hdl);

        //Then add the filter
        if (filter != null) filter.toSAX(hdl);

        //Then add the base query
        if (baseQuery != null) {
            String bqLocalName = Node.Name.BASE_QUERY;
            String bqQName = sdxNsPrefix + ":" + bqLocalName;
            hdl.startElement(sdxNsUri, bqLocalName, bqQName, new AttributesImpl());
            baseQuery.toSAX(hdl);
            hdl.endElement(sdxNsUri, bqLocalName, bqQName);
        }

        //All over
        hdl.endElement(sdxNsUri, localName, qName);
    }

}
