Index: trunk/gsdl/src/recpt/Makefile.in
===================================================================
--- trunk/gsdl/src/recpt/Makefile.in	(revision 12019)
+++ trunk/gsdl/src/recpt/Makefile.in	(revision 12044)
@@ -149,5 +149,5 @@
 
 COMMONHEADERS = receptionist.h cgiwrapper.h cgiargs.h action.h browserclass.h \
-                converter.h recptconfig.h cgiutils.h OIDtools.h browsetools.h \
+                converter.h recptconfig.h cgiutils.h OIDtools.h browsetoolsclass.h \
 		statusaction.h pageaction.h comtypes.h recptproto.h \
 		pingaction.h queryaction.h documentaction.h  \
@@ -171,5 +171,5 @@
 
 COMMONSOURCES = receptionist.cpp cgiwrapper.cpp cgiargs.cpp action.cpp browserclass.cpp \
-                converter.cpp recptconfig.cpp cgiutils.cpp OIDtools.cpp browsetools.cpp \
+                converter.cpp recptconfig.cpp cgiutils.cpp OIDtools.cpp browsetoolsclass.cpp \
 		statusaction.cpp pageaction.cpp comtypes.cpp  \
 		recptproto.cpp pingaction.cpp queryaction.cpp documentaction.cpp \
@@ -204,5 +204,5 @@
 
 COMMONOBJECTS = receptionist.o cgiwrapper.o cgiargs.o action.o browserclass.o \
-                converter.o recptconfig.o cgiutils.o OIDtools.o browsetools.o \
+                converter.o recptconfig.o cgiutils.o OIDtools.o browsetoolsclass.o \
 		statusaction.o pageaction.o comtypes.o \
 		recptproto.o pingaction.o queryaction.o documentaction.o \
Index: trunk/gsdl/src/recpt/browsetools.cpp
===================================================================
--- trunk/gsdl/src/recpt/browsetools.cpp	(revision 12019)
+++ 	(revision )
@@ -1,919 +1,0 @@
-
-/**********************************************************************
- *
- * browsetools.cpp -- 
- * Copyright (C) 1999  The New Zealand Digital Library Project
- *
- * A component of the Greenstone digital library software
- * from the New Zealand Digital Library Project at the
- * University of Waikato, New Zealand.
- *
- * 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.
- *
- * $Id$
- *
- *********************************************************************/
-
-#include "browsetools.h"
-#include "OIDtools.h"
-#include "gsdlunicode.h"
-
-#if defined(GSDL_USE_IOS_H)
-#  if defined(__WIN32__)
-#    include <strstrea.h> // vc4
-#  else
-#    include <strstream.h>
-#  endif
-#else
-#  include <sstream>
-#endif
-
-
-// output_controls displays the detach, expand/contract contents,
-// expand/contract text and highlighting/no highlighting buttons
-
-void output_controls (cgiargsclass &args, const text_tarray &ibuttons,
-		      recptproto * /*collectproto*/, displayclass &disp, 
-		      outconvertclass &outconvert, ostream &textout, 
-		      ostream &/*logout*/) {
-
-  if (args["u"] != "1") {
-    
-    FilterResponse_t response;
-    text_tarray metadata;
-    text_tarray buttons;
-    
-    text_tarray::const_iterator here = ibuttons.begin();
-    text_tarray::const_iterator end = ibuttons.end();
-    
-    while (here != end) {
-      
-      if (*here == "Detach")
-	buttons.push_back ("_document:imagedetach_");
-      else if (*here == "Highlight") {
-	if (args["hl"] == "1") 
-	  buttons.push_back ("_document:imagenohighlight_");
-	else 
-	  buttons.push_back ("_document:imagehighlight_");
-      } else if (*here == "Expand Contents") {
-	if (args["gc"] == "1")
-	  buttons.push_back ("_document:imagecontracttoc_");
-	else 
-	  buttons.push_back ("_document:imageexpandtoc_");
-      } else if (*here == "Expand Text") {
-	if (args.getintarg("gt"))
-	  buttons.push_back ("_document:imagecontracttext_");
-	else 
-	  buttons.push_back ("_document:imageexpandtext_");
-      }
-      ++here;
-    }
-    
-    here = buttons.begin();
-    end = buttons.end();
-    while (here != end) {
-      textout << outconvert << disp << *here;
-      ++here;
-    }
-  }
-}
-
-text_t get_cover_image () {
-   return "_httpcollimg_/{Or}{[parent(Top):archivedir],[archivedir]}/cover.jpg";
-}
-
-// at the moment this just writes out the html to display 
-// the cover image (assuming it's called cover.jpg)
-// this whole thing should be done with a call to the collection
-// server which would send a link to the cover image if there
-// was one otherwise send title, author and stuff
-void output_cover_image (cgiargsclass &args, recptproto * /*collectproto*/, 
-			 displayclass &disp, outconvertclass &outconvert, 
-			 ostream &textout, ostream &/*logout*/) {
-  
-  if (args["d"].empty()) return;
-  
-  textout << outconvert << disp << "<img alt=\"\" onError=\"src='_httpimg_/blank.gif'\" src=\"_httpcollimg_/_thisOID_/cover.jpg\">\n";
-}
-
-void output_titles (cgiargsclass &args, recptproto *collectproto, 
-		    browsermapclass *browsermap, formatinfo_t &formatinfo,
-		    displayclass &disp, outconvertclass &outconvert,
-		    ostream &textout, ostream &logout) {
-
-  if (args["d"].empty()) return;
-  
-  text_tset metadata;
-  bool getParents;
-  FilterResponse_t response;
-
-  format_t *formatlistptr = new format_t();
-  parse_formatstring (formatinfo.DocumentHeading, formatlistptr, metadata, getParents);
-
-  if (!get_info (args["d"], args["c"], args["l"], metadata, getParents, collectproto, response, logout))
-    return;
-
-  text_tmap options;
-  if (formatinfo.AllowExtendedOptions) {
-    load_extended_options(options, args, browsermap, formatinfo, 
-			  collectproto, disp, outconvert, logout);
-  }
-  textout << outconvert << disp 
-	  << get_formatted_string (args["c"],collectproto, response.docInfo[0], disp,
-				   formatlistptr, options, logout);
-}
-
-//this function outputs the related documents in the format specified 
-//in the collection configuration file if the collection preferences
-//indicate they wish related documents to be displayed.
-void output_related_docs (cgiargsclass &args, recptproto *collectproto, 
-			  formatinfo_t &formatinfo, displayclass &disp, 
-			  outconvertclass &outconvert, ostream &textout, 
-			  ostream &logout) {
-
-  if (args["d"].empty()) return; //if no OID
-  if (args["rd"] != "1") return; //if preferences say no related documents
-  
-  text_tset metadata;
-  bool getParents;
-  FilterResponse_t response;
-
-  //create new format pointer and parse the related doc format 
-  //string specified in the collection config file
-  format_t *formatlistptr = new format_t();
-  parse_formatstring (formatinfo.RelatedDocuments, formatlistptr, metadata, getParents);
-
-  if (!get_info (args["d"], args["c"], args["l"], metadata, getParents, collectproto, response, logout))
-    return;
-  
-  //get the format string from formattools.cpp
-  text_tmap options; // no options
-  text_t relateddocs =  get_formatted_string (args["c"],collectproto, response.docInfo[0], 
-					      disp, formatlistptr, options, logout);
-  //output the related documents
-  textout << outconvert << disp << relateddocs;
-}
-
-
-
-static void recurse_contents (ResultDocInfo_t &section, cgiargsclass &args, bool fulltoc,
-			      browserclass *bptr, text_tset &metadata, bool &getParents, 
-			      format_t *formatlistptr, format_tmap &formatlistmap, 
-			      formatinfo_t &formatinfo, browsermapclass *browsermap, 
-			      int tabcount, recptproto *collectproto, displayclass &disp, 
-			      outconvertclass &outconvert, ostream &textout, ostream &logout) {
-  text_t formatstring;
-
-  bool is_classify = false;
-  if (args["d"].empty() || fulltoc) is_classify = true;
-
-  // output this section 
-  bool use_table = is_table_content (formatlistptr);
-  tabcount += bptr->output_section_group (section, args, args["c"], tabcount, formatlistptr, use_table, 
-					  metadata, getParents, collectproto, disp, outconvert, 
-					  textout, logout);
-
-  text_t classification;
-  if (!is_classify) classification = "Document";
-  else get_top (args["cl"], classification);
-
-  int haschildren = section.metadata["haschildren"].values[0].getint();
-  const text_t &doctype = section.metadata["doctype"].values[0];
-  text_t classifytype = section.metadata["childtype"].values[0];
-  // HLists and DateLists are displayed as VLists when contents 
-  // are expanded, Paged documents are displayed as HLists
-  if (classifytype == "HList" || classifytype == "DateList") classifytype = "VList";
-  if (classifytype == "Paged") classifytype = "HList";
-
-  // recurse through children
-  if ((haschildren == 1) && (!is_classify || fulltoc || doctype == "classify")) {
-
-    // get browser for displaying children
-    bptr = browsermap->getbrowser (classifytype);
-    bptr->load_metadata_defaults (metadata);
-
-    // get the formatstring if there is one 
-    if (!get_formatstring (classification, classifytype, 
-			   formatinfo.formatstrings, formatstring))
-      formatstring = bptr->get_default_formatstring();
-
-    format_tmap::const_iterator it = formatlistmap.find (formatstring);
-    // check if formatlistptr is cached
-    if (it != formatlistmap.end()) formatlistptr = (*it).second;
-    else {
-      formatlistptr = new format_t();
-      parse_formatstring (formatstring, formatlistptr, metadata, getParents);
-      formatlistmap[formatstring] = formatlistptr;
-    }
-
-    FilterResponse_t tmp;
-    get_children (section.OID, args["c"], args["l"], metadata, getParents, collectproto, tmp, logout);
-    ResultDocInfo_tarray::iterator thisdoc = tmp.docInfo.begin();
-    ResultDocInfo_tarray::iterator lastdoc = tmp.docInfo.end();
-
-    while (thisdoc != lastdoc) {
-      recurse_contents (*thisdoc, args, fulltoc, bptr, metadata, getParents, 
-			formatlistptr, formatlistmap, formatinfo, browsermap, 
-			tabcount, collectproto, disp, outconvert, textout, logout);
-      ++thisdoc;
-    }
-  }
-}
-
-
-// expanded_contents recurses through all contents. there's a special case
-// for an HList when contents are expanded (i.e. it's displayed as a VList)
-//
-// if we're inside a document we expand all contents from the top,
-// if we're at classification level we'll just expand out those contents below 
-// the current one
-
-void expanded_contents (cgiargsclass &args, int tabcount, bool fulltoc,
-			browsermapclass *browsermap, formatinfo_t &formatinfo, 
-			recptproto *collectproto, displayclass &disp, 
-			outconvertclass &outconvert, ostream &textout, 
-			ostream &logout) {
-  
-  if (args["d"].empty() && args["cl"].empty()) return;
-  text_t OID;
-  
-  FilterResponse_t response;
-  bool getParents = false;
-  text_tset metadata;
-  text_t classifytype, classification, formatstring;
-
-  if (!args["d"].empty()) {
-    // document level
-    if (fulltoc) {
-      get_top (args["cl"], OID);
-      classification = OID;
-    }
-    else {
-      // always expand document level from top
-      get_top (args["d"], OID);
-      classification = "Document";
-    }
-  } else {
-    // classification level
-    OID = args["cl"];
-    get_top (args["cl"], classification);
-  }
-
-  // get classifytype of this level
-  text_t tOID;
-  if (is_top(OID)) {
-    classifytype = "thistype";
-    tOID = OID;
-  } else {
-    classifytype = "childtype";
-    tOID = get_parent (OID);
-  }
-  metadata.insert (classifytype);
-
-  if (!get_info (tOID, args["c"], args["l"], metadata, getParents, collectproto, response, logout))
-    return;
-  classifytype = response.docInfo[0].metadata[classifytype].values[0];
-  // if we still don't have a classifytype we'll use the default
-  if (classifytype.empty()) {
-    browserclass *bptr = browsermap->get_default_browser ();
-    classifytype = bptr->get_browser_name ();
-  }
-
-  // HLists are displayed as VLists when contents are expanded,
-  // Paged documents are displayed as HLists
-  if (classifytype == "HList") {
-    classifytype = "VList";
-    text_t pOID = get_parent (OID);
-    if (!pOID.empty()) {
-      OID = pOID;
-      // this is assuming that top levels are always 'Invisible' !!!
-      if (is_top (OID)) classifytype = "Invisible";
-    }
-  }
-  if (classifytype == "Paged") classifytype = "HList";
-
-  metadata.erase (metadata.begin(), metadata.end());
-		  
-  // metadata elements needed by recurse_contents
-  metadata.insert ("childtype");
-  metadata.insert ("doctype");
-  metadata.insert ("haschildren");
-
-  // load up metadata array with browser defaults
-  browserclass *bptr = browsermap->getbrowser (classifytype);
-  bptr->load_metadata_defaults (metadata);
-
-  // get the formatstring if there is one or use the browsers default
-  if (!get_formatstring (classification, classifytype, 
-			 formatinfo.formatstrings, formatstring))
-    formatstring = bptr->get_default_formatstring();
-
-  format_t *formatlistptr = new format_t();
-  parse_formatstring (formatstring, formatlistptr, metadata, getParents);
-
-  // protocol call
-  if (!get_info (OID, args["c"], args["l"], metadata, getParents, collectproto, response, logout))
-    return;
-
-  format_tmap formatlistmap;
-  formatlistmap[formatstring] = formatlistptr;
-
-  recurse_contents (response.docInfo[0], args, fulltoc, bptr, metadata, 
-		    getParents, formatlistptr, formatlistmap, formatinfo, browsermap, 
-		    tabcount, collectproto, disp, outconvert, textout, logout);
-
-  // clean up format list pointers
-  format_tmap::const_iterator here = formatlistmap.begin();
-  format_tmap::const_iterator end = formatlistmap.end();
-  while (here != end) {
-    delete (*here).second;
-    ++here;
-  }
-}
-
-
-static void load_formatstring (const text_t &classifytype, text_tset &metadata,
-			       bool &getParents, const text_t &classification, 
-			       browsermapclass *browsermap, formatinfo_t &formatinfo,
-			       format_tmap &formatlistmap) {
-  text_t formatstring;
-
-  // load up metadata array with browser defaults
-  browserclass *bptr = browsermap->getbrowser (classifytype);
-  bptr->load_metadata_defaults (metadata);
-
-  // get the formatstring if there is one or use the browsers default
-  if (!get_formatstring (classification, classifytype, 
-			 formatinfo.formatstrings, formatstring))
-    formatstring = bptr->get_default_formatstring();
-
-  // see if it's cached
-  format_tmap::const_iterator it = formatlistmap.find (formatstring);
-  if (it == formatlistmap.end()) {
-    format_t *formatlistptr = new format_t();
-    parse_formatstring (formatstring, formatlistptr, metadata, getParents);
-    formatlistmap[formatstring] = formatlistptr;
-  }
-}
-
-static void load_formatstrings (FilterResponse_t &response, text_tset &metadata,
-				bool &getParents, const text_t &classification,
-				browsermapclass *browsermap, formatinfo_t &formatinfo, 
-				format_tmap &formatlistmap) {
-
-  text_tset cache;
-
-  ResultDocInfo_tarray::iterator thisdoc = response.docInfo.begin();
-  ResultDocInfo_tarray::iterator lastdoc = response.docInfo.end();
-
-  while (thisdoc != lastdoc) {
-
-    if (is_top ((*thisdoc).OID)) {
-      load_formatstring ((*thisdoc).metadata["thistype"].values[0], metadata, 
-			 getParents, classification, browsermap, formatinfo, 
-			 formatlistmap);
-    }
-    
-    // sometimes childtype is not set - why??
-    if ((*thisdoc).metadata.find("childtype") != (*thisdoc).metadata.end()) {
-      text_t &childtype = (*thisdoc).metadata["childtype"].values[0];
-
-      text_tset::const_iterator it = cache.find (childtype);
-      if (it == cache.end()) {
-	load_formatstring (childtype, metadata, getParents, classification,
-			   browsermap, formatinfo, formatlistmap);
-	cache.insert (childtype);
-      }
-    }
-    ++thisdoc;
-  }
-}
-
-static void output_parents (FilterResponse_t &response, cgiargsclass &args, 
-			    browsermapclass *browsermap, formatinfo_t &formatinfo, 
-			    format_tmap &formatlistmap, const text_t &classification,
-			    int &tabcount, text_tset &metadata, bool &getParents,
-			    recptproto *collectproto, displayclass &disp, 
-			    outconvertclass &outconvert, ostream &textout, 
-			    ostream &logout) {
-
-  format_t *formatlistptr = NULL;
-  text_t classifytype, formatstring;
-  bool use_table, first = true;
-  ResultDocInfo_tarray::iterator thisparent = response.docInfo.begin();
-  ResultDocInfo_tarray::iterator lastparent = response.docInfo.end();
-  while (thisparent != lastparent) {
-
-    // get classifytype of this level
-    if (is_top ((*thisparent).OID)) classifytype = (*thisparent).metadata["thistype"].values[0];
-    else if (!first && (*(thisparent-1)).metadata.find("childtype") != (*(thisparent-1)).metadata.end()) classifytype = (*(thisparent-1)).metadata["childtype"].values[0];
-    
-    // if we still don't have a classifytype we'll use the default
-    if (classifytype.empty()) {
-      browserclass *bptr = browsermap->get_default_browser ();
-      classifytype = bptr->get_browser_name ();
-    }
-    
-    browserclass *bptr = browsermap->getbrowser (classifytype);
-
-    // get the formatstring if there is one or use the browsers default
-    if (!get_formatstring (classification, classifytype, 
-			   formatinfo.formatstrings, formatstring))
-      formatstring = bptr->get_default_formatstring();
-    
-    // see if it's cached
-    format_tmap::const_iterator it = formatlistmap.find (formatstring);
-    if (it != formatlistmap.end()) formatlistptr = (*it).second;
-    else {
-      logout << "browsetools error\n";
-      return;
-    }
-    
-    use_table = is_table_content (formatlistptr);
-    tabcount += bptr->output_section_group (*thisparent, args, args["c"], tabcount, formatlistptr, 
-					    use_table, metadata, getParents, collectproto, 
-					    disp, outconvert, textout, logout);
-    first = false;
-    ++thisparent;
-  }
-}
-
-void contracted_contents (cgiargsclass &args, int tabcount, bool fulltoc, 
-			  browsermapclass *browsermap, formatinfo_t &formatinfo, 
-			  recptproto *collectproto, displayclass &disp, 
-			  outconvertclass &outconvert, ostream &textout, 
-			  ostream &logout) {
-
-  FilterResponse_t response;
-  text_tset metadata;
-  bool getParents = false;
-  text_t formatstring;
-  text_tarray parents;
-  text_t OID = args["d"];
-  text_t classification = "Document";
-
-  // if we're not outputting the TOC for a valid OID, then we should be giving
-  // the TOC of a classification
-  if (OID.empty()) {
-    OID = args["cl"];
-    get_top (OID, classification);
-  } 
-  // if we're to give the full TOC of a document, get the parent for the whole
-  // document now
-  else if (fulltoc)
-    get_top (args["cl"], classification);    
-
-  bool haschildren = has_children (OID, args["c"], args["l"], collectproto, logout);
-
-  if ((!args["d"].empty()) && fulltoc)
-    get_parents_array (args["cl"] + ".fc", parents);
-  if (haschildren) get_parents_array (OID + ".fc", parents);
-  else get_parents_array (OID, parents);
-
-  if (!parents.empty()) {
-    // get classifytypes of each parent
-    metadata.insert ("thistype");
-    metadata.insert ("childtype");
-    metadata.insert("mdtype");
-    
-    if (!get_info (parents, args["c"], args["l"], metadata, getParents, collectproto, response, logout))
-      return;
-    
-    // get formatstrings for all parents
-    format_tmap formatlistmap;  
-    load_formatstrings (response, metadata, getParents, classification, 
-			browsermap, formatinfo, formatlistmap);
-
-    if (!get_info (parents, args["c"], args["l"], metadata, getParents, collectproto, response, logout))
-      return;
-    
-    // display each parent
-    output_parents (response, args, browsermap, formatinfo, formatlistmap, 
-		    classification, tabcount, metadata, getParents, 
-		    collectproto, disp, outconvert, textout, logout);
-    
-    metadata.erase (metadata.begin(), metadata.end());
-    
-    // clean up cached format list pointers
-    format_tmap::const_iterator here = formatlistmap.begin();
-    format_tmap::const_iterator end = formatlistmap.end();
-    while (here != end) {
-      delete (*here).second;
-      ++here;
-    }
-  }
-
-  // get childrens classifytype
-  text_t classifytype;
-  int numparents = response.docInfo.size();
-  if (!parents.empty() && (response.docInfo[numparents-1].metadata.find("childtype") != response.docInfo[numparents-1].metadata.end()))
-    classifytype = response.docInfo[numparents-1].metadata["childtype"].values[0];
-  else {
-    // use the default
-    browserclass *bptr = browsermap->get_default_browser ();
-    classifytype = bptr->get_browser_name ();
-  }
-    
-  // load up metadata array with browser defaults
-  browserclass *bptr = browsermap->getbrowser (classifytype);
-  bptr->load_metadata_defaults (metadata);
-
-  if (classifytype == "DateList") {
-    // get the mdtype
-    text_t datelist = "Date";
-    if (!parents.empty() && (response.docInfo[0].metadata.find("mdtype") != response.docInfo[0].metadata.end())) {
-      datelist = response.docInfo[0].metadata["mdtype"].values[0];
-    }
-    args.setarg("dm", datelist);
-    text_tarray dates;
-    splitchar(datelist.begin(), datelist.end(), ',', dates);
-    text_tarray::iterator begin = dates.begin();
-    text_tarray::iterator end = dates.end();
-    while (begin!= end) {
-      metadata.insert(*begin);
-      begin++;
-    }
-    
-  }
-
-  // get the formatstring if there is one or use the browsers default
-  if (!get_formatstring (classification, classifytype, 
-			 formatinfo.formatstrings, formatstring))
-    formatstring = bptr->get_default_formatstring();
-
-  format_t *formatlistptr = new format_t();
-  parse_formatstring (formatstring, formatlistptr, metadata, getParents);
-
-  if (haschildren) 
-    get_children (OID, args["c"], args["l"], metadata, getParents,
-		  collectproto, response, logout);
-  else if (!is_top(OID)) {
-    get_children (OID + ".pr", args["c"], args["l"], metadata, getParents, 
-		  collectproto, response, logout);
-    haschildren = true;
-  }
-
-  // display children
-  if (haschildren) {
-    bool use_table = is_table_content (formatlistptr);
-    bptr->output_section_group (response, args, args["c"], tabcount, formatlistptr, use_table, 
-				metadata, getParents, collectproto, disp, outconvert, 
-				textout, logout);
-  }
-  delete formatlistptr;
-}
-
-/**
- * This function outputs contents of a classifier to the reader
- * including parent levels
- */
-void expand_show_contents (cgiargsclass &args, int tabcount, bool fulltoc,
-			browsermapclass *browsermap, formatinfo_t &formatinfo,
-			recptproto *collectproto, displayclass &disp,
-			outconvertclass &outconvert, ostream &textout, 
-			ostream &logout)
-{
-
-	int coloffset = 0;
-	text_tarray parents;
-	FilterResponse_t response;
- 	text_t OID = args["d"];
-	if (OID.empty()) OID = args["cl"];
-
-	bool haschildren = has_children (OID, args["c"], args["l"], collectproto, logout);
-
-	// get parents list
-	if (!is_top(OID)) get_parents_array (OID, parents);
-	if (args["d"].empty() || haschildren || parents.empty())
-		parents.push_back(OID);
-
-	// if inside a book top title is needed
-	if (!args["d"].empty()) {
-		
-		coloffset = 1;
-		text_t classification, classifytype, formatstring, topOID = parents[0];
-		text_tset metadata;
-		format_t *formatlistptr = new format_t();
-		bool use_table, getParents = false;
-		
-		get_top (args["cl"], classification);
-
-		// getting information about top OID
-		metadata.insert ("thistype");
-
-		get_info ( topOID, args["c"], args["l"], metadata, getParents, collectproto, response, logout);
-		if (!response.docInfo[0].metadata["thistype"].values.empty()) 
-			classifytype = response.docInfo[0].metadata["thistype"].values[0];
-
-		browserclass *bptr = browsermap->getbrowser (classifytype);
-
-		if (classifytype.empty()) {
-			bptr = browsermap->get_default_browser();
-		}
-
-		// get the formatstring if there is one or use the browsers default
-		if (!get_formatstring (classification, classifytype, 
-			formatinfo.formatstrings, formatstring))
-				formatstring = bptr->get_default_formatstring();
-
-		parse_formatstring (formatstring, formatlistptr, metadata, getParents);
-
-		metadata.insert ("doctype");
-		metadata.insert ("haschildren");
-
-		get_info (topOID, args["c"], args["l"], metadata, getParents, collectproto, response, logout);
-
-		// ouput top OID section
-		use_table = is_table_content (formatlistptr);
-		bptr->output_section_group (response.docInfo[0], args, args["c"], tabcount, formatlistptr, use_table,
-				metadata, getParents, collectproto, disp, outconvert, textout, logout);
-
-	}
-
-	recurse_contents_levels (parents, args, coloffset, tabcount, fulltoc, browsermap, 
-		formatinfo, collectproto, disp, outconvert, textout, logout);
-
-	// This messes things up when gc = 2 and doesn't seem to matter otherwise. By Richard Managh
-	// textout << outconvert << "</table></td></tr></table>\n";
-}
-
-void recurse_contents_levels (text_tarray &parents, 
-			cgiargsclass &args, int coloffset, int tabcount, bool fulltoc,
-			browsermapclass *browsermap, formatinfo_t &formatinfo,
-			recptproto *collectproto, displayclass &disp,
-			outconvertclass &outconvert, ostream &textout, 
-			ostream &logout)
-{
-	FilterResponse_t response;
-	text_tset metadata;
-	text_t OID, formatstring, classification, classifytype;;
-	bool use_table, getParents = false;
-	int haschildren = 0;
-	format_t *formatlistptr = new format_t();
-
-	// display children for last level
-	if (tabcount == (parents.size() - 1)) {
-
-		logout << "@@@lastlevel@@@\n";
-		// setting metadata fields 
-		metadata.insert ("thistype");
-		metadata.insert ("childtype");
-		metadata.insert ("haschildren");
-
-		OID = parents[tabcount];
-		get_info (OID, args["c"], args["l"], metadata, getParents, collectproto, response, logout);
-		get_top (OID, classification);
-
-		if (!response.docInfo.empty())
-			haschildren = response.docInfo[0].metadata["haschildren"].values[0].getint();
-
-		// get childrens classifytype
-		if (!response.docInfo.empty())
-			classifytype = response.docInfo[0].metadata["childtype"].values[0];
-		else {
-			// use the default
-			browserclass *bptr = browsermap->get_default_browser ();
-			classifytype = bptr->get_browser_name ();
-		}
-
-		// load up metadata array with browser defaults
-		browserclass *bptr = browsermap->getbrowser (classifytype);
-		bptr->load_metadata_defaults (metadata);
-
-		// get the formatstring if there is one or use the browsers default
-		if (!get_formatstring (classification, classifytype, 
-			formatinfo.formatstrings, formatstring))
-				formatstring = bptr->get_default_formatstring();
-
-		parse_formatstring (formatstring, formatlistptr, metadata, getParents);
-
-		if (haschildren) 
-			get_children (OID, args["c"], args["l"], metadata, getParents,
-				collectproto, response, logout);
-		else if (!is_top(OID)) {
-			get_children (OID + ".pr", args["c"], args["l"], metadata, getParents, 
-			collectproto, response, logout);
-			haschildren = true;
-		}
-
-		// display children
-		if (haschildren) {
-			use_table = is_table_content (formatlistptr);
-			bptr->output_section_group (response, args, args["c"], coloffset + tabcount, formatlistptr, use_table, 
-						metadata, getParents, collectproto, disp, outconvert, 
-						textout, logout);
-		}
-
-	} else {
-
-		text_t pOID;
-		OID = parents[tabcount];
-		get_top (OID, classification);
-
-		// load metadata fields
-		metadata.insert ("thistype");
-		metadata.insert ("childtype");
-		metadata.insert ("haschildren");
-		metadata.insert ("doctype");
-
-		if (tabcount) pOID = parents[tabcount-1];
-		else pOID = OID;
-		get_info (pOID, args["c"], args["l"], metadata, getParents, collectproto, response, logout);
-
-		// get classifytype of this level
-		if (is_top (pOID)) classifytype = response.docInfo[0].metadata["childtype"].values[0];
-		else classifytype = response.docInfo[0].metadata["thistype"].values[0];
-
-		// if we still don't have a classifytype we'll use the default
-		if (classifytype.empty()) {
-			browserclass *bptr = browsermap->get_default_browser ();
-			classifytype = bptr->get_browser_name ();
-		}
-
-		browserclass *bptr = browsermap->getbrowser (classifytype);
-
-		// get the formatstring if there is one or use the browsers default
-		if (!get_formatstring (classification, classifytype, 
-				formatinfo.formatstrings, formatstring))
-			formatstring = bptr->get_default_formatstring();
-
-
-		// parse format string 
-		parse_formatstring (formatstring, formatlistptr, metadata, getParents);
-
-		use_table = is_table_content (formatlistptr);
-
-		get_children (OID, args["c"], args["l"], metadata, getParents, collectproto, response, logout);
-
-		ResultDocInfo_tarray::iterator thissibling = response.docInfo.begin();
-		ResultDocInfo_tarray::iterator lastsibling = response.docInfo.end();
-
-		while (thissibling != lastsibling) {
-
-			logout << "@@@level:@@@" << tabcount << "\n";
-
-			bptr->output_section_group (*thissibling, args, args["c"], coloffset + tabcount, formatlistptr, 
-					use_table, metadata, getParents, collectproto, 
-					disp, outconvert, textout, logout);
-			
-			if ((*thissibling).OID == parents[tabcount+1]) {
-				recurse_contents_levels (parents, args, coloffset, tabcount+1, fulltoc, browsermap,
-					formatinfo, collectproto, disp, outconvert,textout, logout);
-			}
-
-			++thissibling;
-		}
-	}
-	delete formatlistptr;
-}
-
-/**
- * This function outputs the contents of a classifier list to the reader - 
- * the document will in fact be empty, so this does the "real" output
- */
-void output_toc (cgiargsclass &args, browsermapclass *browsermap,
-                 formatinfo_t &formatinfo, recptproto *collectproto,
-                 displayclass &disp, outconvertclass &outconvert,
-                 ostream &textout, ostream &logout) {
-
-  if (!args["d"].empty() && formatinfo.AllowExtendedOptions) {
-    // If AllowExtendedOptions is set and we're viewing a document,
-    // DocumentButtons, DocumentContent, and DocumentImages are effectively
-    // disabled. We just output the DocumentHeading format string and
-    // return
-    output_titles (args, collectproto, browsermap, formatinfo, disp, outconvert, textout, logout);    
-    return;
-  }
-
-  int tabcount = 0;
-  bool fulltoc = false;
-  text_t cl_top, full_toc;
-  if (args["cl"] != "search") {
-    // see if there's a FullTOC string
-    get_top (args["cl"], cl_top);
-    if (get_formatstring (cl_top, "FullTOC", formatinfo.formatstrings, full_toc))
-      if (full_toc == "true") fulltoc = true;
-  }
-  
-  // get the cover image (if there is one) and the control buttons
-  // if we're inside a book
-  if ((!fulltoc) && (!args["d"].empty())) {
-    if (formatinfo.DocumentImages) {
-      textout << outconvert << "<div class=\"heading_image\">\n";
-      output_cover_image(args, collectproto, disp, outconvert, textout, logout);
-      textout << outconvert << "</div>\n";
-    } else if (formatinfo.DocumentTitles) {
-      textout << outconvert << "<div class=\"heading_title\">\n";
-      output_titles(args, collectproto, browsermap, formatinfo, disp, outconvert, textout, logout);
-      textout << outconvert << "</div>\n";
-    }
-    textout << outconvert << "<div class=\"buttons\" id=\"toc_buttons\">\n"; 
-    if (args["u"] != "1") {
-      output_controls (args, formatinfo.DocumentButtons, collectproto, disp, 
-		       outconvert, textout, logout);
-    }
-    textout << outconvert << "</div>\n\n"; 
-  }
-
-  if (formatinfo.DocumentContents || args["d"].empty()) {
-    if (args["d"].empty()) {
-      textout << outconvert << "<div id=\""<<cl_top<<"\" class=\"toc\">\n";
-    } else {
-      textout << outconvert << "<div class=\"toc\">\n";
-      
-    }
-    if (args.getintarg("gc") == 1) {
-      
-      // expanded table of contents
-      expanded_contents (args, tabcount, fulltoc, browsermap, formatinfo, 
-			 collectproto, disp, outconvert, textout, logout);
-    } else if (args.getintarg("gc") == 2) {
-
-		// expand visible levels of table of contents
-	  expand_show_contents(args, tabcount, fulltoc, browsermap, formatinfo,
-			collectproto, disp, outconvert, textout, logout);
-    } else {
-      
-      // contracted table of contents
-      contracted_contents (args, tabcount, fulltoc, browsermap, formatinfo, 
-			   collectproto, disp, outconvert, textout, logout);
-    }
-    textout << outconvert << "</div>\n";
-  }
-
-  //if there is a format specified in the config file then
-  //try to display the related documents (may not be displayed
-  //if preference file does not indicate a wish to display
-  //related documents.
-  if (!formatinfo.RelatedDocuments.empty())
-    output_related_docs(args, collectproto, formatinfo, disp, outconvert, textout, logout);
- 
-}
-
-void load_extended_options(text_tmap &options, cgiargsclass &args, browsermapclass *browsers, 
-			   formatinfo_t &formatinfo, recptproto *collectproto, 
-			   displayclass &disp, outconvertclass &outconvert, ostream &logout) {
-
-  options["DocImage"] = get_cover_image();
-
-#if defined(GSDL_USE_IOS_H)
-  ostrstream *tmpstr = new ostrstream();
-#else
-  ostringstream *tmpstr = new ostringstream(ostringstream::binary);
-#endif
-
-  if (args["gc"] == "1") {
-    expanded_contents (args, 0, false, browsers, formatinfo, 
-		       collectproto, disp, outconvert, *tmpstr,
-		       logout);
-  } else {
-    contracted_contents (args, 0, false, browsers, formatinfo, 
-			 collectproto, disp, outconvert, *tmpstr, logout);
-  }
-#if defined(GSDL_USE_IOS_H)
-  char *t = tmpstr->str();
-  text_t tmp;
-  tmp.setcarr(t, tmpstr->pcount());
-  delete [] t;
-#else
-  text_t tmp = (char *)(tmpstr->str().c_str());
-#endif
-  int len = tmp.size();
-  char *ctmp = tmp.getcstr();
-  utf8inconvertclass utf82text_t;
-  utf82text_t.setinput(ctmp, len);
-  convertclass::status_t status;
-  utf82text_t.convert(tmp, status);
-  options["DocTOC"] = tmp;
-  delete []ctmp;
-  delete tmpstr;
-
-  options["DocumentButtonDetach"] = "_document:imagedetach_";
-  if (args["hl"] == "1") {
-    options["DocumentButtonHighlight"] = "_document:imagenohighlight_";
-  } else {
-    options["DocumentButtonHighlight"] = "_document:imagehighlight_";
-  }
-  if (args["gc"] == "1") {
-    options["DocumentButtonExpandContents"] = "_document:imagecontracttoc_";
-  } else {
-    options["DocumentButtonExpandContents"] = "_document:imageexpandtoc_";
-  }
-  if (args["gt"] == "1") {
-    options["DocumentButtonExpandText"] = "_document:imagecontracttext_";
-  } else {
-    options["DocumentButtonExpandText"] = "_document:imageexpandtext_";
-  }
-}
Index: trunk/gsdl/src/recpt/browsetools.h
===================================================================
--- trunk/gsdl/src/recpt/browsetools.h	(revision 12019)
+++ 	(revision )
@@ -1,90 +1,0 @@
-/**********************************************************************
- *
- * browsetools.h --
- * Copyright (C) 1999  The New Zealand Digital Library Project
- *
- * A component of the Greenstone digital library software
- * from the New Zealand Digital Library Project at the
- * University of Waikato, New Zealand.
- *
- * 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.
- *
- *********************************************************************/
-
-
-#ifndef BROWSETOOLS_H
-#define BROWSETOOLS_H
-
-#include "gsdlconf.h"
-#include "text_t.h"
-#include "cgiargs.h"
-#include "display.h"
-#include "recptproto.h"
-#include "formattools.h"
-#include "browserclass.h"
-
-typedef map<text_t, format_t*, lttext_t> format_tmap; 
-
-void expanded_contents (cgiargsclass &args, int tabcount, bool fulltoc,
-			browsermapclass *browsermap, formatinfo_t &formatinfo, 
-			recptproto *collectproto, displayclass &disp, 
-			outconvertclass &outconvert, ostream &textout, 
-			ostream &logout);
-
-void expand_show_contents (cgiargsclass &args, int tabcount, bool fulltoc,
-			browsermapclass *browsermap, formatinfo_t &formatinfo, 
-			recptproto *collectproto, displayclass &disp, 
-			outconvertclass &outconvert, ostream &textout, 
-			ostream &logout);
-
-void recurse_contents_levels (text_tarray &parents, 
-			cgiargsclass &args, int coloffset, int tabcount, bool fulltoc,
-			browsermapclass *browsermap, formatinfo_t &formatinfo,
-			recptproto *collectproto, displayclass &disp,
-			outconvertclass &outconvert, ostream &textout, 
-			ostream &logout);
-
-void contracted_contents (cgiargsclass &args, int tabcount, bool fulltoc, 
-			  browsermapclass *browsermap, formatinfo_t &formatinfo, 
-			  recptproto *collectproto, displayclass &disp, 
-			  outconvertclass &outconvert, ostream &textout, 
-			  ostream &logout);
-
-void output_toc (cgiargsclass &args, browsermapclass *browsermap,
-                 formatinfo_t &formatinfo, recptproto *collectproto,
-                 displayclass &disp, outconvertclass &outconvert,
-                 ostream &textout, ostream &logout);
-
-void output_titles (cgiargsclass &args, recptproto *collectproto, 
-		    browsermapclass *browsermap, formatinfo_t &formatinfo,
-		    displayclass &disp, outconvertclass &outconvert,
-		    ostream &textout, ostream &logout);
-
-void output_controls (cgiargsclass &args, const text_tarray &ibuttons,
-		      recptproto *collectproto, displayclass &disp, 
-		      outconvertclass &outconvert, ostream &textout, 
-		      ostream &logout);
-
-text_t get_cover_image ();
-
-void output_cover_image (cgiargsclass &args, recptproto *collectproto, 
-			 displayclass &disp, outconvertclass &outconvert, 
-			 ostream &textout, ostream &logout);
-
-void load_extended_options(text_tmap &options, cgiargsclass &args, browsermapclass *browsers, 
-			   formatinfo_t &formatinfo, recptproto *collectproto, 
-			   displayclass &disp, outconvertclass &outconvert, ostream &logout);
-
-#endif
Index: trunk/gsdl/src/recpt/browsetoolsclass.cpp
===================================================================
--- trunk/gsdl/src/recpt/browsetoolsclass.cpp	(revision 12044)
+++ trunk/gsdl/src/recpt/browsetoolsclass.cpp	(revision 12044)
@@ -0,0 +1,902 @@
+
+/**********************************************************************
+ *
+ * browsetools.cpp -- 
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ * $Id$
+ *
+ *********************************************************************/
+
+#include "browsetoolsclass.h"
+#include "OIDtools.h"
+#include "gsdlunicode.h"
+
+#if defined(GSDL_USE_IOS_H)
+#  if defined(__WIN32__)
+#    include <strstrea.h> // vc4
+#  else
+#    include <strstream.h>
+#  endif
+#else
+#  include <sstream>
+#endif
+
+
+browsetoolsclass::browsetoolsclass()
+{
+}
+
+browsetoolsclass::~browsetoolsclass()
+{
+}
+
+// output_controls displays the detach, expand/contract contents,
+// expand/contract text and highlighting/no highlighting buttons
+
+void browsetoolsclass::output_controls(cgiargsclass &args, const text_tarray &ibuttons,
+                                       recptproto *collectproto, displayclass &disp, 
+                                       outconvertclass &outconvert, ostream &textout, 
+                                       ostream &logout)
+{
+  if (args["u"] != "1") {
+    
+    FilterResponse_t response;
+    text_tarray metadata;
+    text_tarray buttons;
+    
+    text_tarray::const_iterator here = ibuttons.begin();
+    text_tarray::const_iterator end = ibuttons.end();
+    
+    while (here != end) {
+      
+      if (*here == "Detach")
+	buttons.push_back ("_document:imagedetach_");
+      else if (*here == "Highlight") {
+	if (args["hl"] == "1") 
+	  buttons.push_back ("_document:imagenohighlight_");
+	else 
+	  buttons.push_back ("_document:imagehighlight_");
+      } else if (*here == "Expand Contents") {
+	if (args["gc"] == "1")
+	  buttons.push_back ("_document:imagecontracttoc_");
+	else 
+	  buttons.push_back ("_document:imageexpandtoc_");
+      } else if (*here == "Expand Text") {
+	if (args.getintarg("gt"))
+	  buttons.push_back ("_document:imagecontracttext_");
+	else 
+	  buttons.push_back ("_document:imageexpandtext_");
+      }
+      ++here;
+    }
+    
+    here = buttons.begin();
+    end = buttons.end();
+    while (here != end) {
+      textout << outconvert << disp << *here;
+      ++here;
+    }
+  }
+}
+
+text_t browsetoolsclass::get_cover_image()
+{
+  return "_httpcollimg_/{Or}{[parent(Top):archivedir],[archivedir]}/cover.jpg";
+}
+
+// at the moment this just writes out the html to display 
+// the cover image (assuming it's called cover.jpg)
+// this whole thing should be done with a call to the collection
+// server which would send a link to the cover image if there
+// was one otherwise send title, author and stuff
+void browsetoolsclass::output_cover_image(cgiargsclass &args, recptproto *collectproto, 
+                                          displayclass &disp, outconvertclass &outconvert, 
+                                          ostream &textout, ostream &logout)
+{
+  if (args["d"].empty()) return;
+  
+  textout << outconvert << disp << "<img alt=\"\" onError=\"src='_httpimg_/blank.gif'\" src=\"_httpcollimg_/_thisOID_/cover.jpg\">\n";
+}
+
+void browsetoolsclass::output_titles(cgiargsclass &args, recptproto *collectproto, 
+                                     browsermapclass *browsermap, formatinfo_t &formatinfo,
+                                     displayclass &disp, outconvertclass &outconvert,
+                                     ostream &textout, ostream &logout)
+{
+  if (args["d"].empty()) return;
+  
+  text_tset metadata;
+  bool getParents;
+  FilterResponse_t response;
+
+  format_t *formatlistptr = new format_t();
+  parse_formatstring (formatinfo.DocumentHeading, formatlistptr, metadata, getParents);
+
+  if (!get_info (args["d"], args["c"], args["l"], metadata, getParents, collectproto, response, logout))
+    return;
+
+  text_tmap options;
+  if (formatinfo.AllowExtendedOptions) {
+    load_extended_options(options, args, browsermap, formatinfo, 
+			  collectproto, disp, outconvert, logout);
+  }
+  textout << outconvert << disp 
+	  << get_formatted_string (args["c"],collectproto, response.docInfo[0], disp,
+				   formatlistptr, options, logout);
+}
+
+void browsetoolsclass::recurse_contents(ResultDocInfo_t &section, cgiargsclass &args, bool fulltoc,
+                                        browserclass *bptr, text_tset &metadata, bool &getParents, 
+                                        format_t *formatlistptr, format_tmap &formatlistmap, 
+                                        formatinfo_t &formatinfo, browsermapclass *browsermap, 
+                                        int tabcount, recptproto *collectproto, displayclass &disp, 
+                                        outconvertclass &outconvert, ostream &textout, ostream &logout)
+{
+  text_t formatstring;
+
+  bool is_classify = false;
+  if (args["d"].empty() || fulltoc) is_classify = true;
+
+  // output this section 
+  bool use_table = is_table_content (formatlistptr);
+  tabcount += bptr->output_section_group (section, args, args["c"], tabcount, formatlistptr, use_table, 
+					  metadata, getParents, collectproto, disp, outconvert, 
+					  textout, logout);
+
+  text_t classification;
+  if (!is_classify) classification = "Document";
+  else get_top (args["cl"], classification);
+
+  int haschildren = section.metadata["haschildren"].values[0].getint();
+  const text_t &doctype = section.metadata["doctype"].values[0];
+  text_t classifytype = section.metadata["childtype"].values[0];
+  // HLists and DateLists are displayed as VLists when contents 
+  // are expanded, Paged documents are displayed as HLists
+  if (classifytype == "HList" || classifytype == "DateList") classifytype = "VList";
+  if (classifytype == "Paged") classifytype = "HList";
+
+  // recurse through children
+  if ((haschildren == 1) && (!is_classify || fulltoc || doctype == "classify")) {
+
+    // get browser for displaying children
+    bptr = browsermap->getbrowser (classifytype);
+    bptr->load_metadata_defaults (metadata);
+
+    // get the formatstring if there is one 
+    if (!get_formatstring (classification, classifytype, 
+			   formatinfo.formatstrings, formatstring))
+      formatstring = bptr->get_default_formatstring();
+
+    format_tmap::const_iterator it = formatlistmap.find (formatstring);
+    // check if formatlistptr is cached
+    if (it != formatlistmap.end()) formatlistptr = (*it).second;
+    else {
+      formatlistptr = new format_t();
+      parse_formatstring (formatstring, formatlistptr, metadata, getParents);
+      formatlistmap[formatstring] = formatlistptr;
+    }
+
+    FilterResponse_t tmp;
+    get_children (section.OID, args["c"], args["l"], metadata, getParents, collectproto, tmp, logout);
+    ResultDocInfo_tarray::iterator thisdoc = tmp.docInfo.begin();
+    ResultDocInfo_tarray::iterator lastdoc = tmp.docInfo.end();
+
+    while (thisdoc != lastdoc) {
+      recurse_contents (*thisdoc, args, fulltoc, bptr, metadata, getParents, 
+			formatlistptr, formatlistmap, formatinfo, browsermap, 
+			tabcount, collectproto, disp, outconvert, textout, logout);
+      ++thisdoc;
+    }
+  }
+}
+
+
+// expanded_contents recurses through all contents. there's a special case
+// for an HList when contents are expanded (i.e. it's displayed as a VList)
+//
+// if we're inside a document we expand all contents from the top,
+// if we're at classification level we'll just expand out those contents below 
+// the current one
+
+void browsetoolsclass::expanded_contents(cgiargsclass &args, int tabcount, bool fulltoc,
+                                         browsermapclass *browsermap, formatinfo_t &formatinfo, 
+                                         recptproto *collectproto, displayclass &disp, 
+                                         outconvertclass &outconvert, ostream &textout, 
+                                         ostream &logout)
+{
+  if (args["d"].empty() && args["cl"].empty()) return;
+  text_t OID;
+  
+  FilterResponse_t response;
+  bool getParents = false;
+  text_tset metadata;
+  text_t classifytype, classification, formatstring;
+
+  if (!args["d"].empty()) {
+    // document level
+    if (fulltoc) {
+      get_top (args["cl"], OID);
+      classification = OID;
+    }
+    else {
+      // always expand document level from top
+      get_top (args["d"], OID);
+      classification = "Document";
+    }
+  } else {
+    // classification level
+    OID = args["cl"];
+    get_top (args["cl"], classification);
+  }
+
+  // get classifytype of this level
+  text_t tOID;
+  if (is_top(OID)) {
+    classifytype = "thistype";
+    tOID = OID;
+  } else {
+    classifytype = "childtype";
+    tOID = get_parent (OID);
+  }
+  metadata.insert (classifytype);
+
+  if (!get_info (tOID, args["c"], args["l"], metadata, getParents, collectproto, response, logout))
+    return;
+  classifytype = response.docInfo[0].metadata[classifytype].values[0];
+  // if we still don't have a classifytype we'll use the default
+  if (classifytype.empty()) {
+    browserclass *bptr = browsermap->get_default_browser ();
+    classifytype = bptr->get_browser_name ();
+  }
+
+  // HLists are displayed as VLists when contents are expanded,
+  // Paged documents are displayed as HLists
+  if (classifytype == "HList") {
+    classifytype = "VList";
+    text_t pOID = get_parent (OID);
+    if (!pOID.empty()) {
+      OID = pOID;
+      // this is assuming that top levels are always 'Invisible' !!!
+      if (is_top (OID)) classifytype = "Invisible";
+    }
+  }
+  if (classifytype == "Paged") classifytype = "HList";
+
+  metadata.erase (metadata.begin(), metadata.end());
+		  
+  // metadata elements needed by recurse_contents
+  metadata.insert ("childtype");
+  metadata.insert ("doctype");
+  metadata.insert ("haschildren");
+
+  // load up metadata array with browser defaults
+  browserclass *bptr = browsermap->getbrowser (classifytype);
+  bptr->load_metadata_defaults (metadata);
+
+  // get the formatstring if there is one or use the browsers default
+  if (!get_formatstring (classification, classifytype, 
+			 formatinfo.formatstrings, formatstring))
+    formatstring = bptr->get_default_formatstring();
+
+  format_t *formatlistptr = new format_t();
+  parse_formatstring (formatstring, formatlistptr, metadata, getParents);
+
+  // protocol call
+  if (!get_info (OID, args["c"], args["l"], metadata, getParents, collectproto, response, logout))
+    return;
+
+  format_tmap formatlistmap;
+  formatlistmap[formatstring] = formatlistptr;
+
+  recurse_contents (response.docInfo[0], args, fulltoc, bptr, metadata, 
+		    getParents, formatlistptr, formatlistmap, formatinfo, browsermap, 
+		    tabcount, collectproto, disp, outconvert, textout, logout);
+
+  // clean up format list pointers
+  format_tmap::const_iterator here = formatlistmap.begin();
+  format_tmap::const_iterator end = formatlistmap.end();
+  while (here != end) {
+    delete (*here).second;
+    ++here;
+  }
+}
+
+void browsetoolsclass::load_formatstring(const text_t &classifytype, text_tset &metadata,
+                                         bool &getParents, const text_t &classification, 
+                                         browsermapclass *browsermap, formatinfo_t &formatinfo,
+                                         format_tmap &formatlistmap)
+{
+  text_t formatstring;
+
+  // load up metadata array with browser defaults
+  browserclass *bptr = browsermap->getbrowser (classifytype);
+  bptr->load_metadata_defaults (metadata);
+
+  // get the formatstring if there is one or use the browsers default
+  if (!get_formatstring (classification, classifytype, 
+			 formatinfo.formatstrings, formatstring))
+    formatstring = bptr->get_default_formatstring();
+
+  // see if it's cached
+  format_tmap::const_iterator it = formatlistmap.find (formatstring);
+  if (it == formatlistmap.end()) {
+    format_t *formatlistptr = new format_t();
+    parse_formatstring (formatstring, formatlistptr, metadata, getParents);
+    formatlistmap[formatstring] = formatlistptr;
+  }
+}
+
+void browsetoolsclass::load_formatstrings(FilterResponse_t &response, text_tset &metadata,
+                                          bool &getParents, const text_t &classification,
+                                          browsermapclass *browsermap, formatinfo_t &formatinfo, 
+                                          format_tmap &formatlistmap)
+{
+  text_tset cache;
+
+  ResultDocInfo_tarray::iterator thisdoc = response.docInfo.begin();
+  ResultDocInfo_tarray::iterator lastdoc = response.docInfo.end();
+
+  while (thisdoc != lastdoc) {
+
+    if (is_top ((*thisdoc).OID)) {
+      load_formatstring ((*thisdoc).metadata["thistype"].values[0], metadata, 
+			 getParents, classification, browsermap, formatinfo, 
+			 formatlistmap);
+    }
+    
+    // sometimes childtype is not set - why??
+    if ((*thisdoc).metadata.find("childtype") != (*thisdoc).metadata.end()) {
+      text_t &childtype = (*thisdoc).metadata["childtype"].values[0];
+
+      text_tset::const_iterator it = cache.find (childtype);
+      if (it == cache.end()) {
+	load_formatstring (childtype, metadata, getParents, classification,
+			   browsermap, formatinfo, formatlistmap);
+	cache.insert (childtype);
+      }
+    }
+    ++thisdoc;
+  }
+}
+
+void browsetoolsclass::output_parents(FilterResponse_t &response, cgiargsclass &args, 
+                                      browsermapclass *browsermap, formatinfo_t &formatinfo, 
+                                      format_tmap &formatlistmap, const text_t &classification,
+                                      int &tabcount, text_tset &metadata, bool &getParents,
+                                      recptproto *collectproto, displayclass &disp, 
+                                      outconvertclass &outconvert, ostream &textout, 
+                                      ostream &logout)
+{
+  format_t *formatlistptr = NULL;
+  text_t classifytype, formatstring;
+  bool use_table, first = true;
+  ResultDocInfo_tarray::iterator thisparent = response.docInfo.begin();
+  ResultDocInfo_tarray::iterator lastparent = response.docInfo.end();
+  while (thisparent != lastparent) {
+
+    // get classifytype of this level
+    if (is_top ((*thisparent).OID)) classifytype = (*thisparent).metadata["thistype"].values[0];
+    else if (!first && (*(thisparent-1)).metadata.find("childtype") != (*(thisparent-1)).metadata.end()) classifytype = (*(thisparent-1)).metadata["childtype"].values[0];
+    
+    // if we still don't have a classifytype we'll use the default
+    if (classifytype.empty()) {
+      browserclass *bptr = browsermap->get_default_browser ();
+      classifytype = bptr->get_browser_name ();
+    }
+    
+    browserclass *bptr = browsermap->getbrowser (classifytype);
+
+    // get the formatstring if there is one or use the browsers default
+    if (!get_formatstring (classification, classifytype, 
+			   formatinfo.formatstrings, formatstring))
+      formatstring = bptr->get_default_formatstring();
+    
+    // see if it's cached
+    format_tmap::const_iterator it = formatlistmap.find (formatstring);
+    if (it != formatlistmap.end()) formatlistptr = (*it).second;
+    else {
+      logout << "browsetools error\n";
+      return;
+    }
+    
+    use_table = is_table_content (formatlistptr);
+    tabcount += bptr->output_section_group (*thisparent, args, args["c"], tabcount, formatlistptr, 
+					    use_table, metadata, getParents, collectproto, 
+					    disp, outconvert, textout, logout);
+    first = false;
+    ++thisparent;
+  }
+}
+
+void browsetoolsclass::contracted_contents(cgiargsclass &args, int tabcount, bool fulltoc, 
+                                           browsermapclass *browsermap, formatinfo_t &formatinfo, 
+                                           recptproto *collectproto, displayclass &disp, 
+                                           outconvertclass &outconvert, ostream &textout, 
+                                           ostream &logout)
+{
+  FilterResponse_t response;
+  text_tset metadata;
+  bool getParents = false;
+  text_t formatstring;
+  text_tarray parents;
+  text_t OID = args["d"];
+  text_t classification = "Document";
+
+  // if we're not outputting the TOC for a valid OID, then we should be giving
+  // the TOC of a classification
+  if (OID.empty()) {
+    OID = args["cl"];
+    get_top (OID, classification);
+  } 
+  // if we're to give the full TOC of a document, get the parent for the whole
+  // document now
+  else if (fulltoc)
+    get_top (args["cl"], classification);    
+
+  bool haschildren = has_children (OID, args["c"], args["l"], collectproto, logout);
+
+  if ((!args["d"].empty()) && fulltoc)
+    get_parents_array (args["cl"] + ".fc", parents);
+  if (haschildren) get_parents_array (OID + ".fc", parents);
+  else get_parents_array (OID, parents);
+
+  if (!parents.empty()) {
+    // get classifytypes of each parent
+    metadata.insert ("thistype");
+    metadata.insert ("childtype");
+    metadata.insert("mdtype");
+    
+    if (!get_info (parents, args["c"], args["l"], metadata, getParents, collectproto, response, logout))
+      return;
+    
+    // get formatstrings for all parents
+    format_tmap formatlistmap;  
+    load_formatstrings (response, metadata, getParents, classification, 
+			browsermap, formatinfo, formatlistmap);
+
+    if (!get_info (parents, args["c"], args["l"], metadata, getParents, collectproto, response, logout))
+      return;
+    
+    // display each parent
+    output_parents (response, args, browsermap, formatinfo, formatlistmap, 
+		    classification, tabcount, metadata, getParents, 
+		    collectproto, disp, outconvert, textout, logout);
+    
+    metadata.erase (metadata.begin(), metadata.end());
+    
+    // clean up cached format list pointers
+    format_tmap::const_iterator here = formatlistmap.begin();
+    format_tmap::const_iterator end = formatlistmap.end();
+    while (here != end) {
+      delete (*here).second;
+      ++here;
+    }
+  }
+
+  // get childrens classifytype
+  text_t classifytype;
+  int numparents = response.docInfo.size();
+  if (!parents.empty() && (response.docInfo[numparents-1].metadata.find("childtype") != response.docInfo[numparents-1].metadata.end()))
+    classifytype = response.docInfo[numparents-1].metadata["childtype"].values[0];
+  else {
+    // use the default
+    browserclass *bptr = browsermap->get_default_browser ();
+    classifytype = bptr->get_browser_name ();
+  }
+    
+  // load up metadata array with browser defaults
+  browserclass *bptr = browsermap->getbrowser (classifytype);
+  bptr->load_metadata_defaults (metadata);
+
+  if (classifytype == "DateList") {
+    // get the mdtype
+    text_t datelist = "Date";
+    if (!parents.empty() && (response.docInfo[0].metadata.find("mdtype") != response.docInfo[0].metadata.end())) {
+      datelist = response.docInfo[0].metadata["mdtype"].values[0];
+    }
+    args.setarg("dm", datelist);
+    text_tarray dates;
+    splitchar(datelist.begin(), datelist.end(), ',', dates);
+    text_tarray::iterator begin = dates.begin();
+    text_tarray::iterator end = dates.end();
+    while (begin!= end) {
+      metadata.insert(*begin);
+      begin++;
+    }
+    
+  }
+
+  // get the formatstring if there is one or use the browsers default
+  if (!get_formatstring (classification, classifytype, 
+			 formatinfo.formatstrings, formatstring))
+    formatstring = bptr->get_default_formatstring();
+
+  format_t *formatlistptr = new format_t();
+  parse_formatstring (formatstring, formatlistptr, metadata, getParents);
+
+  if (haschildren) 
+    get_children (OID, args["c"], args["l"], metadata, getParents,
+		  collectproto, response, logout);
+  else if (!is_top(OID)) {
+    get_children (OID + ".pr", args["c"], args["l"], metadata, getParents, 
+		  collectproto, response, logout);
+    haschildren = true;
+  }
+
+  // display children
+  if (haschildren) {
+    bool use_table = is_table_content (formatlistptr);
+    bptr->output_section_group (response, args, args["c"], tabcount, formatlistptr, use_table, 
+				metadata, getParents, collectproto, disp, outconvert, 
+				textout, logout);
+  }
+  delete formatlistptr;
+}
+
+/**
+ * This function outputs contents of a classifier to the reader
+ * including parent levels
+ */
+void browsetoolsclass::expand_show_contents(cgiargsclass &args, int tabcount, bool fulltoc,
+                                            browsermapclass *browsermap, formatinfo_t &formatinfo,
+                                            recptproto *collectproto, displayclass &disp,
+                                            outconvertclass &outconvert, ostream &textout, 
+                                            ostream &logout)
+{
+  int coloffset = 0;
+  text_tarray parents;
+  FilterResponse_t response;
+  text_t OID = args["d"];
+  if (OID.empty()) OID = args["cl"];
+
+  bool haschildren = has_children(OID, args["c"], args["l"], collectproto, logout);
+
+  // get parents list
+  if (!is_top(OID)) get_parents_array(OID, parents);
+  if (args["d"].empty() || haschildren || parents.empty()) parents.push_back(OID);
+
+  // if inside a book top title is needed
+  if (!args["d"].empty())
+    {
+      coloffset = 1;
+      text_t classification, classifytype, formatstring, topOID = parents[0];
+      text_tset metadata;
+      format_t *formatlistptr = new format_t();
+      bool use_table, getParents = false;
+		
+      get_top(args["cl"], classification);
+
+      // getting information about top OID
+      metadata.insert("thistype");
+
+      get_info(topOID, args["c"], args["l"], metadata, getParents, collectproto, response, logout);
+      if (!response.docInfo[0].metadata["thistype"].values.empty()) 
+        {
+          classifytype = response.docInfo[0].metadata["thistype"].values[0];
+        }
+
+      browserclass *bptr = browsermap->getbrowser (classifytype);
+
+      if (classifytype.empty())
+        {
+          bptr = browsermap->get_default_browser();
+        }
+
+      // get the formatstring if there is one or use the browsers default
+      if (!get_formatstring(classification, classifytype, formatinfo.formatstrings, formatstring))
+        {
+          formatstring = bptr->get_default_formatstring();
+        }
+
+      parse_formatstring(formatstring, formatlistptr, metadata, getParents);
+
+      metadata.insert("doctype");
+      metadata.insert("haschildren");
+
+      get_info(topOID, args["c"], args["l"], metadata, getParents, collectproto, response, logout);
+
+      // ouput top OID section
+      use_table = is_table_content(formatlistptr);
+      bptr->output_section_group(response.docInfo[0], args, args["c"], tabcount, formatlistptr, use_table,
+                                 metadata, getParents, collectproto, disp, outconvert, textout, logout);
+    }
+
+  recurse_contents_levels(parents, args, coloffset, tabcount, fulltoc, browsermap, 
+                          formatinfo, collectproto, disp, outconvert, textout, logout);
+}
+
+void browsetoolsclass::recurse_contents_levels(text_tarray &parents, cgiargsclass &args, int coloffset, int tabcount,
+                                               bool fulltoc, browsermapclass *browsermap, formatinfo_t &formatinfo,
+                                               recptproto *collectproto, displayclass &disp, outconvertclass &outconvert,
+                                               ostream &textout, ostream &logout)
+{
+  FilterResponse_t response;
+  text_tset metadata;
+  text_t OID, formatstring, classification, classifytype;;
+  bool use_table, getParents = false;
+  int haschildren = 0;
+  format_t *formatlistptr = new format_t();
+
+  // display children for last level
+  if (tabcount == (parents.size() - 1))
+    {
+      // setting metadata fields 
+      metadata.insert ("thistype");
+      metadata.insert ("childtype");
+      metadata.insert ("haschildren");
+
+      OID = parents[tabcount];
+      get_info(OID, args["c"], args["l"], metadata, getParents, collectproto, response, logout);
+      get_top(OID, classification);
+
+      if (!response.docInfo.empty())
+        {
+          haschildren = response.docInfo[0].metadata["haschildren"].values[0].getint();
+        }
+
+      // get childrens classifytype
+      if (!response.docInfo.empty())
+        {
+          classifytype = response.docInfo[0].metadata["childtype"].values[0];
+        }
+      else
+        {
+          // use the default
+          browserclass *bptr = browsermap->get_default_browser();
+          classifytype = bptr->get_browser_name();
+        }
+
+      // load up metadata array with browser defaults
+      browserclass *bptr = browsermap->getbrowser(classifytype);
+      bptr->load_metadata_defaults(metadata);
+
+      // get the formatstring if there is one or use the browsers default
+      if (!get_formatstring(classification, classifytype, formatinfo.formatstrings, formatstring))
+        {
+          formatstring = bptr->get_default_formatstring();
+        }
+
+      parse_formatstring(formatstring, formatlistptr, metadata, getParents);
+
+      if (haschildren) 
+        {
+          get_children(OID, args["c"], args["l"], metadata, getParents,
+                       collectproto, response, logout);
+        }
+      else if (!is_top(OID))
+        {
+          get_children(OID + ".pr", args["c"], args["l"], metadata, getParents, 
+                       collectproto, response, logout);
+          haschildren = true;
+        }
+
+      // display children
+      if (haschildren)
+        {
+          use_table = is_table_content (formatlistptr);
+          bptr->output_section_group(response, args, args["c"], coloffset + tabcount, formatlistptr, use_table, 
+                                     metadata, getParents, collectproto, disp, outconvert, textout, logout);
+        }
+    }
+  else
+    {
+      text_t pOID;
+      OID = parents[tabcount];
+      get_top(OID, classification);
+
+      // load metadata fields
+      metadata.insert("thistype");
+      metadata.insert("childtype");
+      metadata.insert("haschildren");
+      metadata.insert("doctype");
+
+      if (tabcount) pOID = parents[tabcount-1];
+      else pOID = OID;
+      get_info(pOID, args["c"], args["l"], metadata, getParents, collectproto, response, logout);
+
+      // get classifytype of this level
+      if (is_top (pOID)) classifytype = response.docInfo[0].metadata["childtype"].values[0];
+      else classifytype = response.docInfo[0].metadata["thistype"].values[0];
+
+      // if we still don't have a classifytype we'll use the default
+      if (classifytype.empty())
+        {
+          browserclass *bptr = browsermap->get_default_browser();
+          classifytype = bptr->get_browser_name();
+        }
+
+      browserclass *bptr = browsermap->getbrowser (classifytype);
+
+      // get the formatstring if there is one or use the browsers default
+      if (!get_formatstring (classification, classifytype, formatinfo.formatstrings, formatstring))
+        {
+          formatstring = bptr->get_default_formatstring();
+        }
+
+      // parse format string 
+      parse_formatstring(formatstring, formatlistptr, metadata, getParents);
+
+      use_table = is_table_content(formatlistptr);
+
+      get_children(OID, args["c"], args["l"], metadata, getParents, collectproto, response, logout);
+
+      ResultDocInfo_tarray::iterator thissibling = response.docInfo.begin();
+      ResultDocInfo_tarray::iterator lastsibling = response.docInfo.end();
+
+      while (thissibling != lastsibling)
+        {
+          bptr->output_section_group(*thissibling, args, args["c"], coloffset + tabcount, formatlistptr, 
+                                     use_table, metadata, getParents, collectproto, 
+                                     disp, outconvert, textout, logout);
+			
+          if ((*thissibling).OID == parents[tabcount+1])
+            {
+              recurse_contents_levels(parents, args, coloffset, tabcount+1, fulltoc, browsermap,
+                                      formatinfo, collectproto, disp, outconvert,textout, logout);
+            }
+          ++thissibling;
+        }
+    }
+  delete formatlistptr;
+}
+
+/**
+ * This function outputs the contents of a classifier list to the reader - 
+ * the document will in fact be empty, so this does the "real" output
+ */
+void browsetoolsclass::output_toc(cgiargsclass &args, browsermapclass *browsermap,
+                                  formatinfo_t &formatinfo, recptproto *collectproto,
+                                  displayclass &disp, outconvertclass &outconvert,
+                                  ostream &textout, ostream &logout)
+{
+  if (!args["d"].empty() && formatinfo.AllowExtendedOptions) {
+    // If AllowExtendedOptions is set and we're viewing a document,
+    // DocumentButtons, DocumentContent, and DocumentImages are effectively
+    // disabled. We just output the DocumentHeading format string and
+    // return
+    output_titles(args, collectproto, browsermap, formatinfo, disp, outconvert, textout, logout);    
+    return;
+  }
+
+  int tabcount = 0;
+  bool fulltoc = false;
+  text_t cl_top, full_toc;
+  if (args["cl"] != "search") {
+    // see if there's a FullTOC string
+    get_top (args["cl"], cl_top);
+    if (get_formatstring (cl_top, "FullTOC", formatinfo.formatstrings, full_toc))
+      if (full_toc == "true") fulltoc = true;
+  }
+  
+  // get the cover image (if there is one) and the control buttons
+  // if we're inside a book
+  if ((!fulltoc) && (!args["d"].empty())) {
+    if (formatinfo.DocumentImages) {
+      textout << outconvert << "<div class=\"heading_image\">\n";
+      output_cover_image(args, collectproto, disp, outconvert, textout, logout);
+      textout << outconvert << "</div>\n";
+    } else if (formatinfo.DocumentTitles) {
+      textout << outconvert << "<div class=\"heading_title\">\n";
+      output_titles(args, collectproto, browsermap, formatinfo, disp, outconvert, textout, logout);
+      textout << outconvert << "</div>\n";
+    }
+    textout << outconvert << "<div class=\"buttons\" id=\"toc_buttons\">\n"; 
+    if (args["u"] != "1") {
+      output_controls (args, formatinfo.DocumentButtons, collectproto, disp, 
+		       outconvert, textout, logout);
+    }
+    textout << outconvert << "</div>\n\n"; 
+  }
+
+  if (formatinfo.DocumentContents || args["d"].empty()) {
+    if (args["d"].empty()) {
+      textout << outconvert << "<div id=\""<<cl_top<<"\" class=\"toc\">\n";
+    } else {
+      textout << outconvert << "<div class=\"toc\">\n";
+      
+    }
+    if (args.getintarg("gc") == 1) {
+      
+      // expanded table of contents
+      expanded_contents (args, tabcount, fulltoc, browsermap, formatinfo, 
+			 collectproto, disp, outconvert, textout, logout);
+    } else if (args.getintarg("gc") == 2) {
+
+		// expand visible levels of table of contents
+	  expand_show_contents(args, tabcount, fulltoc, browsermap, formatinfo,
+			collectproto, disp, outconvert, textout, logout);
+    } else {
+      
+      // contracted table of contents
+      contracted_contents (args, tabcount, fulltoc, browsermap, formatinfo, 
+			   collectproto, disp, outconvert, textout, logout);
+    }
+    textout << outconvert << "</div>\n";
+  }
+}
+
+void browsetoolsclass::load_extended_options(text_tmap &options, cgiargsclass &args, browsermapclass *browsers, 
+                                             formatinfo_t &formatinfo, recptproto *collectproto, 
+                                             displayclass &disp, outconvertclass &outconvert, ostream &logout)
+{
+  options["DocImage"] = get_cover_image();
+
+#if defined(GSDL_USE_IOS_H)
+  ostrstream *tmpstr = new ostrstream();
+#else
+  ostringstream *tmpstr = new ostringstream(ostringstream::binary);
+#endif
+
+  if (args["gc"] == "1")
+    {
+      expanded_contents(args, 0, false, browsers, formatinfo, collectproto,
+                        disp, outconvert, *tmpstr, logout);
+    }
+  else
+    {
+      contracted_contents(args, 0, false, browsers, formatinfo, 
+                          collectproto, disp, outconvert, *tmpstr, logout);
+    }
+#if defined(GSDL_USE_IOS_H)
+  char *t = tmpstr->str();
+  text_t tmp;
+  tmp.setcarr(t, tmpstr->pcount());
+  delete [] t;
+#else
+  text_t tmp = (char *)(tmpstr->str().c_str());
+#endif
+  int len = tmp.size();
+  char *ctmp = tmp.getcstr();
+  utf8inconvertclass utf82text_t;
+  utf82text_t.setinput(ctmp, len);
+  convertclass::status_t status;
+  utf82text_t.convert(tmp, status);
+  options["DocTOC"] = tmp;
+  delete []ctmp;
+  delete tmpstr;
+
+  options["DocumentButtonDetach"] = "_document:imagedetach_";
+  if (args["hl"] == "1")
+    {
+      options["DocumentButtonHighlight"] = "_document:imagenohighlight_";
+    }
+  else
+    {
+      options["DocumentButtonHighlight"] = "_document:imagehighlight_";
+    }
+  if (args["gc"] == "1")
+    {
+      options["DocumentButtonExpandContents"] = "_document:imagecontracttoc_";
+    }
+  else
+    {
+      options["DocumentButtonExpandContents"] = "_document:imageexpandtoc_";
+    }
+  if (args["gt"] == "1")
+    {
+      options["DocumentButtonExpandText"] = "_document:imagecontracttext_";
+    }
+  else
+    {
+      options["DocumentButtonExpandText"] = "_document:imageexpandtext_";
+    }
+}
Index: trunk/gsdl/src/recpt/browsetoolsclass.h
===================================================================
--- trunk/gsdl/src/recpt/browsetoolsclass.h	(revision 12044)
+++ trunk/gsdl/src/recpt/browsetoolsclass.h	(revision 12044)
@@ -0,0 +1,127 @@
+/**********************************************************************
+ *
+ * browsetools.h --
+ * Copyright (C) 1999  The New Zealand Digital Library Project
+ *
+ * A component of the Greenstone digital library software
+ * from the New Zealand Digital Library Project at the
+ * University of Waikato, New Zealand.
+ *
+ * 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.
+ *
+ *********************************************************************/
+
+
+#ifndef BROWSETOOLSCLASS_H
+#define BROWSETOOLSCLASS_H
+
+#include "gsdlconf.h"
+#include "text_t.h"
+#include "cgiargs.h"
+#include "display.h"
+#include "recptproto.h"
+#include "formattools.h"
+#include "browserclass.h"
+
+class browsetoolsclass
+{
+public:
+  
+  browsetoolsclass();
+  virtual ~browsetoolsclass();
+
+  virtual void output_toc(cgiargsclass &args, browsermapclass *browsermap,
+                          formatinfo_t &formatinfo, recptproto *collectproto,
+                          displayclass &disp, outconvertclass &outconvert,
+                          ostream &textout, ostream &logout);
+
+  virtual text_t get_cover_image();
+
+  virtual void load_extended_options(text_tmap &options, cgiargsclass &args, browsermapclass *browsers, 
+                                     formatinfo_t &formatinfo, recptproto *collectproto, 
+                                     displayclass &disp, outconvertclass &outconvert, ostream &logout);
+
+protected:
+
+  typedef map<text_t, format_t*, lttext_t> format_tmap; 
+
+  virtual void expanded_contents(cgiargsclass &args, int tabcount, bool fulltoc,
+                                 browsermapclass *browsermap, formatinfo_t &formatinfo, 
+                                 recptproto *collectproto, displayclass &disp, 
+                                 outconvertclass &outconvert, ostream &textout, 
+                                 ostream &logout);
+
+  virtual void expand_show_contents(cgiargsclass &args, int tabcount, bool fulltoc,
+                                    browsermapclass *browsermap, formatinfo_t &formatinfo, 
+                                    recptproto *collectproto, displayclass &disp, 
+                                    outconvertclass &outconvert, ostream &textout, 
+                                    ostream &logout);
+
+  virtual void recurse_contents_levels(text_tarray &parents, cgiargsclass &args, int coloffset,
+                                       int tabcount, bool fulltoc, browsermapclass *browsermap,
+                                       formatinfo_t &formatinfo, recptproto *collectproto,
+                                       displayclass &disp, outconvertclass &outconvert,
+                                       ostream &textout, ostream &logout);
+
+  virtual void contracted_contents(cgiargsclass &args, int tabcount, bool fulltoc, 
+                                   browsermapclass *browsermap, formatinfo_t &formatinfo, 
+                                   recptproto *collectproto, displayclass &disp, 
+                                   outconvertclass &outconvert, ostream &textout, 
+                                   ostream &logout);
+
+  virtual void output_titles(cgiargsclass &args, recptproto *collectproto, 
+                             browsermapclass *browsermap, formatinfo_t &formatinfo,
+                             displayclass &disp, outconvertclass &outconvert,
+                             ostream &textout, ostream &logout);
+
+  virtual void output_controls(cgiargsclass &args, const text_tarray &ibuttons,
+                               recptproto *collectproto, displayclass &disp, 
+                               outconvertclass &outconvert, ostream &textout, 
+                               ostream &logout);
+  
+  virtual void output_cover_image(cgiargsclass &args, recptproto *collectproto, 
+                                  displayclass &disp, outconvertclass &outconvert, 
+                                  ostream &textout, ostream &logout);
+
+  virtual void recurse_contents(ResultDocInfo_t &section, cgiargsclass &args, bool fulltoc,
+                                browserclass *bptr, text_tset &metadata, bool &getParents, 
+                                format_t *formatlistptr, format_tmap &formatlistmap, 
+                                formatinfo_t &formatinfo, browsermapclass *browsermap, 
+                                int tabcount, recptproto *collectproto, displayclass &disp, 
+                                outconvertclass &outconvert, ostream &textout, ostream &logout);
+
+  virtual void load_formatstring(const text_t &classifytype, text_tset &metadata,
+                                 bool &getParents, const text_t &classification, 
+                                 browsermapclass *browsermap, formatinfo_t &formatinfo,
+                                 format_tmap &formatlistmap);
+
+  virtual void load_formatstrings(FilterResponse_t &response, text_tset &metadata,
+                                  bool &getParents, const text_t &classification,
+                                  browsermapclass *browsermap, formatinfo_t &formatinfo, 
+                                  format_tmap &formatlistmap);
+
+  virtual void output_parents(FilterResponse_t &response, cgiargsclass &args, 
+                              browsermapclass *browsermap, formatinfo_t &formatinfo, 
+                              format_tmap &formatlistmap, const text_t &classification,
+                              int &tabcount, text_tset &metadata, bool &getParents,
+                              recptproto *collectproto, displayclass &disp, 
+                              outconvertclass &outconvert, ostream &textout, 
+                              ostream &logout);
+
+
+
+};
+
+#endif
Index: trunk/gsdl/src/recpt/documentaction.cpp
===================================================================
--- trunk/gsdl/src/recpt/documentaction.cpp	(revision 12019)
+++ trunk/gsdl/src/recpt/documentaction.cpp	(revision 12044)
@@ -27,5 +27,4 @@
 
 #include "documentaction.h"
-#include "browsetools.h"
 #include "OIDtools.h"
 #include "querytools.h"
@@ -33,8 +32,8 @@
 #include "gsdltools.h"
 #include "highlighttext.h"
+#include "browsetoolsclass.h"
 
 documentaction::documentaction () {
   recpt = NULL;
-
 
   // this action uses cgi variables "a", "d", "cl",
@@ -181,5 +180,6 @@
 }
 
-documentaction::~documentaction () {
+documentaction::~documentaction()
+{
 }
 
@@ -984,9 +984,9 @@
 
 
-bool documentaction::do_action (cgiargsclass &args, recptprotolistclass *protos, 
-				browsermapclass *browsers, displayclass &disp, 
-				outconvertclass &outconvert, ostream &textout, 
-				ostream &logout) {
- 
+bool documentaction::do_action(cgiargsclass &args, recptprotolistclass *protos, 
+                               browsermapclass *browsers, displayclass &disp, 
+                               outconvertclass &outconvert, ostream &textout, 
+                               ostream &logout)
+{
   // must have a valid collection server
   recptproto *collectproto = protos->getrecptproto (args["c"], logout);
@@ -1036,6 +1036,7 @@
       
     // output the table of contents
-    output_toc (args, browsers, formatinfo, collectproto, 
-		disp, outconvert, textout, logout);
+    browsetoolsclass b;
+    b.output_toc(args, browsers, formatinfo, collectproto, 
+                 disp, outconvert, textout, logout);
    
     if (formatinfo.DocumentArrowsTop && !args["d"].empty()) {
@@ -1091,6 +1092,7 @@
 
       if (formatinfo.AllowExtendedOptions) {
-	load_extended_options(options, args, browsers, formatinfo, 
-			      collectproto, disp, outconvert, logout);
+        browsetoolsclass b;
+	b.load_extended_options(options, args, browsers, formatinfo, 
+                                collectproto, disp, outconvert, logout);
       }
       
Index: trunk/gsdl/src/recpt/vlistbrowserclass.cpp
===================================================================
--- trunk/gsdl/src/recpt/vlistbrowserclass.cpp	(revision 12019)
+++ trunk/gsdl/src/recpt/vlistbrowserclass.cpp	(revision 12044)
@@ -27,5 +27,5 @@
 #include <assert.h>
 #include "OIDtools.h"
-#include "browsetools.h"
+#include "browsetoolsclass.h"
 
 vlistbrowserclass::vlistbrowserclass () {
@@ -63,14 +63,14 @@
 }
 
-int vlistbrowserclass::output_section_group (ResultDocInfo_t &section, cgiargsclass &args,
-					     const text_t &collection, int colnumber, 
-					     format_t *formatlistptr, bool use_table, 
-					     text_tset &/*metadata*/, bool &/*getParents*/, 
-					     recptproto * collectproto, displayclass &disp, 
-					     outconvertclass &outconvert, ostream &textout, 
-					     ostream& logout) {
-
+int vlistbrowserclass::output_section_group(ResultDocInfo_t &section, cgiargsclass &args,
+                                            const text_t &collection, int colnumber, 
+                                            format_t *formatlistptr, bool use_table, 
+                                            text_tset &metadata, bool &getParents, 
+                                            recptproto * collectproto, displayclass &disp, 
+                                            outconvertclass &outconvert, ostream &textout, 
+                                            ostream& logout)
+{
+  browsetoolsclass btools;
   text_t link, icon;
-
   text_t collink = collection;
 
@@ -106,5 +106,5 @@
   if (highlight) options["highlight"] = "1";
   else options["highlight"] = "0";
-  options["DocImage"] = get_cover_image();
+  options["DocImage"] = btools.get_cover_image();
   textout << outconvert << disp 
 	  << get_formatted_string (collection, collectproto, 
@@ -121,12 +121,13 @@
 }
 
-int vlistbrowserclass::output_section_group (FilterResponse_t &sections, cgiargsclass &args,
-					     const text_t &collection, int colnumber, 
-					     format_t *formatlistptr, bool use_table, 
-					     text_tset &/*metadata*/, bool &/*getParents*/, 
-					     recptproto * collectproto, displayclass &disp, 
-					     outconvertclass &outconvert, ostream &textout, 
-					     ostream& logout) {
-
+int vlistbrowserclass::output_section_group(FilterResponse_t &sections, cgiargsclass &args,
+                                            const text_t &collection, int colnumber, 
+                                            format_t *formatlistptr, bool use_table, 
+                                            text_tset &/*metadata*/, bool &/*getParents*/, 
+                                            recptproto * collectproto, displayclass &disp, 
+                                            outconvertclass &outconvert, ostream &textout, 
+                                            ostream& logout)
+{
+  browsetoolsclass btools;
   text_t link, icon;
   text_t &arg_d = args["d"];
@@ -168,5 +169,5 @@
   options["icon"] = icon;
   options["highlight"] = "0";
-  options["DocImage"] = get_cover_image();
+  options["DocImage"] = btools.get_cover_image();
   
   if ( thissection != endsection ) { // only if there are results (else corrupts display)
@@ -198,5 +199,5 @@
     if (highlight) options["highlight"] = "1";
     else options["highlight"] = "0";
-    options["DocImage"] = get_cover_image();
+    options["DocImage"] = btools.get_cover_image();
     
     textout << outconvert << disp 
Index: trunk/gsdl/src/recpt/win32.mak
===================================================================
--- trunk/gsdl/src/recpt/win32.mak	(revision 12019)
+++ trunk/gsdl/src/recpt/win32.mak	(revision 12044)
@@ -55,5 +55,5 @@
 LDFLAGS = 
 
-DEFS = -D__WIN32__ -DHAVE_CONFIG_H -DPARADOCNUM -D_LITTLE_ENDIAN -DSHORT_SUFFIX -D_CRT_SECURE_NO_DEPRECATE
+DEFS = -D__WIN32__ -DHAVE_CONFIG_H -DPARADOCNUM -D_LITTLE_ENDIAN -DSHORT_SUFFIX -D_CRT_SECURE_NO_DEPRECATE -DGSDL_NOCACHE
 INCLUDES = -I"$(GSDLHOME)\src\recpt" -I"$(GSDLHOME)\lib" -I"$(GSDLHOME)\src\colservr" \
 	   -I"$(GSDLHOME)\packages\mg" -I"$(GSDLHOME)\packages\mg\lib" \
@@ -107,5 +107,5 @@
 
 COMMONHEADERS = receptionist.h cgiargs.h action.h browserclass.h \
-                converter.h recptconfig.h cgiutils.h OIDtools.h browsetools.h \
+                converter.h recptconfig.h cgiutils.h OIDtools.h browsetoolsclass.h \
 		statusaction.h pageaction.h comtypes.h recptproto.h pingaction.h \
 		queryaction.h documentaction.h extlinkaction.h htmlutils.h \
@@ -123,5 +123,5 @@
 
 COMMONSOURCES = receptionist.cpp cgiargs.cpp action.cpp browserclass.cpp \
-                converter.cpp recptconfig.cpp cgiutils.cpp OIDtools.cpp browsetools.cpp \
+                converter.cpp recptconfig.cpp cgiutils.cpp OIDtools.cpp browsetoolsclass.cpp \
 		statusaction.cpp pageaction.cpp comtypes.cpp \
 		recptproto.cpp pingaction.cpp queryaction.cpp documentaction.cpp \
@@ -140,5 +140,5 @@
 
 COMMONOBJECTS = receptionist.obj cgiargs.obj action.obj browserclass.obj \
-                converter.obj recptconfig.obj cgiutils.obj OIDtools.obj browsetools.obj \
+                converter.obj recptconfig.obj cgiutils.obj OIDtools.obj browsetoolsclass.obj \
 		statusaction.obj pageaction.obj comtypes.obj recptproto.obj \
 		pingaction.obj queryaction.obj documentaction.obj extlinkaction.obj \
