Index: trunk/gsdl3/src/java/org/greenstone/gsdl3/service/PhindPhraseBrowse.java
===================================================================
--- trunk/gsdl3/src/java/org/greenstone/gsdl3/service/PhindPhraseBrowse.java	(revision 3651)
+++ trunk/gsdl3/src/java/org/greenstone/gsdl3/service/PhindPhraseBrowse.java	(revision 3651)
@@ -0,0 +1,455 @@
+/*
+ *    PhindServices.java
+ *    Copyright (C) 2002 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;
+
+import org.greenstone.gsdl3.util.*;
+
+import org.greenstone.mgpp.*;
+import org.w3c.dom.Document; 
+import org.w3c.dom.Node; 
+import org.w3c.dom.Element; 
+import org.w3c.dom.Text; 
+
+import java.util.Vector;
+import java.util.HashMap;
+/** 
+ * PhindServices - the phind phrase browsing service
+ * 
+ * @author <a href="mailto:kjdon@cs.waikato.ac.nz">Katherine Don</a>
+ * @version $Revision$
+ */
+public class PhindPhraseBrowse
+    extends ServiceRack {
+    
+    // the services on offer
+    private static final String PHIND_SERVICE = "PhindApplet";
+
+    private MGPPWrapper mgpp_src_=null;
+    private String basepath_ = null;
+    public PhindPhraseBrowse() {
+	mgpp_src_ = new MGPPWrapper();
+	// set up the default params
+	mgpp_src_.setQueryLevel("Document");
+	mgpp_src_.setReturnLevel("Document");
+	mgpp_src_.setMaxDocs(5);
+	mgpp_src_.setStem(false);
+	mgpp_src_.setCase(true);
+    }
+    /** configure the service module
+     *
+     * @param info a DOM Element containing any config info for the service
+     * @return true if configured
+     */
+    public boolean configure(Element info) {
+
+	System.out.println("configuring PhindPhraseBrowse");
+
+	// set up short_service_info_ - for now just has name and type
+	Element e = doc_.createElement(GSXML.SERVICE_ELEM);
+	e.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_QUERY);
+	e.setAttribute(GSXML.NAME_ATT, PHIND_SERVICE);
+	short_service_info_.appendChild(e);
+
+	// set up service_info_map_ - we only have one element, and it has
+	// no extra info yet - we are not processing the config info
+	Element f = doc_.createElement(GSXML.SERVICE_ELEM);
+	f.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_QUERY);
+	f.setAttribute(GSXML.NAME_ATT, PHIND_SERVICE);
+
+	// add in the applet info for the phind applet
+	// need to make this dynamic - library names etc
+	// change the applet params - have a single param with the library name
+	// this is left blank at this end, and must be filled in by applet action - if the library name is not needed, this param is left out
+	// phindcgi param now is not complete - library must be prepended to it.
+	String app_info = "<"+GSXML.APPLET_ELEM+" CODEBASE='lib/java' CODE='org.greenstone.applet.phind.Phind.class' ARCHIVE='phind.jar, xercesImpl.jar, gsdl3.jar, jaxp.jar, xml-apis.jar' WIDTH='500' HEIGHT='400'><PARAM NAME='library' VALUE=''/> <PARAM NAME='phindcgi' VALUE='?";
+	app_info += GSCGI.ACTION_ARG +"=a&amp;"+GSCGI.SUBACTION_ARG +"=r&amp;"+GSCGI.SERVICE_ARG+"=Phind'/>";
+	app_info +="<PARAM NAME='collection'   VALUE='";
+	app_info += cluster_name_;
+	app_info += "'/> <PARAM NAME='classifier' VALUE='1'/>  <PARAM NAME='orientation'  VALUE='vertical'/> <PARAM NAME='depth' VALUE='2'/> <PARAM NAME='resultorder' VALUE='L,l,E,e,D,d'/> <PARAM NAME='backdrop' VALUE='interfaces/default/images/phindbg1.jpg'/><PARAM NAME='fontsize' VALUE='10'/> <PARAM NAME='blocksize'    VALUE='10'/>The Phind java applet.</"+GSXML.APPLET_ELEM+">";
+	
+	Document dom = converter_.getDOM(app_info);
+	Element app_elem = dom.getDocumentElement();
+	f.appendChild(doc_.importNode(app_elem, true));
+	
+	service_info_map_.put(PHIND_SERVICE, f);
+	
+	return true;
+    }
+
+    /** creates a display element containing all the text strings needed to display the service page, in the language specified */
+    protected Element createServiceDisplay(String service, String lang) {
+	Element display = doc_.createElement(GSXML.DISPLAY_ELEM);
+	display.appendChild(GSXML.createTextElement(doc_, GSXML.DISPLAY_NAME_ELEM,  getTextString(service+".name", lang)));
+	display.appendChild(GSXML.createTextElement(doc_,  GSXML.DISPLAY_SUBMIT_ELEM, getTextString(service+".submit", lang)));
+
+	Element param;
+
+	return display;
+	
+    }
+
+    protected Element processPhindApplet(Element request) {
+	
+	Element param_elem = (Element)GSXML.getChildByTagName(request, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
+	HashMap params = GSXML.extractParams(param_elem);
+	
+	long first_e = Long.parseLong((String)params.get("pfe"));
+	long last_e = Long.parseLong((String)params.get("ple"));
+	long first_l = Long.parseLong((String)params.get("pfl"));
+	long last_l = Long.parseLong((String)params.get("pll"));
+	long first_d = Long.parseLong((String)params.get("pfd"));
+	long last_d = Long.parseLong((String)params.get("pld"));
+	
+	long phrase;
+	String phrase_str = (String)params.get("ppnum");
+	if (phrase_str == null || phrase_str.equals("")) {
+	    phrase=0;
+	} else {
+	    phrase = Long.parseLong(phrase_str);
+	}
+	String word = (String)params.get("pptext");
+	String phind_index = (String)params.get("pc");
+	// the location of the mgpp database files
+	basepath_ = GSFile.phindBaseDir(site_home_, cluster_name_, phind_index);
+
+	// the result element
+	Element result = doc_.createElement(GSXML.RESPONSE_ELEM);
+	String from = GSPath.appendLink(cluster_name_, "PhindApplet");
+	result.setAttribute(GSXML.FROM_ATT, from);
+	result.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_QUERY);
+
+	// applet result info must be in appletInfo element
+	Element applet_data = doc_.createElement(GSXML.APPLET_DATA_ELEM);
+	result.appendChild(applet_data);
+	Element phind_data = doc_.createElement("phindData");
+	applet_data.appendChild(phind_data);
+
+
+	// if we dont know the phrase number, look it up
+	if (phrase == 0) {
+	    if (word==null || word.equals("")) {
+		Element error = phindError("no word or phrase");
+		phind_data.appendChild(error);
+		return result;
+	    }
+	    phrase = findPhraseNumberFromWord( word);
+	    System.out.println("phind, term number for "+word+" is "+phrase);
+	}
+	if (phrase==0) {
+	    // the word is not in the collection
+	    // return a phind error string
+	    Element error = phindError("the term "+word+" is not in the collection");
+	    phind_data.appendChild(error);
+	    return result;
+	}
+	
+	// get the phrase data into the phind_data node
+	getPhraseData(phind_data, phrase, first_l, last_l,
+		      first_e, last_e,  first_d, last_d);
+	return result;
+	
+	
+    }// processPhindApplet
+    
+    protected long findPhraseNumberFromWord(String word) {
+
+	// set the mgpp index data - we are looking up pword
+	mgpp_src_.loadIndexData(basepath_, "pword");
+
+	mgpp_src_.runQuery(word);
+
+	MGPPQueryResult res = mgpp_src_.getQueryResult();
+	Vector docs = res.getDocs();
+	if (docs.size()==0) {
+	    // phrase not found
+	    return 0;
+	}
+	MGPPDocInfo doc = (MGPPDocInfo)docs.firstElement();
+	return doc.num_;
+    }
+
+    protected boolean getPhraseData(Element phind_data,
+				    long phrase, long first_l, long last_l,
+				    long first_e, long last_e, long first_d, 
+				    long last_d) {
+
+	String record = mgpp_src_.getDocument(basepath_, "pdata", "Document",
+					      phrase);
+	if (record.equals("")) {
+	    Element error = phindError("somethings gone wrong - we haven't got a record for phrase number "+phrase);
+	    phind_data.appendChild(error);
+	    return false;
+	}
+	
+	System.out.println("record="+record);
+	// parse the record - its in gordons cryptic form
+	// ":word:tf:ef:df:el:dl:lf:ll"
+	// el: e,e,e
+	// dl: d;f,d;f,
+	// lf and ll may be null
+	// l: type,dest, dest; type,dest,dest
+
+	// ignore everything up to and including first colon (has
+	// <Document>3505: at the start)
+	record = record.substring(record.indexOf(':')+1);
+
+	// split on ':'
+	String [] fields = record.split(":");
+	String word = fields[0];
+	String tf = fields[1];
+	String ef = fields[2];
+	String df = fields[3];
+
+	
+	String expansions = fields[4];
+	String documents = fields[5];
+	String lf = "0";
+	String linklist = "";
+	if (fields.length > 7) {// have thesaurus stuff
+	    lf =fields[6];
+	    linklist = fields[7];
+	}
+	
+	// the phindData attributes and phrase
+	phind_data.setAttribute("id", Long.toString(phrase));
+	phind_data.setAttribute("df", df);
+	phind_data.setAttribute("ef", ef);
+	phind_data.setAttribute("lf", lf);
+	phind_data.setAttribute("tf", tf);
+	GSXML.createTextElement(doc_, "phrase", word);
+
+	addExpansionList(phind_data, expansions, word, ef, first_e, last_e);
+	addDocumentList(phind_data, documents, word, df, first_d, last_d);
+	if (!lf.equals("0")) {
+	    System.out.println("adding thesaurus stuff");
+	    addThesaurusList(phind_data, linklist, word, lf, first_l, last_l);
+	}
+	return true;
+    }
+
+    protected boolean addExpansionList( Element phind_data, String record, 
+				       String word,
+				       String freq,
+				       long first, long last) {
+
+	Element expansion_list = doc_.createElement("expansionList");
+	phind_data.appendChild(expansion_list);
+	expansion_list.setAttribute("length", freq);
+	expansion_list.setAttribute("start", Long.toString(first));
+	expansion_list.setAttribute("end", Long.toString(last));
+
+	// get the list of strings
+	String [] expansions = record.split(",");
+	int length = expansions.length;
+	if (length < last) last = length;
+	for (long i = first; i < last; i++) {
+	    long num  = Long.parseLong(expansions[(int)i]);
+	    Element expansion = getExpansion( num, word);
+	    expansion.setAttribute("num", Long.toString(i));
+	    expansion_list.appendChild(expansion);
+	}
+	return true;
+    }
+    
+    protected Element getExpansion(long phrase_num, 
+				   String orig_phrase) {
+	
+	// look up the phrase in the pdata thingy
+	String record = mgpp_src_.getDocument(basepath_, "pdata", "Document",
+					      phrase_num);
+
+	if (record ==null || record.equals("")) return null;
+
+	// ignore everything up to and including first colon 
+	record = record.substring(record.indexOf(':')+1);
+
+	String [] fields = record.split(":");
+	String phrase = fields[0];
+	String tf = fields[1];
+	//String ef = fields[2]; dont use this
+	String df = fields[3];
+
+	Element expansion = doc_.createElement("expansion");
+	expansion.setAttribute("tf", tf);
+	expansion.setAttribute("df", df);
+	expansion.setAttribute("id", Long.toString(phrase_num));
+
+	// get teh suffix and prefix
+	String [] ends = splitPhraseOnWord(phrase, orig_phrase);
+	if (!ends[0].equals("")) {
+	    expansion.appendChild(GSXML.createTextElement(doc_, "prefix", ends[0]));
+	}
+	if (!ends[1].equals("")) {
+	    expansion.appendChild(GSXML.createTextElement(doc_, "suffix", ends[1]));
+	}
+
+	return expansion;
+
+    }
+
+    protected boolean addDocumentList(Element phind_data, String record, 
+				      String word,
+				      String freq,
+				      long first, long last) {
+
+	Element document_list = doc_.createElement("documentList");
+	phind_data.appendChild(document_list);
+	document_list.setAttribute("length", freq);
+	document_list.setAttribute("start", Long.toString(first));
+	document_list.setAttribute("end", Long.toString(last));
+
+	// get the list of doc,freq
+	String [] doc_freqs = record.split(";");
+	int length = doc_freqs.length;
+	if (length<last) last=length;
+
+	for (long i = first; i < last; i++) {
+	    String doc_elem = doc_freqs[(int)i];
+	    int p = doc_elem.indexOf(',');
+	    long doc_num;
+	    String doc_freq;
+	    if (p == -1) { // there is no freq in the record
+		doc_num =Long.parseLong(doc_elem);
+		doc_freq = "1";
+	    } else {
+		doc_num = Long.parseLong(doc_elem.substring(0,p));
+		doc_freq = doc_elem.substring(p+1);
+	    }
+	    Element document = getDocument( doc_num);
+	    document.setAttribute("freq", doc_freq);
+	    document.setAttribute("num", Long.toString(i));
+	    document_list.appendChild(document);
+	}
+
+	
+	return true;
+    }
+
+
+    protected Element getDocument(long doc_num) {
+	
+	// look up the phrase in the docs thingy
+	String record = mgpp_src_.getDocument(basepath_, "docs", "Document",
+					      doc_num);
+	
+	if (record ==null || record.equals("")) return null;
+	System.out.println("doc record:"+record);
+	
+	// ignore everything up to and including first \t
+	record = record.substring(record.indexOf('\t')+1);
+
+	String [] fields = record.split("\t");
+	String hash = fields[0];
+	String title = fields[1];
+
+	Element d = doc_.createElement("document");
+	d.setAttribute("hash", hash);
+	d.appendChild(GSXML.createTextElement(doc_, "title", title));
+	
+	return d;
+
+    }
+    protected boolean addThesaurusList(Element phind_data, String record,
+				       String word,
+				       String freq,
+				       long first, long last) {
+
+
+	Element thesaurus_list = doc_.createElement("thesaurusList");
+	phind_data.appendChild(thesaurus_list);
+	thesaurus_list.setAttribute("length", freq);
+	thesaurus_list.setAttribute("start", Long.toString(first));
+	thesaurus_list.setAttribute("end", Long.toString(last));
+	
+	System.out.println("record for thesaurus="+record);
+
+	// get the list of type,dest,dest
+	String [] links = record.split(";");
+	int length = links.length;
+	long index = 0;
+	for (int i = 0; i < length; i++) { // go through the entries
+	    String link_info = links[(int)i];
+	    String [] items = link_info.split(",");
+	    // the first entry is teh type
+	    String type = items[0];
+	    for (int j = 1; j<items.length; j++, index++) {
+		if (index >= first && index < last) { // only output the ones we want
+		    long phrase = Long.parseLong(items[j]);
+		    Element t = getThesaurus(phrase);
+		    t.setAttribute("type", type);
+		    thesaurus_list.appendChild(t);
+		}
+	    }
+	}
+
+	return true;
+    }
+
+    protected Element getThesaurus(long phrase_num) {
+
+	// look up the phrase in the pdata thingy
+	String record = mgpp_src_.getDocument(basepath_, "pdata", "Document",
+					      phrase_num);
+
+	if (record ==null || record.equals("")) return null;
+
+	// ignore everything up to and including first colon 
+	record = record.substring(record.indexOf(':')+1);
+
+	String [] fields = record.split(":");
+	String phrase = fields[0];
+	String tf = fields[1];
+	//String ef = fields[2]; dont use this
+	String df = fields[3];
+
+	Element thesaurus = doc_.createElement("thesaurus");
+	thesaurus.setAttribute("tf", tf);
+	thesaurus.setAttribute("df", df);
+	thesaurus.setAttribute("id", Long.toString(phrase_num));
+	thesaurus.appendChild(GSXML.createTextElement(doc_, "phrase", phrase));
+	return thesaurus;
+
+    }
+
+    /** returns an array of two elements - the prefix and the suffix*/
+    protected String [] splitPhraseOnWord(String phrase, String word) {
+	
+	if (word.equals("")) {
+	    
+	    String [] res =  {phrase, ""};
+	    return res;
+	}
+	// use 2 so that we only split on the first occurrance. trailing empty strings should be included 
+	String [] result = phrase.split(word, 2);
+	if (result.length !=2) {
+	    System.out.println("didn't get two substrings!!");
+	}
+	return result;
+	
+    }
+
+    protected Element phindError(String message) {
+	Element e = doc_.createElement("phindError");
+	Text t = doc_.createTextNode(message);
+	e.appendChild(t);
+	return e;
+    }
+    
+}
+
