/*
 * LIUS - Lucene Index Update and Search
 * http://sourceforge.net/projects/lius/
 *
 * Copyright (c) 2004, Laval University Library.  All rights reserved.
 *
 * This program is a free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 * This program 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
 * General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */
package ca.ulaval.bibl.lius.search;


import org.apache.lucene.search.Query;
import org.apache.lucene.index.Term;
import java.lang.reflect.Constructor;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.queryParser.MultiFieldQueryParser;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.search.RangeQuery;

import ca.ulaval.bibl.lius.Lucene.AnalyzerFactory;
import ca.ulaval.bibl.lius.config.LiusConfig;

/**
 * Classe permettant de créer des objets de type Query.
 * <br/><br/>
 * Class that creates Query objects.
 * @author Rida Benjelloun (rida.benjelloun@bibl.ulaval.ca)
 */
public class LiusQuery {

private static LiusQuery liusQueryInst;
private  Query q = null;

  /*public static LiusQuery getSingletonInstance() {
    if (liusQueryInst == null)
      liusQueryInst = new LiusQuery();
    return liusQueryInst;
  }*/

  /**
   * Méthode utilisant la réflexion et permettant de créer des objets de type Query,
   * dont le constructeur prend un objet de type Term.
   * L'objet Term est construit à partir du nom du champs spécifié dans le
   * fichier de configuration et de la valeur exprimée sous forme de paramètre
   * "searchExp"de la méthode createQueryTerm.
   * <br/><br/>
   * The method uses reflection which creates object of type Query which constructor takes
   * an object of type Term as parameter. The Term object is constructed from
   * the name of the specified field in the configuration file and the value of
   * "searchExp" parameter.
   */
  public Query createQueryTerm(LiusConfig xc, String searchExp) {

    try {
      Class classe = Class.forName(xc.getQueryTermClass());
      Constructor[] con = classe.getConstructors();
      for (int i = 0; i < con.length; i++) {
        Class[] conParam = con[i].getParameterTypes();
        for (int j = 0; j < conParam.length; j++)
          if (conParam[j].getName().equals("org.apache.lucene.index.Term")) {
            // Création de l'objet Term
            Term t = new Term(xc.getTermFiled(), searchExp);
            q = (Query) con[i].newInstance(new Object[] {t});
          }
      }

    }

    catch (ClassNotFoundException e) {
      System.out.println("La classe n'a pas été trouvée" + e.getMessage());
    }
    catch (InstantiationException e) {
      System.out.println("La classe est soit abstraite, soit une interface" +
                         e.getMessage());
    }
    catch (IllegalAccessException e) {
      System.out.println("La classe n'est pas accessible" + e.getMessage());
    }
    catch (java.lang.reflect.InvocationTargetException e) {
      System.out.println(" Exception déclenchée si le constructeur invoqué" +
                         e.getMessage());
    }
    catch (IllegalArgumentException e) {
      System.out.println(" Mauvais type de paramètres " + e.getMessage());
    }
    return q;
  }

  /**
   * Création d'un objet Query de type MultiFieldQueryParser à partir du
   * fichier de configuration.
   * <br/><br/<
   * Creation of an object Query of type MultiFieldQueryParser from the
   * configuration file.
   */
  public Query createMultiFieldQueryParser(LiusConfig xc, String searchExp) {

    try {
      q = MultiFieldQueryParser.parse(searchExp, xc.getSearchFields(),
                                      AnalyzerFactory.getAnalyzer(xc));
    }
    catch (ParseException e) {
      e.printStackTrace();
    }
    return q;
  }

  /**
   * Création d'un objet Query de type QueryParser à partir du fichier de
   * configuration.
   * <br/><br/>
   * Creation of a Query object of type QueryParser from the configuration file.
   */
  public Query createQueryParser(LiusConfig xc, String searchExp) {

    try {
      q = QueryParser.parse(searchExp, xc.getDefaultSearchField(),
                            AnalyzerFactory.getAnalyzer(xc));
    }
    catch (ParseException e) {
      e.printStackTrace();
    }
    return q;
  }

  /**
   * Méthode permettant de créer un objet Query en fonction de l'élément
   * XML trouvé dans le fichier de configuration.
   * <br/><br/>
   * Method that creates a Query Object relative to the XML element found in the
   * configuration file.
   */
  public Query getQueryFactory(String type, LiusConfig xc, String searchExp) {

    if (type.equals("queryTerm"))
      q = createQueryTerm(xc, searchExp);
    else if (type.equals("queryParser"))
      q = createQueryParser(xc, searchExp);
    else if (type.equals("multiFieldQueryParser"))
      q = createMultiFieldQueryParser(xc, searchExp);
    return q;
  }

  /**
   * Création d'un objet Query de type RangeQuery à partir du fichier
   * de configuration.
   * <br/><br/>
   * Creation of a Query object of type RangeQuery from the configuration file.
   */
  public Query createRangeQuery(LiusConfig xc, String lowerSearchExp1,
                                String uppersearchExp2) {

    String[] values = xc.getRangeQueryFileds();
    boolean inclusive = true;
    if (values[1].equalsIgnoreCase("true")) {
      inclusive = true;
    }
    else {
      inclusive = false;
    }
    Term t1 = new Term(values[0], lowerSearchExp1);
    Term t2 = new Term(values[0], uppersearchExp2);
    q = new RangeQuery(t1, t2, inclusive);

    return q;
  }

}