Index: main/trunk/greenstone3/src/java/org/greenstone/gsdl3/service/AbstractGS2FieldSearch.java
===================================================================
--- main/trunk/greenstone3/src/java/org/greenstone/gsdl3/service/AbstractGS2FieldSearch.java	(revision 24393)
+++ main/trunk/greenstone3/src/java/org/greenstone/gsdl3/service/AbstractGS2FieldSearch.java	(revision 24394)
@@ -40,5 +40,5 @@
 
 abstract public class AbstractGS2FieldSearch 
-    extends AbstractGS2Search 
+    extends AbstractGS2TextSearch 
 {
 
@@ -159,8 +159,8 @@
 	  } 
 	  
-	  // AbstractGS2Search has set up the text query service, but we may not want it
+	  // AbstractGS2TextSearch has set up the TextQuery service, but we may not want it
 	  if (!this.plain_search) {
 	    // need to remove the TextQuery service
-	    Element tq_service = GSXML.getNamedElement(short_service_info, GSXML.SERVICE_ELEM, GSXML.NAME_ATT, TEXT_QUERY_SERVICE);
+	    Element tq_service = GSXML.getNamedElement(short_service_info, GSXML.SERVICE_ELEM, GSXML.NAME_ATT, QUERY_SERVICE);
 	    short_service_info.removeChild(tq_service);
 	    
@@ -200,5 +200,5 @@
 	
 	// the format info is the same for all services
-	Element format_info = (Element)format_info_map.get(TEXT_QUERY_SERVICE);
+	Element format_info = (Element)format_info_map.get(QUERY_SERVICE);
 	
 	// set up the extra services which are available for this collection
@@ -349,5 +349,5 @@
 	} else if (name.equals(FIELD_CASE_PARAM) || name.equals(FIELD_STEM_PARAM) || name.equals(FIELD_ACCENT_PARAM)) {
 	    String[] bool_ops = {"0", "1"};
-	    String[] bool_texts = {getTextString("param.boolean.off", lang, "AbstractSearch"),getTextString("param.boolean.on", lang, "AbstractSearch")}; 
+	    String[] bool_texts = {getTextString("param.boolean.off", lang, "AbstractTextSearch"),getTextString("param.boolean.on", lang, "AbstractTextSearch")}; 
 	    param = GSXML.createParameterDescription(this.doc, name, getTextString("param."+name, lang), GSXML.PARAM_TYPE_BOOLEAN, BOOLEAN_PARAM_ON, bool_ops, bool_texts);
 	    
@@ -430,5 +430,4 @@
     protected Element processAnyQuery(Element request, int query_type)
     {
-
 	String service_name=null;
 	String empty_query_test_param=null;
@@ -436,5 +435,5 @@
 	switch (query_type) {
 	case TEXT_QUERY:
-	    service_name = TEXT_QUERY_SERVICE; 
+	    service_name = QUERY_SERVICE; 
 	    empty_query_test_param = QUERY_PARAM;
 	    break;
Index: main/trunk/greenstone3/src/java/org/greenstone/gsdl3/service/AbstractGS2Search.java
===================================================================
--- main/trunk/greenstone3/src/java/org/greenstone/gsdl3/service/AbstractGS2Search.java	(revision 24393)
+++ 	(revision )
@@ -1,389 +1,0 @@
-/*
- *    GS2MGSearch.java
- *    Copyright (C) 2002 New Zealand Digital Library, http://www.nzdl.org
- *
- *    This program is free software; you can redistribute it and/or modify
- *   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., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-package org.greenstone.gsdl3.service;
-
-
-// Greenstone classes
-import org.greenstone.gsdl3.util.OID;
-import org.greenstone.gsdl3.util.DBInfo;
-import org.greenstone.gsdl3.util.GSXML;
-import org.greenstone.gsdl3.util.SimpleCollectionDatabase;
-import org.greenstone.gsdl3.util.GSFile;
-
-// XML classes
-import org.w3c.dom.Document;
-import org.w3c.dom.Element; 
-import org.w3c.dom.NodeList;
-
-// java
-import java.util.Vector;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-import java.util.Iterator;
-import java.io.File;
-
-import org.apache.log4j.*;
-
-public abstract class AbstractGS2Search 
-    extends AbstractSearch 
-{
-
-    protected static final String EQUIV_TERM_ELEM = "equivTerm";
-
-    protected static final String STEM_ATT = "stem";
-    protected static final String NUM_DOCS_MATCH_ATT = "numDocsMatch";
-    protected static final String FREQ_ATT = "freq";
-
-    // Elements used in the config file that are specific to this class
-    protected static final String DEFAULT_INDEX_ELEM = "defaultIndex";
-    protected static final String INDEX_STEM_ELEM = "indexStem";
-    protected static final String INDEX_ELEM = "index";
-    protected static final String DEFAULT_INDEX_SUBCOLLECTION_ELEM = "defaultIndexSubcollection";
-    protected static final String DEFAULT_INDEX_LANGUAGE_ELEM = "defaultIndexLanguage";
-    protected static final String INDEX_SUBCOLLECTION_ELEM = "indexSubcollection";
-    protected static final String INDEX_LANGUAGE_ELEM = "indexLanguage";
-   
-
-    // Some indexing options
-    protected static final String STEMINDEX_OPTION = "stemIndexes";
-    protected static final String MAXNUMERIC_OPTION = "maxnumeric";
-
-    /** the stem used for the index files */
-    protected String index_stem = null;
-
-    // stem indexes available
-    protected boolean does_case=true;
-    protected boolean does_stem=true;
-    protected boolean does_accent=false;
-
-    // maxnumeric - 
-    protected int maxnumeric = 4;
-
-    // collection database
-    protected SimpleCollectionDatabase coll_db = null;
-
-    static Logger logger = Logger.getLogger(org.greenstone.gsdl3.service.AbstractGS2Search.class.getName());
-
-
-    /** constructor */
-    public AbstractGS2Search()
-    {
-	
-    }
-    public void cleanUp() {
-	super.cleanUp();
-	this.coll_db.closeDatabase();
-    }
-
-    /** configure this service */
-    public boolean configure(Element info, Element extra_info)
-    {
-	if (!super.configure(info, extra_info)){
-	    return false;
-	}
-
-	// find out what kind of database we have
-	Element database_type_elem = (Element) GSXML.getChildByTagName(info, GSXML.DATABASE_TYPE_ELEM);
-	String database_type = null;
-	if (database_type_elem != null) {
-	  database_type = database_type_elem.getAttribute(GSXML.NAME_ATT);
-	}
-	if (database_type == null || database_type.equals("")) {
-	  database_type = "gdbm"; // the default
-	}
-	coll_db = new SimpleCollectionDatabase(database_type);
-	if (!coll_db.databaseOK()) {
-	  logger.error("Couldn't create the collection database of type "+database_type);
-	  return false;
-	}
-	
-	// the index stem is either the collection name or is specified in the config file
-	Element index_stem_elem = (Element) GSXML.getChildByTagName(info, INDEX_STEM_ELEM);
-	if (index_stem_elem != null) {
-	    this.index_stem = index_stem_elem.getAttribute(GSXML.NAME_ATT);
-	}
-	if (this.index_stem == null || this.index_stem.equals("")) {
-	    logger.warn("indexStem element not found, stem will default to collection name");
-	    this.index_stem = this.cluster_name;
-	}
-
-	// Open database for querying
-	String coll_db_file = GSFile.collectionDatabaseFile(this.site_home, this.cluster_name, this.index_stem, database_type);
-	if (!this.coll_db.openDatabase(coll_db_file, SimpleCollectionDatabase.READ)) {
-	    logger.error("Could not open collection database!");
-	    return false;
-	}
-
-	// do we support any of the extended features?
-	does_chunking = true;
-
-	// Get the default index out of <defaultIndex> (buildConfig.xml)
-	Element def = (Element) GSXML.getChildByTagName(info, DEFAULT_INDEX_ELEM);
-	if (def != null) {
-	    this.default_index = def.getAttribute(GSXML.SHORTNAME_ATT);
-	} // otherwise will be "", and the first one will be the default
-        
-        //get the default indexSubcollection out of <defaultIndexSubcollection> (buildConfig.xml)
-        Element defSub = (Element) GSXML.getChildByTagName(info, DEFAULT_INDEX_SUBCOLLECTION_ELEM); 
-	if (defSub != null) {
-	    this.default_index_subcollection = defSub.getAttribute(GSXML.SHORTNAME_ATT);
-	} 
-
-	//get the default indexLanguage out of <defaultIndexLanguage> (buildConfig.xml)
-        Element defLang = (Element) GSXML.getChildByTagName(info, DEFAULT_INDEX_LANGUAGE_ELEM); 
-	if (defLang != null) {
-	    this.default_index_language = defLang.getAttribute(GSXML.SHORTNAME_ATT);
-	} //concate defaultIndex + defaultIndexSubcollection + defaultIndexLanguage
-     	
-	// get index options
-	Element index_option_list = (Element) GSXML.getChildByTagName(info, GSXML.INDEX_OPTION_ELEM + GSXML.LIST_MODIFIER);
-	if (index_option_list != null) {
-	    NodeList options = index_option_list.getElementsByTagName(GSXML.INDEX_OPTION_ELEM);
-	    for (int i=0; i<options.getLength(); i++) {
-		Element opt = (Element)options.item(i);
-		String name = opt.getAttribute(GSXML.NAME_ATT);
-		String value = opt.getAttribute(GSXML.VALUE_ATT);
-		if (name.equals(MAXNUMERIC_OPTION)) {
-		    int maxnum = Integer.parseInt(value);
-		    if (4 <= maxnum && maxnum < 512) {
-			maxnumeric = maxnum;
-		    }
-		}
-		else if (name.equals(STEMINDEX_OPTION)) {
-		    int stemindex = Integer.parseInt(value);
-		    // stem and case are true by default, accent folding false by default
-		    if ((stemindex & 1) == 0) {
-			does_case = false;
-		    }
-		    if ((stemindex & 2) == 0) {
-			does_stem = false;
-		    }
-		    if ((stemindex & 4) != 0) {
-			does_accent = true;
-		    }
-		}
-	    }
-	}
-
-	// get display info from extra info
-	if (extra_info !=null) {
-	    Document owner = info.getOwnerDocument();
-	    // so far we have index specific display elements, and global format elements 
-	    NodeList indexes = info.getElementsByTagName(GSXML.INDEX_ELEM);
-	    Element config_search = (Element)GSXML.getChildByTagName(extra_info, GSXML.SEARCH_ELEM);
-	    
-	    for (int i=0; i<indexes.getLength();i++) {
-		Element ind = (Element)indexes.item(i);
-		String name = ind.getAttribute(GSXML.NAME_ATT);
-		Element node_extra = GSXML.getNamedElement(config_search,
-							   GSXML.INDEX_ELEM,
-							   GSXML.NAME_ATT,
-							   name);
-		if (node_extra == null) {
-		    logger.error("haven't found extra info for index named "+name);
-		    continue;
-		}
-		
-		// get the display elements if any - displayName
-		NodeList display_names = node_extra.getElementsByTagName(GSXML.DISPLAY_TEXT_ELEM);
-		if (display_names !=null) {
-		    for (int j=0; j<display_names.getLength(); j++) {
-			Element e = (Element)display_names.item(j);
-			ind.appendChild(owner.importNode(e, true));
-		    }
-		}
-	    } // for each index
-	}
-	return true;
-    }
-
-    protected void getIndexData(ArrayList index_ids, ArrayList index_names, String lang) {
-	// the index info -
-	Element index_list = (Element)GSXML.getChildByTagName(this.config_info, INDEX_ELEM+GSXML.LIST_MODIFIER);
-	NodeList indexes = index_list.getElementsByTagName(INDEX_ELEM);
-	int len = indexes.getLength();
-	// now add even if there is only one
-	for (int i=0; i<len; i++) {
-	    Element index = (Element)indexes.item(i);
-	    String shortname = index.getAttribute(GSXML.SHORTNAME_ATT);
-	    if (shortname.equals("")) {
-		continue;
-	    }
-	    index_ids.add(shortname);
-	    String display_name = GSXML.getDisplayText(index, GSXML.DISPLAY_TEXT_NAME, lang, "en");
-	    if (display_name.equals("")) {
-		display_name = index.getAttribute(GSXML.NAME_ATT);
-		if (display_name.equals("")) {
-		    display_name = shortname;
-		}
-	    }
-	    index_names.add(display_name);
-	}	
-    }
-
-    protected void getIndexSubcollectionData(ArrayList index_sub_ids, ArrayList index_sub_names, String lang){
-	// the index info -
-	Element index_sub_list = (Element)GSXML.getChildByTagName(this.config_info, INDEX_SUBCOLLECTION_ELEM+GSXML.LIST_MODIFIER);
-	NodeList index_subs = index_sub_list.getElementsByTagName(INDEX_SUBCOLLECTION_ELEM);
-	int len = index_subs.getLength();
-	// now add even if there is only one
-	for (int i=0; i<len; i++) {
-	    Element indexsub = (Element)index_subs.item(i);
-	    String shortname = indexsub.getAttribute(GSXML.SHORTNAME_ATT);
-	    if (shortname.equals("")) {
-		continue;
-	    }
-	    index_sub_ids.add(shortname);
-	    String display_name = GSXML.getDisplayText(indexsub, GSXML.DISPLAY_TEXT_NAME, lang, "en");
-	    if (display_name.equals("")) {
-		display_name = indexsub.getAttribute(GSXML.NAME_ATT);
-		if (display_name.equals("")) {
-		    display_name = shortname;
-		}
-	    }
-	    index_sub_names.add(display_name);
-	}		 
-     }
-      
-    protected void getIndexLanguageData(ArrayList index_lang_ids, ArrayList index_lang_names, String lang){
-	// the index info -
-	Element index_lang_list = (Element)GSXML.getChildByTagName(this.config_info, INDEX_LANGUAGE_ELEM+GSXML.LIST_MODIFIER);
-	NodeList index_langs = index_lang_list.getElementsByTagName(INDEX_LANGUAGE_ELEM);
-	int len = index_langs.getLength();
-	// now add even if there is only one
-	for (int i=0; i<len; i++) {
-	    Element indexlang = (Element)index_langs.item(i);
-	    String shortname = indexlang.getAttribute(GSXML.SHORTNAME_ATT);
-	    if (shortname.equals("")) {
-		continue;
-	    }
-	    index_lang_ids.add(shortname);
-	    String display_name = GSXML.getDisplayText(indexlang, GSXML.DISPLAY_TEXT_NAME, lang, "en");
-	    if (display_name.equals("")) {
-		display_name = indexlang.getAttribute(GSXML.NAME_ATT);
-		if (display_name.equals("")) {
-		    display_name = shortname;
-		}
-	    }
-	    index_lang_names.add(display_name);
-	}	
-	
-
-    }
-
-
-    protected void addCustomQueryParams(Element param_list, String lang) 
-    {
-	if (this.does_case){
-	  // gs2 has case on by default
-	  createParameter(CASE_PARAM, param_list, lang,  BOOLEAN_PARAM_ON);
-	}
-	if (this.does_stem){
-	  // but stem is off by default
-	  createParameter(STEM_PARAM, param_list, lang, BOOLEAN_PARAM_OFF);
-	}
-	if (this.does_accent){
-	  // and so is accent folding
-	    createParameter(ACCENT_PARAM, param_list, lang, BOOLEAN_PARAM_OFF);
-	}
-	createParameter(MATCH_PARAM, param_list, lang);
-    }
-
-
-
-    /** returns the document type of the doc that the specified node 
-	belongs to. should be one of 
-	GSXML.DOC_TYPE_SIMPLE, 
-	GSXML.DOC_TYPE_PAGED, 
-	GSXML.DOC_TYPE_HIERARCHY
-    */
-    protected String getDocType(String node_id){
-	DBInfo info = this.coll_db.getInfo(node_id);
-	if (info == null) {
-	    return GSXML.DOC_TYPE_SIMPLE;
-	}
-	String doc_type = info.getInfo("doctype");
-	if (!doc_type.equals("")&&!doc_type.equals("doc")) {
-	    return doc_type;
-	}
-
-	String top_id = OID.getTop(node_id);
-	boolean is_top = (top_id.equals(node_id) ? true : false);
-	
-	String children = info.getInfo("contains");
-	boolean is_leaf = (children.equals("") ? true : false);
-
-	if (is_top && is_leaf) { // a single section document
-	    return GSXML.DOC_TYPE_SIMPLE;
-	}
-
-	// now we just check the top node
-	if (!is_top) { // we need to look at the top info
-	    info = this.coll_db.getInfo(top_id);
-	}
-	if (info == null) {
-	    return GSXML.DOC_TYPE_HIERARCHY;
-	}
- 
-	String childtype = info.getInfo("childtype");
-	if (childtype.equals("Paged")) {
-	    return GSXML.DOC_TYPE_PAGED;
-	}
-	return GSXML.DOC_TYPE_HIERARCHY;
-
-    }
-    
-    /** returns true if the node has child nodes */
-    protected boolean hasChildren(String node_id){
-	DBInfo info = this.coll_db.getInfo(node_id);
-	if (info == null) {
-	    return false;
-	}
-	String contains = info.getInfo("contains");
-	if (contains.equals("")) {
-	    return false;
-	}
-	return true;
-    }
-    
-    /** returns true if the node has a parent */
-    protected boolean hasParent(String node_id){
-	String parent = OID.getParent(node_id);
-	if (parent.equals(node_id)) {
-	    return false;
-	}
-	return true;
-    }
-    
-   /** convert indexer internal id to Greenstone oid */
-    protected String internalNum2OID(long docnum)
-    {
-	return this.coll_db.docnum2OID(docnum);
-	
-    }
-    protected String internalNum2OID(String docnum)
-    {
-	return this.coll_db.docnum2OID(docnum);
-	
-    }
-
-}
-
-
Index: main/trunk/greenstone3/src/java/org/greenstone/gsdl3/service/AbstractGS2TextSearch.java
===================================================================
--- main/trunk/greenstone3/src/java/org/greenstone/gsdl3/service/AbstractGS2TextSearch.java	(revision 24394)
+++ main/trunk/greenstone3/src/java/org/greenstone/gsdl3/service/AbstractGS2TextSearch.java	(revision 24394)
@@ -0,0 +1,324 @@
+/*
+ *    AbstractGS2TextSearch.java
+ *    Copyright (C) 2011 New Zealand Digital Library, http://www.nzdl.org
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *   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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+package org.greenstone.gsdl3.service;
+
+
+// Greenstone classes
+import org.greenstone.gsdl3.util.OID;
+import org.greenstone.gsdl3.util.DBInfo;
+import org.greenstone.gsdl3.util.GSXML;
+import org.greenstone.gsdl3.util.SimpleDocumentDatabase;
+import org.greenstone.gsdl3.util.GSFile;
+
+// XML classes
+import org.w3c.dom.Document;
+import org.w3c.dom.Element; 
+import org.w3c.dom.NodeList;
+
+// java
+import java.util.Vector;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.Iterator;
+import java.io.File;
+
+import org.apache.log4j.*;
+
+public abstract class AbstractGS2TextSearch 
+    extends AbstractTextSearch 
+{
+
+    protected static final String EQUIV_TERM_ELEM = "equivTerm";
+
+    protected static final String STEM_ATT = "stem";
+    protected static final String NUM_DOCS_MATCH_ATT = "numDocsMatch";
+    protected static final String FREQ_ATT = "freq";
+
+    // Elements used in the config file that are specific to this class
+    protected static final String DEFAULT_INDEX_ELEM = "defaultIndex";
+    protected static final String INDEX_STEM_ELEM = "indexStem";
+    protected static final String INDEX_ELEM = "index";
+    protected static final String DEFAULT_INDEX_SUBCOLLECTION_ELEM = "defaultIndexSubcollection";
+    protected static final String DEFAULT_INDEX_LANGUAGE_ELEM = "defaultIndexLanguage";
+    protected static final String INDEX_SUBCOLLECTION_ELEM = "indexSubcollection";
+    protected static final String INDEX_LANGUAGE_ELEM = "indexLanguage";
+   
+
+    // Some indexing options
+    protected static final String STEMINDEX_OPTION = "stemIndexes";
+    protected static final String MAXNUMERIC_OPTION = "maxnumeric";
+
+    /** the stem used for the index files */
+    protected String index_stem = null;
+
+    // stem indexes available
+    protected boolean does_case=true;
+    protected boolean does_stem=true;
+    protected boolean does_accent=false;
+
+    // maxnumeric - 
+    protected int maxnumeric = 4;
+
+    SimpleDocumentDatabase gs_doc_db = null;
+
+    static Logger logger = Logger.getLogger(org.greenstone.gsdl3.service.AbstractGS2TextSearch.class.getName());
+
+
+    /** constructor */
+    public AbstractGS2TextSearch()
+    {
+	
+    }
+    public void cleanUp() {
+	super.cleanUp();
+	this.gs_doc_db.cleanUp();
+    }
+
+    /** configure this service */
+    public boolean configure(Element info, Element extra_info)
+    {
+	if (!super.configure(info,extra_info)) {
+	    return false;
+	}
+
+	// find out what kind of database we have
+	Element database_type_elem = (Element) GSXML.getChildByTagName(info, GSXML.DATABASE_TYPE_ELEM);
+	String database_type = null;
+	if (database_type_elem != null) {
+	  database_type = database_type_elem.getAttribute(GSXML.NAME_ATT);
+	}
+	if (database_type == null || database_type.equals("")) {
+	  database_type = "gdbm"; // the default
+	}
+	
+	// the index stem is either the collection name or is specified in the config file
+	Element index_stem_elem = (Element) GSXML.getChildByTagName(info, INDEX_STEM_ELEM);
+	if (index_stem_elem != null) {
+	    this.index_stem = index_stem_elem.getAttribute(GSXML.NAME_ATT);
+	}
+	if (this.index_stem == null || this.index_stem.equals("")) {
+	    logger.warn("indexStem element not found, stem will default to collection name");
+	    this.index_stem = this.cluster_name;
+	}
+
+	// replaces default AbstractSearch version with one tied to database
+	gs_doc_db = new SimpleDocumentDatabase(this.doc, 
+					       database_type,this.site_home,
+					       this.cluster_name,
+					       this.index_stem);
+	if (!gs_doc_db.isValid()) {
+	    logger.error("Failed to open Document Database.");
+	    return false;
+	}
+	this.gs_doc = gs_doc_db; 
+
+	// do we support any of the extended features?
+	does_chunking = true;
+
+	// Get the default index out of <defaultIndex> (buildConfig.xml)
+	Element def = (Element) GSXML.getChildByTagName(info, DEFAULT_INDEX_ELEM);
+	if (def != null) {
+	    this.default_index = def.getAttribute(GSXML.SHORTNAME_ATT);
+	} // otherwise will be "", and the first one will be the default
+        
+        //get the default indexSubcollection out of <defaultIndexSubcollection> (buildConfig.xml)
+        Element defSub = (Element) GSXML.getChildByTagName(info, DEFAULT_INDEX_SUBCOLLECTION_ELEM); 
+	if (defSub != null) {
+	    this.default_index_subcollection = defSub.getAttribute(GSXML.SHORTNAME_ATT);
+	} 
+
+	//get the default indexLanguage out of <defaultIndexLanguage> (buildConfig.xml)
+        Element defLang = (Element) GSXML.getChildByTagName(info, DEFAULT_INDEX_LANGUAGE_ELEM); 
+	if (defLang != null) {
+	    this.default_index_language = defLang.getAttribute(GSXML.SHORTNAME_ATT);
+	} //concate defaultIndex + defaultIndexSubcollection + defaultIndexLanguage
+     	
+	// get index options
+	Element index_option_list = (Element) GSXML.getChildByTagName(info, GSXML.INDEX_OPTION_ELEM + GSXML.LIST_MODIFIER);
+	if (index_option_list != null) {
+	    NodeList options = index_option_list.getElementsByTagName(GSXML.INDEX_OPTION_ELEM);
+	    for (int i=0; i<options.getLength(); i++) {
+		Element opt = (Element)options.item(i);
+		String name = opt.getAttribute(GSXML.NAME_ATT);
+		String value = opt.getAttribute(GSXML.VALUE_ATT);
+		if (name.equals(MAXNUMERIC_OPTION)) {
+		    int maxnum = Integer.parseInt(value);
+		    if (4 <= maxnum && maxnum < 512) {
+			maxnumeric = maxnum;
+		    }
+		}
+		else if (name.equals(STEMINDEX_OPTION)) {
+		    int stemindex = Integer.parseInt(value);
+		    // stem and case are true by default, accent folding false by default
+		    if ((stemindex & 1) == 0) {
+			does_case = false;
+		    }
+		    if ((stemindex & 2) == 0) {
+			does_stem = false;
+		    }
+		    if ((stemindex & 4) != 0) {
+			does_accent = true;
+		    }
+		}
+	    }
+	}
+
+	// get display info from extra info
+	if (extra_info !=null) {
+	    Document owner = info.getOwnerDocument();
+	    // so far we have index specific display elements, and global format elements 
+	    NodeList indexes = info.getElementsByTagName(GSXML.INDEX_ELEM);
+	    Element config_search = (Element)GSXML.getChildByTagName(extra_info, GSXML.SEARCH_ELEM);
+	    
+	    for (int i=0; i<indexes.getLength();i++) {
+		Element ind = (Element)indexes.item(i);
+		String name = ind.getAttribute(GSXML.NAME_ATT);
+		Element node_extra = GSXML.getNamedElement(config_search,
+							   GSXML.INDEX_ELEM,
+							   GSXML.NAME_ATT,
+							   name);
+		if (node_extra == null) {
+		    logger.error("haven't found extra info for index named "+name);
+		    continue;
+		}
+		
+		// get the display elements if any - displayName
+		NodeList display_names = node_extra.getElementsByTagName(GSXML.DISPLAY_TEXT_ELEM);
+		if (display_names !=null) {
+		    for (int j=0; j<display_names.getLength(); j++) {
+			Element e = (Element)display_names.item(j);
+			ind.appendChild(owner.importNode(e, true));
+		    }
+		}
+	    } // for each index
+	}
+	return true;
+    }
+
+    protected void getIndexData(ArrayList index_ids, ArrayList index_names, String lang) 
+    {
+	// the index info -
+	Element index_list = (Element)GSXML.getChildByTagName(this.config_info, INDEX_ELEM+GSXML.LIST_MODIFIER);
+	NodeList indexes = index_list.getElementsByTagName(INDEX_ELEM);
+	int len = indexes.getLength();
+	// now add even if there is only one
+	for (int i=0; i<len; i++) {
+	    Element index = (Element)indexes.item(i);
+	    String shortname = index.getAttribute(GSXML.SHORTNAME_ATT);
+	    if (shortname.equals("")) {
+		continue;
+	    }
+	    index_ids.add(shortname);
+	    String display_name = GSXML.getDisplayText(index, GSXML.DISPLAY_TEXT_NAME, lang, "en");
+	    if (display_name.equals("")) {
+		display_name = index.getAttribute(GSXML.NAME_ATT);
+		if (display_name.equals("")) {
+		    display_name = shortname;
+		}
+	    }
+	    index_names.add(display_name);
+	}	
+    }
+
+    protected void getIndexSubcollectionData(ArrayList index_sub_ids, ArrayList index_sub_names, String lang)
+    {
+	// the index info -
+	Element index_sub_list = (Element)GSXML.getChildByTagName(this.config_info, INDEX_SUBCOLLECTION_ELEM+GSXML.LIST_MODIFIER);
+	NodeList index_subs = index_sub_list.getElementsByTagName(INDEX_SUBCOLLECTION_ELEM);
+	int len = index_subs.getLength();
+	// now add even if there is only one
+	for (int i=0; i<len; i++) {
+	    Element indexsub = (Element)index_subs.item(i);
+	    String shortname = indexsub.getAttribute(GSXML.SHORTNAME_ATT);
+	    if (shortname.equals("")) {
+		continue;
+	    }
+	    index_sub_ids.add(shortname);
+	    String display_name = GSXML.getDisplayText(indexsub, GSXML.DISPLAY_TEXT_NAME, lang, "en");
+	    if (display_name.equals("")) {
+		display_name = indexsub.getAttribute(GSXML.NAME_ATT);
+		if (display_name.equals("")) {
+		    display_name = shortname;
+		}
+	    }
+	    index_sub_names.add(display_name);
+	}		 
+     }
+      
+    protected void getIndexLanguageData(ArrayList index_lang_ids, ArrayList index_lang_names, String lang)
+    {
+	// the index info -
+	Element index_lang_list = (Element)GSXML.getChildByTagName(this.config_info, INDEX_LANGUAGE_ELEM+GSXML.LIST_MODIFIER);
+	NodeList index_langs = index_lang_list.getElementsByTagName(INDEX_LANGUAGE_ELEM);
+	int len = index_langs.getLength();
+	// now add even if there is only one
+	for (int i=0; i<len; i++) {
+	    Element indexlang = (Element)index_langs.item(i);
+	    String shortname = indexlang.getAttribute(GSXML.SHORTNAME_ATT);
+	    if (shortname.equals("")) {
+		continue;
+	    }
+	    index_lang_ids.add(shortname);
+	    String display_name = GSXML.getDisplayText(indexlang, GSXML.DISPLAY_TEXT_NAME, lang, "en");
+	    if (display_name.equals("")) {
+		display_name = indexlang.getAttribute(GSXML.NAME_ATT);
+		if (display_name.equals("")) {
+		    display_name = shortname;
+		}
+	    }
+	    index_lang_names.add(display_name);
+	}	
+	
+
+    }
+
+
+    protected void addCustomQueryParams(Element param_list, String lang) 
+    {
+	if (this.does_case){
+	  // gs2 has case on by default
+	  createParameter(CASE_PARAM, param_list, lang,  BOOLEAN_PARAM_ON);
+	}
+	if (this.does_stem){
+	  // but stem is off by default
+	  createParameter(STEM_PARAM, param_list, lang, BOOLEAN_PARAM_OFF);
+	}
+	if (this.does_accent){
+	  // and so is accent folding
+	    createParameter(ACCENT_PARAM, param_list, lang, BOOLEAN_PARAM_OFF);
+	}
+	createParameter(MATCH_PARAM, param_list, lang);
+    }
+
+    
+    /** convert indexer internal id to Greenstone oid */
+    protected String internalNum2OID(long docnum)
+    {
+	return this.gs_doc_db.internalNum2OID(docnum);
+    }
+
+    protected String internalNum2OID(String docnum)
+    {
+	return this.gs_doc_db.internalNum2OID(docnum);
+    }
+
+}
+
+
Index: main/trunk/greenstone3/src/java/org/greenstone/gsdl3/service/AbstractSearch.java
===================================================================
--- main/trunk/greenstone3/src/java/org/greenstone/gsdl3/service/AbstractSearch.java	(revision 24393)
+++ main/trunk/greenstone3/src/java/org/greenstone/gsdl3/service/AbstractSearch.java	(revision 24394)
@@ -22,4 +22,6 @@
 import org.greenstone.gsdl3.util.GSXML;
 import org.greenstone.gsdl3.util.GSPath;
+import org.greenstone.gsdl3.util.AbstractSimpleDocument;
+import org.greenstone.gsdl3.util.SimpleDocument;
 
 // XML classes
@@ -43,10 +45,9 @@
 {
 
-   static Logger logger = Logger.getLogger(org.greenstone.gsdl3.service.AbstractSearch.class.getName());
-
-    
+    static Logger logger = Logger.getLogger(org.greenstone.gsdl3.service.AbstractSearch.class.getName());
+
     // the search service
-    protected static final String TEXT_QUERY_SERVICE = "TextQuery";
-
+    protected String QUERY_SERVICE = null; // set by subclass 
+    
     // compulsory params
     protected static final String INDEX_PARAM = "index";
@@ -54,26 +55,11 @@
 
     // optional standard params - some of these have to be implemented
-    protected static final String INDEX_SUBCOLLECTION_PARAM = "indexSubcollection";
-    protected static final String INDEX_LANGUAGE_PARAM = "indexLanguage";
     protected static final String MAXDOCS_PARAM = "maxDocs";
     protected static final String HITS_PER_PAGE_PARAM = "hitsPerPage";
     protected static final String START_PAGE_PARAM = "startPage";
 
-    protected static final String INDEX_SUBCOLLECTION_ELEM = "indexSubcollection";
-    protected static final String INDEX_LANGUAGE_ELEM = "indexLanguage";
-   
-
-    // some other common params that may be used
-    protected static final String CASE_PARAM = "case";
-    protected static final String STEM_PARAM = "stem";
-    protected static final String ACCENT_PARAM="accent";
-
-    protected static final String BOOLEAN_PARAM_ON = "1";
-    protected static final String BOOLEAN_PARAM_OFF = "0";
-    protected static final String MATCH_PARAM = "matchMode";
-    protected static final String MATCH_PARAM_ALL = "all";
-    protected static final String MATCH_PARAM_SOME = "some";
-
-    /** can more than one index be searched at the smae time? */
+    protected AbstractSimpleDocument gs_doc = null;
+
+    /** can more than one index be searched at the same time? */
     protected boolean does_multi_index_search = false;
     /** does this service support paging of results? */
@@ -90,8 +76,4 @@
     protected String default_index = "";
 
-    protected String default_index_subcollection = "";
-
-    protected String default_index_language = "";
-   
     protected String default_max_docs = "100";
     
@@ -102,7 +84,9 @@
     }
 
-    /** sets up the short service info for TextQuery. If other services 
-     * will be provided, should be added in the subclass configure
-     * also looks for search format info, and document format info
+    /** Sets up the short service info for service by QUERY_SERVICE 
+     *	  (e.g. TextQuery or AudioQuery)
+     *  If other services will be provided, should be added in the
+     *  subclass configure also looks for search format info, and
+     *  document format info
      */
     public boolean configure(Element info, Element extra_info)
@@ -116,12 +100,16 @@
 	this.config_info = info;
 
-	// set up short_service_info_ - for now just has id and type. the name (lang dependent) will be added in if the list is requested.
+	// set up short_service_info_ 
+	// => for now just has id and type. the name (lang dependent)
+	//    will be added in if the list is requested.
+
 	Element tq_service = this.doc.createElement(GSXML.SERVICE_ELEM);
 	tq_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_QUERY);
-	tq_service.setAttribute(GSXML.NAME_ATT, TEXT_QUERY_SERVICE);
+	tq_service.setAttribute(GSXML.NAME_ATT, QUERY_SERVICE);
 	this.short_service_info.appendChild(tq_service);
 
-	// add some format info to service map if there is any - look in extra info
-	// first look in buildConfig
+	// add some format info to service map if there is any 
+	// => lookin extra info first look in buildConfig
+
 	Element format = (Element)GSXML.getChildByTagName(info, GSXML.FORMAT_ELEM);
 
@@ -129,23 +117,27 @@
 	    String path = GSPath.appendLink(GSXML.SEARCH_ELEM, GSXML.FORMAT_ELEM);
 
-      //note by xiao: instead of retrieving the first 'format' element inside the 'search'
-      // element, we are trying to find the real format element which has at least one
-      // 'gsf:template' child element. (extra_info is collectionConfig.xml)
-      //format = (Element) GSXML.getNodeByPath(extra_info, path);
-      Element search_elem = (Element) GSXML.getChildByTagName(extra_info, GSXML.SEARCH_ELEM);
-      NodeList format_elems = null;
-      if (search_elem != null) {
-        format_elems = search_elem.getElementsByTagName(GSXML.FORMAT_ELEM);
-      }
-      for(int i=0; i<format_elems.getLength(); i++) {
-          format = (Element)format_elems.item(i);
-          if (format.getElementsByTagName("gsf:template").getLength() != 0) {
-            break;
-          }
-      }
+	    // Note by xiao: instead of retrieving the first 'format'
+	    //   element inside the 'search' element, we are trying to
+	    //   find the real format element which has at least one
+	    //   'gsf:template' child element. (extra_info is
+	    //   collectionConfig.xml)
+
+	    //format = (Element) GSXML.getNodeByPath(extra_info, path);
+	  
+	    Element search_elem = (Element) GSXML.getChildByTagName(extra_info, GSXML.SEARCH_ELEM);
+	    NodeList format_elems = null;
+	    if (search_elem != null) {
+		format_elems = search_elem.getElementsByTagName(GSXML.FORMAT_ELEM);
+	    }
+	    for(int i=0; i<format_elems.getLength(); i++) {
+		format = (Element)format_elems.item(i);
+		if (format.getElementsByTagName("gsf:template").getLength() != 0) {
+		    break;
+		}
+	    }
 	}//end of if(format==null)
 	//
 	if (format != null) {
-	    this.format_info_map.put(TEXT_QUERY_SERVICE, this.doc.importNode(format, true));
+	    this.format_info_map.put(QUERY_SERVICE, this.doc.importNode(format, true));
 	}
 	
@@ -164,12 +156,15 @@
 	}
 
+	// Base line for document (might be overriden by sub-classes)
+	gs_doc = new SimpleDocument(this.doc,this.default_document_type);
+
 	return true;
     }
     
-    /** returns the description of the TextQuery service. If a subclass 
-     * provides other services they need to provides their own descriptions */
+    /** returns a basic description for QUERY_SERVICE. If a subclass 
+     * provides other services they need to provide their own descriptions */
     protected Element getServiceDescription(String service, String lang, String subset) 
     {
-	if (!service.equals(TEXT_QUERY_SERVICE)) {
+	if (!service.equals(QUERY_SERVICE)) {
 	    return null;
 	}
@@ -177,9 +172,9 @@
 	Element tq_service = this.doc.createElement(GSXML.SERVICE_ELEM);
 	tq_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_QUERY);
-	tq_service.setAttribute(GSXML.NAME_ATT, TEXT_QUERY_SERVICE);
+	tq_service.setAttribute(GSXML.NAME_ATT, QUERY_SERVICE);
 	if (subset==null || subset.equals(GSXML.DISPLAY_TEXT_ELEM+GSXML.LIST_MODIFIER)) {
-	    tq_service.appendChild(GSXML.createDisplayTextElement(this.doc, GSXML.DISPLAY_TEXT_NAME, getServiceName(TEXT_QUERY_SERVICE, lang) ));
-	    tq_service.appendChild(GSXML.createDisplayTextElement(this.doc, GSXML.DISPLAY_TEXT_SUBMIT, getServiceSubmit(TEXT_QUERY_SERVICE, lang) ));
-	    tq_service.appendChild(GSXML.createDisplayTextElement(this.doc, GSXML.DISPLAY_TEXT_DESCRIPTION, getServiceDescription(TEXT_QUERY_SERVICE, lang)));
+	    tq_service.appendChild(GSXML.createDisplayTextElement(this.doc, GSXML.DISPLAY_TEXT_NAME, getServiceName(QUERY_SERVICE, lang) ));
+	    tq_service.appendChild(GSXML.createDisplayTextElement(this.doc, GSXML.DISPLAY_TEXT_SUBMIT, getServiceSubmit(QUERY_SERVICE, lang) ));
+	    tq_service.appendChild(GSXML.createDisplayTextElement(this.doc, GSXML.DISPLAY_TEXT_DESCRIPTION, getServiceDescription(QUERY_SERVICE, lang)));
 	}
 	if (subset==null || subset.equals(GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER)) {
@@ -219,10 +214,4 @@
 	    createParameter(INDEX_PARAM, param_list, lang);
 	}
-	if (!default_index_subcollection.equals("")){
-	    createParameter(INDEX_SUBCOLLECTION_PARAM,param_list, lang);
-	}
-	if (!default_index_language.equals("")){
-	    createParameter(INDEX_LANGUAGE_PARAM,param_list, lang); 
-	}
 	if (does_chunking) {
 	    createParameter(MAXDOCS_PARAM, param_list, lang);
@@ -243,18 +232,30 @@
 	// default behaviour, do nothing
     }
-
-    protected void createParameter(String name, Element param_list, String lang) {
-      createParameter(name, param_list, lang, null);
-    }
-    /** default implementations for the standard parameters plus some 
-     * other common ones 
-     * index, maxDocs, hitsPerPage, startPage, query, case, stem, 
+    
+    protected void createParameter(String name, Element param_list, String lang) 
+    {
+	createParameter(name, param_list, lang, null);
+    }
+
+     protected void createParameter(String name, Element param_list, String lang, String default_value) 
+    {
+	// at this level, not interested in boolean return type
+	createParameterChain(name,param_list,lang,default_value);
+    }
+
+
+    /** default implementations for the standard parameters plus some
+     * other common ones index, maxDocs, hitsPerPage, startPage
     */
-     protected void createParameter(String name, Element param_list, String lang, String default_value) {
+
+     protected boolean createParameterChain(String name, Element param_list, String lang, String default_value) 
+    {
 	Element param = null;
 	String param_default = default_value;
+
 	if (name.equals(QUERY_PARAM)) {
 	    param = GSXML.createParameterDescription(this.doc, QUERY_PARAM, getTextString("param."+QUERY_PARAM, lang), GSXML.PARAM_TYPE_STRING, param_default, null, null);
 	    param_list.appendChild(param);
+	    return true;
 	} else if (name.equals(INDEX_PARAM)) {
 
@@ -272,100 +273,57 @@
 	    param = GSXML.createParameterDescription2(this.doc, INDEX_PARAM, getTextString("param."+INDEX_PARAM, lang), param_type, param_default, index_ids, index_names);
 	    param_list.appendChild(param);
-	}
-        else if (name.equals(INDEX_SUBCOLLECTION_PARAM)){
-	    Element index_sub_list = (Element)GSXML.getChildByTagName(this.config_info, INDEX_SUBCOLLECTION_ELEM+GSXML.LIST_MODIFIER);
-	     if (index_sub_list == null) return;
-	     ArrayList index_sub_ids = new ArrayList();
-	     ArrayList index_sub_names = new ArrayList();
-	    getIndexSubcollectionData(index_sub_ids, index_sub_names, lang);
-	    String param_type = GSXML.PARAM_TYPE_ENUM_SINGLE;
-	    if (does_multi_index_search) {
-		param_type = GSXML.PARAM_TYPE_ENUM_MULTI;
-	    }
+	    return true;
+	}
+        else if (name.equals(MAXDOCS_PARAM)) {
 	    if (param_default == null) {
-	      param_default = this.default_index_subcollection;
-	    }
-	    param = GSXML.createParameterDescription2(this.doc, INDEX_SUBCOLLECTION_PARAM, getTextString("param."+INDEX_SUBCOLLECTION_PARAM, lang), param_type, param_default, index_sub_ids, index_sub_names);
-	    param_list.appendChild(param);
-	}
-	else if(name.equals(INDEX_LANGUAGE_PARAM)){
-	    Element index_lang_list = (Element)GSXML.getChildByTagName(this.config_info, INDEX_LANGUAGE_ELEM+GSXML.LIST_MODIFIER);
-            if (index_lang_list == null) return; 
-	    ArrayList index_lang_ids = new ArrayList();
-	    ArrayList index_lang_names = new ArrayList();
-	    getIndexLanguageData(index_lang_ids, index_lang_names, lang);
-	    String param_type = GSXML.PARAM_TYPE_ENUM_SINGLE;
-	    if (does_multi_index_search) {
-		param_type = GSXML.PARAM_TYPE_ENUM_MULTI;
-	    }
+		param_default = this.default_max_docs;
+	    }
+	  
+	    param = GSXML.createParameterDescription(this.doc, name, getTextString("param."+name, lang), GSXML.PARAM_TYPE_INTEGER, param_default, null, null);
+	    param_list.appendChild(param);
+	    return true;
+	}
+	else if(name.equals(HITS_PER_PAGE_PARAM)){
 	    if (param_default == null) {
-	      param_default = this.default_index_language;
-	    }
-	    param = GSXML.createParameterDescription2(this.doc, INDEX_LANGUAGE_PARAM, getTextString("param."+INDEX_LANGUAGE_PARAM, lang), param_type, param_default, index_lang_ids, index_lang_names);
-	    param_list.appendChild(param);
-	}
-        else if (name.equals(MAXDOCS_PARAM)) {
-	  if (param_default == null) {
-	    param_default = this.default_max_docs;
-	  }
-
+	    param_default = this.default_hits_per_page;
+	    }
+	  
 	    param = GSXML.createParameterDescription(this.doc, name, getTextString("param."+name, lang), GSXML.PARAM_TYPE_INTEGER, param_default, null, null);
 	    param_list.appendChild(param);
-	}
-	else if(name.equals(HITS_PER_PAGE_PARAM)){
-	  if (param_default == null) {
-	    param_default = this.default_hits_per_page;
-	  }
-	  
-	     param = GSXML.createParameterDescription(this.doc, name, getTextString("param."+name, lang), GSXML.PARAM_TYPE_INTEGER, param_default, null, null);
-	    param_list.appendChild(param);
-	}
-	else if (name.equals(CASE_PARAM) || name.equals(STEM_PARAM) || name.equals(ACCENT_PARAM)) {
-	  if (param_default == null) {
-	    param_default = BOOLEAN_PARAM_OFF;
-	  }
-	    String[] bool_ops = {"0", "1"};
-	    String[] bool_texts = {getTextString("param.boolean.off", lang),getTextString("param.boolean.on", lang)}; 
-	    param = GSXML.createParameterDescription(this.doc, name, getTextString("param."+name, lang), GSXML.PARAM_TYPE_BOOLEAN, param_default, bool_ops, bool_texts);
-	    param_list.appendChild(param);
-	} else if (name.equals(MATCH_PARAM)) {
-	  if (param_default == null) {
-	    param_default = MATCH_PARAM_SOME;
-	  }
-	  
-	    String[] vals = {MATCH_PARAM_SOME, MATCH_PARAM_ALL };
-	    String[] val_texts = {getTextString("param."+MATCH_PARAM+"."+MATCH_PARAM_SOME, lang), getTextString("param."+MATCH_PARAM+"."+MATCH_PARAM_ALL, lang)}; 
-	    param = GSXML.createParameterDescription(this.doc, MATCH_PARAM, getTextString("param."+MATCH_PARAM, lang), GSXML.PARAM_TYPE_ENUM_SINGLE, param_default, vals, val_texts);
-	    param_list.appendChild(param);
+	    return true;
 	} else if (name.equals(START_PAGE_PARAM)) {
-	  if (param_default == null) {
-	    param_default = "1";
-	  }
-	  
+	    if (param_default == null) {
+		param_default = "1";
+	    }
+	    
 	    // start page - set to 1 for the search page
 	    param = GSXML.createParameterDescription(this.doc, START_PAGE_PARAM, "", GSXML.PARAM_TYPE_INVISIBLE, param_default, null, null);
 	    param_list.appendChild(param);
-	}
-	    
-	    
-    }
+	    return true;
+	}
+
+	// Get to there then none of the above params matched
+	// => return false so the chain can continue
+	return false;
+    }
+
+
     /** create an element to go into the search results list. A node element
      * has the form
      * <docNode nodeId='xxx' nodeType='leaf' docType='hierarchy' rank='0.23'/>
      */
-    protected Element createDocNode(String node_id, String rank) {
-	Element node = this.doc.createElement(GSXML.DOC_NODE_ELEM);
-	node.setAttribute(GSXML.NODE_ID_ATT, node_id);
-	node.setAttribute(GSXML.NODE_RANK_ATT, rank);
-	String doc_type = null;
-	if (default_document_type != null) {
-	    doc_type = default_document_type;
-	} else {
-	    doc_type = getDocType(node_id);
-	}
-	node.setAttribute(GSXML.DOC_TYPE_ATT, doc_type);
-	String node_type = getNodeType(node_id, doc_type);	
-	node.setAttribute(GSXML.NODE_TYPE_ATT, node_type);
-	return node;
+    protected Element createDocNode(String node_id, String rank) 
+    {
+	return this.gs_doc.createDocNode(node_id,rank);
+    }
+
+    /** returns the document type of the doc that the specified node 
+	belongs to. should be one of 
+	GSXML.DOC_TYPE_SIMPLE, 
+	GSXML.DOC_TYPE_PAGED, 
+	GSXML.DOC_TYPE_HIERARCHY
+    */
+    protected String getDocType(String node_id){
+	return this.gs_doc.getDocType(node_id);
     }
 
@@ -376,53 +334,22 @@
 	GSXML.NODE_TYPE_ROOT
     */
-    protected String getNodeType(String node_id, String doc_type) {
-	if (doc_type.equals(GSXML.DOC_TYPE_SIMPLE)) {
-	    return GSXML.NODE_TYPE_LEAF;
-	}
-
-	if (!hasParent(node_id)) {
-	    return GSXML.NODE_TYPE_ROOT;
-	}
-	if (doc_type.equals(GSXML.DOC_TYPE_PAGED)) {
-	     return GSXML.NODE_TYPE_LEAF;
-	}
-	if (!hasChildren(node_id)) {
-	    return GSXML.NODE_TYPE_LEAF;
-	}
-	return GSXML.NODE_TYPE_INTERNAL;	
-	
-    }
-
-
-    /** returns the document type of the doc that the specified node 
-	belongs to. should be one of 
-	GSXML.DOC_TYPE_SIMPLE, 
-	GSXML.DOC_TYPE_PAGED, 
-	GSXML.DOC_TYPE_HIERARCHY
-	default implementation returns GSXML.DOC_TYPE_SIMPLE, over ride 
-	if documents can be hierarchical
-    */
-    protected String getDocType(String node_id) {
-	return GSXML.DOC_TYPE_SIMPLE;
-    }
-    
-    /** returns true if the node has child nodes 
-     * default implementation returns false, over ride if documents can be 
-     * hierarchical 
-     */
-    protected boolean hasChildren(String node_id) {
-	return false;
-    }
-    /** returns true if the node has a parent 
-     * default implementation returns false, over ride if documents can be 
-     * hierarchical*/
-    protected boolean hasParent(String node_id) {
-	return false;
-    }
-
-    /** do the actual query 
-     * must be implemented by subclass */
-    abstract protected Element processTextQuery(Element request); 
-	
+    protected String getNodeType(String node_id, String doc_type) 
+    {
+	return this.gs_doc.getNodeType(node_id,doc_type);
+    }
+    
+    /** returns true if the node has child nodes */
+    protected boolean hasChildren(String node_id)
+    {
+	return this.gs_doc.hasChildren(node_id);
+    }
+    
+    /** returns true if the node has a parent */
+    protected boolean hasParent(String node_id)
+    {
+	return this.gs_doc.hasParent(node_id);
+    }
+
+
     /** get the details about the indexes available
      * must be implemented by subclass
@@ -430,15 +357,4 @@
     abstract protected void getIndexData(ArrayList index_ids, ArrayList index_names, String lang);
 
-    /** get the details about the indexexSubcollections available
-     * might be implemented by subclass
-     */
-    protected void getIndexSubcollectionData(ArrayList index_ids, ArrayList index_names, String lang){}
-    
-    /** get the details about the indexes available
-     * might be implemented by subclass
-     */
-    protected void getIndexLanguageData(ArrayList index_ids, ArrayList index_names, String lang){}
-  
-
 }
 
Index: main/trunk/greenstone3/src/java/org/greenstone/gsdl3/service/AbstractTextSearch.java
===================================================================
--- main/trunk/greenstone3/src/java/org/greenstone/gsdl3/service/AbstractTextSearch.java	(revision 24394)
+++ main/trunk/greenstone3/src/java/org/greenstone/gsdl3/service/AbstractTextSearch.java	(revision 24394)
@@ -0,0 +1,161 @@
+/*
+ *    AbstractTextSearch.java
+ *    Copyright (C) 2005 New Zealand Digital Library, http://www.nzdl.org
+ *
+ *    This program is 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+package org.greenstone.gsdl3.service;
+
+// Greenstone classes
+import org.greenstone.gsdl3.util.GSXML;
+import org.greenstone.gsdl3.util.GSPath;
+
+// XML classes
+import org.w3c.dom.Document;
+import org.w3c.dom.Element; 
+import org.w3c.dom.NodeList;
+
+// java classes
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import org.apache.log4j.*;
+
+/** Partially implements a generic search service
+ *
+ * @author <a href="mailto:kjdon@cs.waikato.ac.nz">Katherine Don</a>
+ */
+
+public abstract class AbstractTextSearch
+    extends AbstractSearch 
+{
+
+   static Logger logger = Logger.getLogger(org.greenstone.gsdl3.service.AbstractTextSearch.class.getName());
+
+    
+    // optional standard params - some of these have to be implemented
+    protected static final String INDEX_SUBCOLLECTION_PARAM = "indexSubcollection";
+    protected static final String INDEX_LANGUAGE_PARAM = "indexLanguage";
+
+    protected static final String INDEX_SUBCOLLECTION_ELEM = "indexSubcollection";
+    protected static final String INDEX_LANGUAGE_ELEM = "indexLanguage";
+   
+
+    // some other common params that may be used
+    protected static final String CASE_PARAM = "case";
+    protected static final String STEM_PARAM = "stem";
+    protected static final String ACCENT_PARAM="accent";
+
+    protected static final String BOOLEAN_PARAM_ON = "1";
+    protected static final String BOOLEAN_PARAM_OFF = "0";
+    protected static final String MATCH_PARAM = "matchMode";
+    protected static final String MATCH_PARAM_ALL = "all";
+    protected static final String MATCH_PARAM_SOME = "some";
+
+    protected String default_index_subcollection = "";
+
+    protected String default_index_language = "";
+   
+    public AbstractTextSearch()
+    {
+	// the search service
+	QUERY_SERVICE = "TextQuery";
+    }
+
+
+    /** adds the standard query params into the service description */
+    protected void addStandardQueryParams(Element param_list, String lang) 
+    {
+	if (!default_index_subcollection.equals("")){
+	    createParameter(INDEX_SUBCOLLECTION_PARAM,param_list, lang);
+	}
+	if (!default_index_language.equals("")){
+	    createParameter(INDEX_LANGUAGE_PARAM,param_list, lang); 
+	}
+
+	super.addStandardQueryParams(param_list,lang);
+    }
+
+    /** Top up createParameterChain with TextQuery specific params:
+     *    case, stem ...
+     */
+     protected boolean createParameterChain(String name, Element param_list, String lang, String default_value) 
+    {
+	Element param = null;
+	String param_default = default_value;
+
+	if (super.createParameterChain(name,param_list,lang,default_value)) {
+	    // found a match, so can stop here
+	    return true;
+	}
+	// otherwise look to see if it is a text specific parameter
+	else if (name.equals(INDEX_SUBCOLLECTION_PARAM)){
+	    Element index_sub_list = (Element)GSXML.getChildByTagName(this.config_info, INDEX_SUBCOLLECTION_ELEM+GSXML.LIST_MODIFIER);
+	    if (index_sub_list == null) return true; // processed, just not a very interesting result
+	    ArrayList index_sub_ids = new ArrayList();
+	    ArrayList index_sub_names = new ArrayList();
+	    getIndexSubcollectionData(index_sub_ids, index_sub_names, lang);
+	    String param_type = GSXML.PARAM_TYPE_ENUM_SINGLE;
+	    if (does_multi_index_search) {
+		param_type = GSXML.PARAM_TYPE_ENUM_MULTI;
+	    }
+	    if (param_default == null) {
+	      param_default = this.default_index_subcollection;
+	    }
+	    param = GSXML.createParameterDescription2(this.doc, INDEX_SUBCOLLECTION_PARAM, getTextString("param."+INDEX_SUBCOLLECTION_PARAM, lang), param_type, param_default, index_sub_ids, index_sub_names);
+	    param_list.appendChild(param);
+	    return true;
+	}
+	else if(name.equals(INDEX_LANGUAGE_PARAM)){
+	    Element index_lang_list = (Element)GSXML.getChildByTagName(this.config_info, INDEX_LANGUAGE_ELEM+GSXML.LIST_MODIFIER);
+            if (index_lang_list == null) return true; // processed, just not a very interesting result
+	    ArrayList index_lang_ids = new ArrayList();
+	    ArrayList index_lang_names = new ArrayList();
+	    getIndexLanguageData(index_lang_ids, index_lang_names, lang);
+	    String param_type = GSXML.PARAM_TYPE_ENUM_SINGLE;
+	    if (does_multi_index_search) {
+		param_type = GSXML.PARAM_TYPE_ENUM_MULTI;
+	    }
+	    if (param_default == null) {
+	      param_default = this.default_index_language;
+	    }
+	    param = GSXML.createParameterDescription2(this.doc, INDEX_LANGUAGE_PARAM, getTextString("param."+INDEX_LANGUAGE_PARAM, lang), param_type, param_default, index_lang_ids, index_lang_names);
+	    param_list.appendChild(param);
+	    return true;
+	}
+
+	// Get to there then none of the above params matched
+	// => return false so the chain can continue
+	return false;
+	    
+    }
+
+    /** do the actual query 
+     * must be implemented by subclass */
+    abstract protected Element processTextQuery(Element request); 
+	
+    /** get the details about the indexexSubcollections available
+     * might be implemented by subclass
+     */
+    protected void getIndexSubcollectionData(ArrayList index_ids, ArrayList index_names, String lang){}
+    
+    /** get the details about the indexes available
+     * might be implemented by subclass
+     */
+    protected void getIndexLanguageData(ArrayList index_ids, ArrayList index_names, String lang){}
+  
+
+}
+
Index: main/trunk/greenstone3/src/java/org/greenstone/gsdl3/service/CrossCollectionSearch.java
===================================================================
--- main/trunk/greenstone3/src/java/org/greenstone/gsdl3/service/CrossCollectionSearch.java	(revision 24393)
+++ main/trunk/greenstone3/src/java/org/greenstone/gsdl3/service/CrossCollectionSearch.java	(revision 24394)
@@ -270,5 +270,5 @@
 	    Element service_list = (Element)GSXML.getChildByTagName(coll, GSXML.SERVICE_ELEM+GSXML.LIST_MODIFIER);
 	    if (service_list==null) continue;
-	    Element query_service = GSXML.getNamedElement(service_list, GSXML.SERVICE_ELEM, GSXML.NAME_ATT, TEXT_QUERY_SERVICE); // should be AbstractSearch.TEXT_QUERY_SERVICE
+	    Element query_service = GSXML.getNamedElement(service_list, GSXML.SERVICE_ELEM, GSXML.NAME_ATT, TEXT_QUERY_SERVICE); // should be AbstractTextSearch.TEXT_QUERY_SERVICE
 	    if (query_service == null) continue;
 	    // use the name of the response in case we are talking to a remote collection, not the name of the collection.
Index: main/trunk/greenstone3/src/java/org/greenstone/gsdl3/service/GS2MGSearch.java
===================================================================
--- main/trunk/greenstone3/src/java/org/greenstone/gsdl3/service/GS2MGSearch.java	(revision 24393)
+++ main/trunk/greenstone3/src/java/org/greenstone/gsdl3/service/GS2MGSearch.java	(revision 24394)
@@ -46,5 +46,5 @@
 
 public class GS2MGSearch
-extends AbstractGS2Search {
+extends AbstractGS2TextSearch {
     
     protected static MGSearchWrapper mg_src = null;
@@ -81,5 +81,5 @@
         // Create a new (empty) result message ('doc' is in ServiceRack.java)
         Element result = this.doc.createElement (GSXML.RESPONSE_ELEM);
-        result.setAttribute (GSXML.FROM_ATT, TEXT_QUERY_SERVICE);
+        result.setAttribute (GSXML.FROM_ATT, QUERY_SERVICE);
         result.setAttribute (GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_PROCESS);
         
Index: main/trunk/greenstone3/src/java/org/greenstone/gsdl3/service/GoogleNgramMGPPSearch.java
===================================================================
--- main/trunk/greenstone3/src/java/org/greenstone/gsdl3/service/GoogleNgramMGPPSearch.java	(revision 24393)
+++ main/trunk/greenstone3/src/java/org/greenstone/gsdl3/service/GoogleNgramMGPPSearch.java	(revision 24394)
@@ -69,5 +69,5 @@
 	      String num = Long.toString((((MGPPDocInfo) docs.elementAt(d)).num_));
 	      String doc_id = internalNum2OID(num);
-	      DBInfo dbInfo = this.coll_db.getInfo(doc_id);
+	      DBInfo dbInfo = this.gs_doc_db.getInfo(doc_id);
 	      String fre = (String)dbInfo.getInfo("Frequency");
 	      String tense = (String)dbInfo.getInfo("Tense");
Index: main/trunk/greenstone3/src/java/org/greenstone/gsdl3/service/IViaSearch.java
===================================================================
--- main/trunk/greenstone3/src/java/org/greenstone/gsdl3/service/IViaSearch.java	(revision 24393)
+++ main/trunk/greenstone3/src/java/org/greenstone/gsdl3/service/IViaSearch.java	(revision 24394)
@@ -26,5 +26,5 @@
 
 public class IViaSearch
-    extends AbstractSearch {
+    extends AbstractTextSearch {
     
 
@@ -77,5 +77,5 @@
 	// Create a new (empty) result message
 	Element result = this.doc.createElement(GSXML.RESPONSE_ELEM);
-	result.setAttribute(GSXML.FROM_ATT, TEXT_QUERY_SERVICE);
+	result.setAttribute(GSXML.FROM_ATT, QUERY_SERVICE);
 	result.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_PROCESS);
 	Element doc_node_list = this.doc.createElement(GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
Index: main/trunk/greenstone3/src/java/org/greenstone/gsdl3/service/LuceneSearch.java
===================================================================
--- main/trunk/greenstone3/src/java/org/greenstone/gsdl3/service/LuceneSearch.java	(revision 24393)
+++ main/trunk/greenstone3/src/java/org/greenstone/gsdl3/service/LuceneSearch.java	(revision 24394)
@@ -32,5 +32,5 @@
 
 public class LuceneSearch 
-    extends AbstractSearch {
+    extends AbstractTextSearch {
 
      static Logger logger = Logger.getLogger(org.greenstone.gsdl3.service.LuceneSearch.class.getName());
@@ -74,5 +74,5 @@
 	// Create a new (empty) result message
 	Element result = this.doc.createElement(GSXML.RESPONSE_ELEM);
-	result.setAttribute(GSXML.FROM_ATT, TEXT_QUERY_SERVICE);
+	result.setAttribute(GSXML.FROM_ATT, QUERY_SERVICE);
 	result.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_PROCESS);
 	Element doc_node_list = this.doc.createElement(GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
Index: main/trunk/greenstone3/src/java/org/greenstone/gsdl3/service/MapSearch.java
===================================================================
--- main/trunk/greenstone3/src/java/org/greenstone/gsdl3/service/MapSearch.java	(revision 24393)
+++ main/trunk/greenstone3/src/java/org/greenstone/gsdl3/service/MapSearch.java	(revision 24394)
@@ -50,5 +50,5 @@
  */
 public class MapSearch 
-    extends AbstractSearch {
+    extends AbstractTextSearch {
 
 
@@ -163,5 +163,5 @@
 	// Create a new (empty) result message
 	Element result = doc.createElement(GSXML.RESPONSE_ELEM);
-	result.setAttribute(GSXML.FROM_ATT, TEXT_QUERY_SERVICE);
+	result.setAttribute(GSXML.FROM_ATT, QUERY_SERVICE);
 	result.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_PROCESS);
 
