Index: /trunk/protemix/etc/collect.cfg
===================================================================
--- /trunk/protemix/etc/collect.cfg	(revision 3181)
+++ /trunk/protemix/etc/collect.cfg	(revision 3182)
@@ -11,5 +11,5 @@
 
 plugin        GAPlug
-plugin        ProtemixPlug 
+plugin        ProtemixPlug
 plugin        ArcPlug
 plugin        RecPlug
Index: /trunk/protemix/macros/style.dm
===================================================================
--- /trunk/protemix/macros/style.dm	(revision 3181)
+++ /trunk/protemix/macros/style.dm	(revision 3182)
@@ -126,10 +126,11 @@
 </tr>
 </table>
-<div style="margin-left:10; margin-right:10; margin-bottom:10">
+<center>
+<table border="0" cellpadding="0" cellspacing="0" width="638"><tr><td>
 }
 
 _footer_ {
 _pagefooterextra_
-</div>
+</td></tr></table>
 </body>
 </html>
Index: /trunk/protemix/perllib/plugins/ProtemixPlug.pm
===================================================================
--- /trunk/protemix/perllib/plugins/ProtemixPlug.pm	(revision 3181)
+++ /trunk/protemix/perllib/plugins/ProtemixPlug.pm	(revision 3182)
@@ -176,3 +176,16 @@
 }
 
+# don't want to convert character entities for now as mgpp appears to be broken
+sub read_file {
+    my ($self, $filename, $encoding, $language, $textref) = @_;
+
+    &BasPlug::read_file($self, $filename, $encoding, $language, $textref);
+
+    # Convert entities to their UTF8 equivalents
+#    $$textref =~ s/&(lt|gt|amp|quot);/&z$1;/go;
+#    $$textref =~ s/&([^;]+);/&ghtml::getcharequiv($1,1)/gseo;
+#    $$textref =~ s/&z(lt|gt|amp|quot);/&$1;/go;
+}
+
+
 1;
Index: /trunk/protemix/rename.pl
===================================================================
--- /trunk/protemix/rename.pl	(revision 3181)
+++ /trunk/protemix/rename.pl	(revision 3182)
@@ -91,4 +91,8 @@
     $noncss =~ s/\\\n/\n/sg;
 
+    # Occurances of 2HCl (lowercase el) were mistakenly changed to 2HC1
+    # (digit one) during OCR in some cases so we'll change them back
+    $noncss =~ s/2HC1/2HCl/g;
+
     # alter <img> tags to support renamed files
     $noncss =~ s/(<img src=\")([^\"]+)/$1 . &rename_file($2)/sige;
Index: /trunk/protemix/src/recpt/Makefile.in
===================================================================
--- /trunk/protemix/src/recpt/Makefile.in	(revision 3181)
+++ /trunk/protemix/src/recpt/Makefile.in	(revision 3182)
@@ -67,7 +67,7 @@
 HEADERS = ptmxqueryaction.h ptmxdocaction.h
 
-SOURCES = ptmxmain.cpp ptmxqueryaction.cpp ptmxdocaction.cpp browsetools.cpp
+SOURCES = ptmxmain.cpp ptmxqueryaction.cpp ptmxdocaction.cpp browsetools.cpp equivterms.cpp
 
-OBJECTS = ptmxmain.o ptmxqueryaction.o ptmxdocaction.o browsetools.o
+OBJECTS = ptmxmain.o ptmxqueryaction.o ptmxdocaction.o browsetools.o equivterms.o
 
 EXEC    = ptmx
Index: /trunk/protemix/src/recpt/equivterms.cpp
===================================================================
--- /trunk/protemix/src/recpt/equivterms.cpp	(revision 3182)
+++ /trunk/protemix/src/recpt/equivterms.cpp	(revision 3182)
@@ -0,0 +1,161 @@
+
+#include "text_t.h"
+#include <ctype.h> // for isspace
+#include <vector>
+
+void equiv_lookup(text_t& terms) {
+  // eventually we'll get these terms out of a config file or something...
+  vector<text_t> group;
+  vector< vector<text_t> > all_groups;
+  
+  group.push_back("triene");
+  group.push_back("trientine");
+  group.push_back("trien");
+  group.push_back("\"triethylenetetramine dihydrochloride\"");
+  group.push_back("\"triethylene tetramine dihydrochloride\"");
+  group.push_back("syprine");
+  group.push_back("teta");
+  group.push_back(text_t("\"trien 2hcl\""));
+  group.push_back(text_t("\"triethylenetetramine 2hcl\""));
+  group.push_back(text_t("\"bis aminoethyl ethanediamine dihydrochloride\""));
+  all_groups.push_back(group);
+
+
+  group.clear();
+  group.push_back("pkpd");
+  group.push_back("pkin");
+  group.push_back("pharmocokinetic");
+  group.push_back("pharmacodynamic");
+  all_groups.push_back(group);
+
+
+  group.clear();
+  group.push_back("safety");
+  group.push_back("\"side effects\"");
+  group.push_back("toxicity");
+  group.push_back("toxicology");
+  all_groups.push_back(group);
+
+
+  group.clear();
+  group.push_back("sod");
+  group.push_back("\"superoxide dismutase\"");
+  group.push_back("\"super oxide dismutase\"");
+  all_groups.push_back(group);
+
+
+  group.clear();
+  group.push_back("ceruloplasmin");
+  group.push_back("caeruloplasmin");
+  all_groups.push_back(group);
+
+
+  // we always convert to lowercase to do the lookup
+  text_t casestemoptions="";
+  text_t termproper="";
+
+  text_t::const_iterator hash=terms.end();
+  text_t::const_iterator start=terms.begin();
+  while (hash!=start) {
+    if (*hash=='#') break;
+    --hash;
+  }
+  if (hash!=start) { // we found a hash
+    casestemoptions=substr(hash,terms.end());
+    termproper=substr(start,hash);
+  } else {
+    termproper=terms;
+  }
+
+  // canonicalise termproper to lowercase for lookup
+  lc(termproper.begin(), termproper.end());
+
+  // look up vectors
+  vector< vector<text_t> >::const_iterator group_here=all_groups.begin();
+  vector< vector<text_t> >::const_iterator group_done=all_groups.end();
+
+  while (group_here != group_done) {
+    vector<text_t>::const_iterator syn_here=group_here->begin();
+    vector<text_t>::const_iterator syn_done=group_here->end();
+
+    while (syn_here != syn_done) {
+      if (*syn_here == termproper) // we found a match
+        break;
+      ++syn_here;
+    }
+    if (syn_here != syn_done) { // we found a match in this group
+      syn_here=group_here->begin();
+      terms="(";
+      
+      while (syn_here != syn_done) {
+        terms+= *syn_here;
+        terms+= casestemoptions;
+        if (syn_here != syn_done - 1) {
+          terms+=" | ";
+        }
+        ++syn_here;
+      }
+      terms.push_back(')');
+      break;
+    }
+    ++group_here;
+  }
+
+}
+
+void insert_equiv_terms(text_t& query) {
+
+  // we assume that for protemix, we don't have "high" unicode values.
+  // don't do terms inside quotes
+  text_t new_query="";
+
+  unsigned int query_length=query.size();
+  unsigned int i;
+  bool inside_quotes=false;
+  bool inside_field=false; // we need to OR together the terms inside fields
+  bool in_a_term=false;
+  text_t::const_iterator here = query.begin();
+  text_t::const_iterator end = query.end();
+
+  text_t::const_iterator term_start=here;
+  // | and &...
+  while (here < end) {
+    if (*here=='"') {
+      new_query.push_back('"');
+      if (inside_quotes==false) {
+        inside_quotes=true;
+        while (*(++here) != '"')
+          new_query.push_back(*here);
+        new_query.push_back('"');
+      } else {
+        inside_quotes=false;
+      }
+    } else if (isspace(*here)) {
+      if (in_a_term) { // we've reached the end of a term
+        // this might include case and stem options...
+        text_t term=substr(term_start,here);
+        equiv_lookup(term);
+        new_query+=term;
+        new_query+=" ";
+        in_a_term=false;
+      }
+    } else if (*here=='[') {
+      // start of a field...
+    } else if (*here==']') {
+      // end of a field...
+    } else if (!in_a_term) { // this char is start of term
+      term_start=here;
+      in_a_term=true;
+    }
+
+    ++here;
+  }
+
+  // tidy up for last term
+  if (in_a_term) {
+    text_t term=substr(term_start,here);
+    equiv_lookup(term);
+    new_query+=term;
+  }
+  query=new_query;
+}
Index: /trunk/protemix/src/recpt/ptmxdocaction.cpp
===================================================================
--- /trunk/protemix/src/recpt/ptmxdocaction.cpp	(revision 3181)
+++ /trunk/protemix/src/recpt/ptmxdocaction.cpp	(revision 3182)
@@ -27,4 +27,5 @@
 #include "ptmxdocaction.h"
 #include "OIDtools.h"
+#include "querytools.h"
 
 ptmxdocaction::ptmxdocaction () {
@@ -62,2 +63,159 @@
 }
 
+// overridden to format the querystring when highlighting text
+void ptmxdocaction::output_document (const text_t &OID, cgiargsclass &args, 
+				     recptproto *collectproto, displayclass &disp, 
+				     outconvertclass &outconvert, ostream &textout, 
+				     ostream &logout) {
+  FilterResponse_t inforesponse;
+  FilterResponse_t queryresponse;
+  text_tset metadata;
+  bool getParents = false;
+  bool highlight = false;
+  int wanttext = 0;
+  int arg_gt = args.getintarg("gt");
+  text_t &collection = args["c"];
+    
+  // if we have a query string and highlighting is turned on we need
+  // to redo the query to get the terms for highlighting
+  if (args.getintarg("hl")) {
+    FilterRequest_t request;
+    comerror_t err;
+    request.filterResultOptions = FRmatchTerms;
+    text_t formattedstring = args["q"];
+    format_querystring (formattedstring, args.getintarg("b"));
+
+    // ------ for ptmx collection
+
+    if (!args["c1"].empty() && args["c1"] != "Any") {
+      //    formattedstring = "[" + args["c1"] + "]:CL";
+      formattedstring = args["c1"];
+    }
+    if (!args["c2"].empty() && args["c2"] != "Any") {
+      if (!formattedstring.empty()) formattedstring += " & ";
+      //    formattedstring += "[" + args["c2"] + "]:CA";
+      formattedstring += args["c2"];
+    }
+    if (!args["c3"].empty() && args["c3"] != "Any") {
+      if (!formattedstring.empty()) formattedstring += " & ";
+      //    formattedstring += "[" + args["c3"] + "]:CS";
+      formattedstring += args["c3"];
+    }
+    if (!args["q"].empty()) {
+      if (!formattedstring.empty()) formattedstring += " & ";
+      formattedstring += args["q"];
+    }
+
+    void insert_equiv_terms(text_t&); // declaration
+    insert_equiv_terms(formattedstring);
+    
+    // --------------
+
+    if (!formattedstring.empty()) {
+
+      set_queryfilter_options (request, formattedstring, args);
+      collectproto->filter (args["c"], request, queryresponse, err, logout);
+      if (err != noError) {
+	outconvertclass text_t2ascii;
+	logout << text_t2ascii
+	       << "documentaction::output_document: call to QueryFilter failed "
+	       << "for " << args["c"] << " collection (" << get_comerror_string (err) << ")\n";
+	highlight = false;
+      } else {
+	highlight = true;
+      }
+    }
+  }
+
+
+  format_t *formatlistptr = new format_t();
+  parse_formatstring (formatinfo.DocumentText, formatlistptr, metadata, getParents);
+
+  metadata.insert ("hastxt");
+  metadata.insert ("haschildren");
+
+  if (formatinfo.DocumentText == "[Text]")
+    wanttext = 1;
+  else {
+    char *docformat = formatinfo.DocumentText.getcstr();
+    if (strstr (docformat, "[Text]") != NULL)
+      wanttext = 2;
+    delete docformat;
+  }
+    
+  if (get_info (OID, collection, metadata, getParents, collectproto, inforesponse, logout)) {
+    int hastxt = inforesponse.docInfo[0].metadata["hastxt"].values[0].getint();
+    int haschildren = inforesponse.docInfo[0].metadata["haschildren"].values[0].getint();
+    
+    if (arg_gt == 0) {
+      output_text (inforesponse.docInfo[0], formatlistptr, queryresponse.termInfo, 
+		   OID, highlight, hastxt, wanttext, collection, collectproto, 
+		   disp, outconvert, textout, logout);
+
+
+    } else {
+
+      ResultDocInfo_t thisdocinfo = inforesponse.docInfo[0];
+	
+      // text is to be expanded
+      text_t exOID = OID;
+      if (haschildren != 1) exOID = get_parent (OID);
+      if (exOID.empty()) exOID = OID;
+	
+      // if we're not in a document (i.e. we're in a top level classification)
+      // we need to pass "is_classify = true" to get_contents so that it 
+      // doesn't recurse all the way through each document in the classification
+      bool is_classify = false;
+      if (args["d"].empty()) is_classify = true;
+
+      get_contents (exOID, is_classify, metadata, collection, 
+		    collectproto, inforesponse, logout);
+	
+      ResultDocInfo_tarray::iterator sechere = inforesponse.docInfo.begin();
+      ResultDocInfo_tarray::iterator secend = inforesponse.docInfo.end();
+
+      if (arg_gt == 1) {
+	// check if there are more than 10 sections containing text to be expanded - 
+	// if there are output warning message - this isn't a great way to do this
+	// since the sections may be very large or very small - one day I'll fix it 
+	// -- Stefan.
+	int seccount = 0;
+	while (sechere != secend) {
+	  int shastxt = (*sechere).metadata["hastxt"].values[0].getint();
+	  if (shastxt == 1) seccount ++;
+	  if (seccount > 10) break;
+	  sechere ++;
+	}
+	if (seccount > 10) {
+	  // more than 10 sections so output warning message and text 
+	  // for current section only
+	  textout << outconvert << disp << "_document:textltwarning_";
+
+	  output_text (thisdocinfo, formatlistptr, queryresponse.termInfo, 
+		       OID, highlight, hastxt, wanttext, collection, 
+		       collectproto, disp, outconvert, textout, logout);
+	  
+	}
+	else arg_gt = 2;
+      }
+
+      if (arg_gt == 2) {
+	// get the text for each section
+	sechere = inforesponse.docInfo.begin();
+	int count = 0;
+	while (sechere != secend) {
+	  textout << outconvert << disp << "\n<p><a name=" << (*sechere).OID << "></a>\n";
+
+	  int shastxt = (*sechere).metadata["hastxt"].values[0].getint();
+
+	  output_text (*sechere, formatlistptr, queryresponse.termInfo, 
+		       (*sechere).OID, highlight, shastxt, wanttext, collection, 
+		       collectproto, disp, outconvert, textout, logout);
+	  count ++;
+	  sechere ++;
+	}
+      }
+    }
+  }
+  delete formatlistptr;
+}
Index: /trunk/protemix/src/recpt/ptmxdocaction.h
===================================================================
--- /trunk/protemix/src/recpt/ptmxdocaction.h	(revision 3181)
+++ /trunk/protemix/src/recpt/ptmxdocaction.h	(revision 3182)
@@ -41,4 +41,10 @@
   virtual void define_internal_macros (displayclass &disp, cgiargsclass &args, 
 				       recptprotolistclass *protos, ostream &logout);
+
+  virtual void output_document (const text_t &OID, cgiargsclass &args, 
+				recptproto *collectproto, displayclass &disp, 
+				outconvertclass &outconvert, ostream &textout, 
+				ostream &logout);
+
 };
 
Index: /trunk/protemix/src/recpt/ptmxqueryaction.cpp
===================================================================
--- /trunk/protemix/src/recpt/ptmxqueryaction.cpp	(revision 3181)
+++ /trunk/protemix/src/recpt/ptmxqueryaction.cpp	(revision 3182)
@@ -128,5 +128,7 @@
   }
 
-  logout << outconvert << "formattedstring: " << formattedstring << "\n";
+  // do synonym searching stuff
+  int insert_equiv_terms(text_t&); // forward declaration
+  insert_equiv_terms(formattedstring);
 
   if (!formattedstring.empty()) {
