Index: gsdl/trunk/src/recpt/dynamicclassifieraction.cpp
===================================================================
--- gsdl/trunk/src/recpt/dynamicclassifieraction.cpp	(revision 15947)
+++ gsdl/trunk/src/recpt/dynamicclassifieraction.cpp	(revision 15949)
@@ -149,11 +149,190 @@
   }
 
+  // Produce the page
   text_t metadata_element_name = cinfo->dynamic_classifiers[arg_dcl];
+  if (args["dcn"].empty())
+  {
+    // Simple case for the top-level page
+    output_top_level_page (metadata_element_name, args, collectproto, browsers, disp, outconvert, textout, logout);
+  }
+  else
+  {
+    // More complex case for an internal page
+    output_internal_page (metadata_element_name, args, collectproto, browsers, disp, outconvert, textout, logout);
+  }
+
+  textout << outconvert << disp << "_document:footer_\n";
+  return true;
+}
+
+
+void dynamicclassifieraction::output_top_level_page (text_t metadata_element_name, cgiargsclass &args,
+						     recptproto *collectproto, browsermapclass *browsers,
+						     displayclass &disp, outconvertclass &outconvert,
+						     ostream &textout, ostream &logout)
+{
+  // Get all the metadata values for the specified element (these become the classifier nodes at the top level)
+  FilterResponse_t metadata_values_response;
+  get_metadata_values (metadata_element_name, "", args["c"], collectproto, metadata_values_response, logout);
+
+  // Deal with any hierarchical metadata values
+  map<text_t, int, lttext_t> classifier_nodes;
+  ResultDocInfo_tarray::iterator metadata_value_iterator = metadata_values_response.docInfo.begin();
+  while (metadata_value_iterator != metadata_values_response.docInfo.end())
+  {
+    // Is this metadata value hierarchical?
+    text_t metadata_value = (*metadata_value_iterator).OID;
+    text_t::iterator hierarchy_split_position = findchar(metadata_value.begin(), metadata_value.end(), '|');
+    if (hierarchy_split_position != metadata_value.end())
+    {
+      // Yes, so use the first part of the hierarchy only
+      metadata_value = substr(metadata_value.begin(), hierarchy_split_position);
+    }
+
+    // Create a node for this metadata value if we haven't seen it before
+    if (classifier_nodes.find(metadata_value) == classifier_nodes.end())
+    {
+      classifier_nodes[metadata_value] = 0;
+    }
+
+    // Increment the occurrence count
+    classifier_nodes[metadata_value] += (*metadata_value_iterator).result_num;
+
+    metadata_value_iterator++;
+  }
+
+  // Display the top-level classifier nodes
+  map<text_t, int, lttext_t>::iterator classifier_nodes_iterator = classifier_nodes.begin();
+  while (classifier_nodes_iterator != classifier_nodes.end())
+  {
+    text_t classifier_node_OID = (*classifier_nodes_iterator).first;
+    text_t classifier_node_label = (*classifier_nodes_iterator).first;
+    int classifier_node_numleafdocs = (*classifier_nodes_iterator).second;
+    output_classifier_node (classifier_node_OID, classifier_node_label, classifier_node_numleafdocs, 0, args, collectproto, browsers, disp, outconvert, textout, logout);
+    classifier_nodes_iterator++;
+  }
+}
+
+
+void dynamicclassifieraction::output_internal_page (text_t metadata_element_name, cgiargsclass &args,
+						    recptproto *collectproto, browsermapclass *browsers,
+						    displayclass &disp, outconvertclass &outconvert,
+						    ostream &textout, ostream &logout)
+{
+  text_t arg_dcn = args["dcn"];
+  text_t classifier_node_metadata_value = arg_dcn;
+  int node_indent = 0;
+
+  // Get all the classifier nodes at this level
+  text_t metadata_value_filter = classifier_node_metadata_value + "|*";
+  FilterResponse_t metadata_values_response;
+  get_metadata_values (metadata_element_name, metadata_value_filter, args["c"], collectproto, metadata_values_response, logout);
+
+  // Get all the documents at this level
+  FilterResponse_t document_OIDs_response;
+  get_documents_with_metadata_value (metadata_element_name, classifier_node_metadata_value, "dls.Title", args["c"], collectproto, document_OIDs_response, logout);
+
+  // Check there are some classifier nodes or some documents at this level, otherwise the "dcn" argument was invalid
+  if (metadata_values_response.docInfo.empty() && document_OIDs_response.docInfo.empty())
+  {
+    textout << outconvert << disp << "Error: Invalid dcn value \"" << arg_dcn << "\".\n";
+    return;
+  }
+
+  // Determine the parent classifier nodes
+  text_tarray parent_classifier_node_labels;
+  splitchar(classifier_node_metadata_value.begin(), classifier_node_metadata_value.end(), '|', parent_classifier_node_labels);
+
+  // Display the parent classifier nodes
+  text_t parent_classifier_node_OID = "";
+  text_tarray::iterator parent_classifier_node_labels_iterator = parent_classifier_node_labels.begin();
+  while (parent_classifier_node_labels_iterator != parent_classifier_node_labels.end())
+  {
+    parent_classifier_node_OID += *parent_classifier_node_labels_iterator;
+    text_t parent_classifier_node_label = *parent_classifier_node_labels_iterator;
+    text_t parent_classifier_node_numleafdocs = "?";
+    output_classifier_node (parent_classifier_node_OID, parent_classifier_node_label, parent_classifier_node_numleafdocs, node_indent, args, collectproto, browsers, disp, outconvert, textout, logout);
+    node_indent++;
+
+    parent_classifier_node_labels_iterator++;
+  }
+
+  // Display the classifier nodes at this level
+  map<text_t, int, lttext_t> classifier_nodes;
+  ResultDocInfo_tarray::iterator metadata_value_iterator = metadata_values_response.docInfo.begin();
+  while (metadata_value_iterator != metadata_values_response.docInfo.end())
+  {
+    text_t metadata_value = (*metadata_value_iterator).OID;
+
+    if (starts_with(metadata_value, arg_dcn + "|"))
+    {
+      metadata_value = substr(metadata_value.begin() + (arg_dcn + "|").size(), metadata_value.end());
+    }
+
+    // Is this metadata value hierarchical?
+    text_t::iterator hierarchy_split_position = findchar(metadata_value.begin(), metadata_value.end(), '|');
+    if (hierarchy_split_position != metadata_value.end())
+    {
+      // Yes, so split off the first part of the hierarchy for the classifier node
+      metadata_value = substr(metadata_value.begin(), hierarchy_split_position);
+    }
+
+    // Create a node for this metadata value if we haven't seen it before
+    if (classifier_nodes.find(metadata_value) == classifier_nodes.end())
+    {
+      classifier_nodes[metadata_value] = 0;
+    }
+
+    // Increment the occurrence count
+    classifier_nodes[metadata_value] += (*metadata_value_iterator).result_num;
+
+    metadata_value_iterator++;
+  }
+
+  // Display the classifier nodes at this level
+  map<text_t, int, lttext_t>::iterator classifier_nodes_iterator = classifier_nodes.begin();
+  while (classifier_nodes_iterator != classifier_nodes.end())
+  {
+    text_t classifier_node_OID = parent_classifier_node_OID + "|" + (*classifier_nodes_iterator).first;
+    text_t classifier_node_label = (*classifier_nodes_iterator).first;
+    int classifier_node_numleafdocs = (*classifier_nodes_iterator).second;
+    output_classifier_node (classifier_node_OID, classifier_node_label, classifier_node_numleafdocs, node_indent, args, collectproto, browsers, disp, outconvert, textout, logout);
+    classifier_nodes_iterator++;
+  }
+
+  // Display the documents at this level
+  text_tarray document_OIDs;
+  ResultDocInfo_tarray::iterator document_OID_iterator = document_OIDs_response.docInfo.begin();
+  while (document_OID_iterator != document_OIDs_response.docInfo.end())
+  {
+    document_OIDs.push_back ((*document_OID_iterator).OID);
+    document_OID_iterator++;
+  }
+
+  output_document_nodes (document_OIDs, node_indent, args, collectproto, browsers, disp, outconvert, textout, logout);
+}
+
+
+void dynamicclassifieraction::output_classifier_node (text_t classifier_node_OID, text_t classifier_node_label,
+						      text_t classifier_node_numleafdocs, int classifier_node_indent,
+						      cgiargsclass &args, recptproto *collectproto,
+						      browsermapclass *browsers, displayclass &disp,
+						      outconvertclass &outconvert, ostream &textout,
+						      ostream &logout)
+{
+  // Generate the ResultDocInfo_t containing the information for the classifier node
+  ResultDocInfo_t classifier_node;
+  classifier_node.OID = classifier_node_OID;
+  classifier_node.metadata["doctype"].values.push_back ("classify");
+  classifier_node.metadata["haschildren"].values.push_back ("1");
+  classifier_node.metadata["numleafdocs"].values.push_back (classifier_node_numleafdocs);
+  classifier_node.metadata["Title"].values.push_back (classifier_node_label);
+
+  // Get the format statement for this classifier if there is one, or use the browser's default otherwise
+  text_t formatstring;
   text_t classifier_type = "VList";
   browserclass *bptr = browsers->getbrowser (classifier_type);
-
-  // Get the formatstring if there is one, or use the browser's default otherwise
-  text_t formatstring;
-  if (!get_formatstring (arg_dcl, classifier_type, cinfo->format, formatstring))
+  ColInfoResponse_t *cinfo = recpt->get_collectinfo_ptr (collectproto, args["c"], logout);
+  if (!get_formatstring (args["dcl"], classifier_type, cinfo->format, formatstring))
   {
     formatstring = bptr->get_default_formatstring();
@@ -165,102 +344,35 @@
   bool use_table = is_table_content (formatlistptr);
 
-  // Check if a dynamic classifier node has been specified
-  text_t arg_dcn = args["dcn"];
-  if (arg_dcn.empty())
-  {
-    // No, so display the top-level classifier page, containing all the metadata values for the specified element
-    FilterResponse_t metadata_values_response;
-    get_metadata_values (metadata_element_name, args["c"], collectproto, metadata_values_response, logout);
-
-    // Deal with hierarchical metadata values
-    map<text_t, int, lttext_t> classifier_nodes;
-    ResultDocInfo_tarray::iterator metadata_value_iterator = metadata_values_response.docInfo.begin();
-    while (metadata_value_iterator != metadata_values_response.docInfo.end())
-    {
-      text_t metadata_value = (*metadata_value_iterator).OID;
-
-      // Is this metadata value hierarchical?
-      text_t::iterator hierarchy_split_position = findchar(metadata_value.begin(), metadata_value.end(), '|');
-      if (hierarchy_split_position != metadata_value.end())
-      {
-	// Yes, so split off the first part of the hierarchy for the classifier node
-	metadata_value = substr(metadata_value.begin(), hierarchy_split_position);
-      }
-
-      // Create a node for this metadata value if we haven't seen it before
-      if (classifier_nodes.find(metadata_value) == classifier_nodes.end())
-      {
-	classifier_nodes[metadata_value] = 0;
-      }
-
-      // Increment the occurrence count
-      classifier_nodes[metadata_value] += (*metadata_value_iterator).result_num;
-
-      metadata_value_iterator++;
-    }
-
-    // Create the structure containing the classifer nodes to pass to output_section_group(), with the right info
-    FilterResponse_t classifier_nodes_response;
-    map<text_t, int, lttext_t>::iterator classifier_nodes_iterator = classifier_nodes.begin();
-    while (classifier_nodes_iterator != classifier_nodes.end())
-    {
-      ResultDocInfo_t classifier_node;
-      classifier_node.OID = (*classifier_nodes_iterator).first;
-
-      // Add metadata necessary for output_section_group() to display the results as classifier nodes
-      classifier_node.metadata["doctype"].values.push_back ("classify");
-      classifier_node.metadata["haschildren"].values.push_back ("1");
-      classifier_node.metadata["numleafdocs"].values.push_back ((*classifier_nodes_iterator).second);
-      classifier_node.metadata["Title"].values.push_back ((*classifier_nodes_iterator).first);
-
-      classifier_nodes_response.docInfo.push_back (classifier_node);
-      classifier_nodes_iterator++;
-    }
-
-    // Display the classifier nodes
-    bptr->output_section_group (classifier_nodes_response, args, args["c"], 0, formatlistptr, use_table, metadata, getParents, collectproto, disp, outconvert, textout, logout);
-  }
-  else
-  {
-    // Yes, so get all the documents that fall under this node
-    text_t metadata_value = arg_dcn;
-    FilterResponse_t document_OIDs_response;
-    get_documents_with_metadata_value (metadata_element_name, metadata_value, "dls.Title", args["c"], collectproto, document_OIDs_response, logout);
-
-    // Check the metadata value is valid
-    if (document_OIDs_response.docInfo.empty())
-    {
-      textout << outconvert << disp << "Error: No documents have metadata value \"" << arg_dcn << "\".\n";
-      textout << outconvert << disp << "_document:footer_\n";
-      return true;
-    }
-
-    // Make an array of matching document OIDs
-    text_tarray document_OIDs;
-    ResultDocInfo_tarray::iterator document_OID_iterator = document_OIDs_response.docInfo.begin();
-    while (document_OID_iterator != document_OIDs_response.docInfo.end())
-    {
-      document_OIDs.push_back ((*document_OID_iterator).OID);
-      document_OID_iterator++;
-    }
-
-    // Display the classifier node
-    ResultDocInfo_t classifier_node;
-    classifier_node.OID = arg_dcn;
-    classifier_node.metadata["doctype"].values.push_back("classify");
-    classifier_node.metadata["haschildren"].values.push_back("1");
-    classifier_node.metadata["numleafdocs"].values.push_back(document_OIDs.size());
-    classifier_node.metadata["Title"].values.push_back(classifier_node.OID);
-    bptr->output_section_group (classifier_node, args, args["c"], 0, formatlistptr, use_table, metadata, getParents, collectproto, disp, outconvert, textout, logout);
-
-    // Request the necessary metadata for the documents under this node
-    FilterResponse_t document_info_response;
-    get_info (document_OIDs, args["c"], args["l"], metadata, getParents, collectproto, document_info_response, logout);
-
-    // Display the document nodes
-    bptr->output_section_group (document_info_response, args, args["c"], 1, formatlistptr, use_table, metadata, getParents, collectproto, disp, outconvert, textout, logout);
-  }
-
-  textout << outconvert << disp << "_document:footer_\n";
-  return true;
-}
+  // Display the classifier node
+  bptr->output_section_group (classifier_node, args, args["c"], classifier_node_indent, formatlistptr, use_table, metadata, getParents, collectproto, disp, outconvert, textout, logout);
+}
+
+
+void dynamicclassifieraction::output_document_nodes (text_tarray document_OIDs, int document_nodes_indent,
+						     cgiargsclass &args, recptproto *collectproto,
+						     browsermapclass *browsers, displayclass &disp,
+						     outconvertclass &outconvert, ostream &textout,
+						     ostream &logout)
+{
+  // Get the format statement for this classifier if there is one, or use the browser's default otherwise
+  text_t formatstring;
+  text_t classifier_type = "VList";
+  browserclass *bptr = browsers->getbrowser (classifier_type);
+  ColInfoResponse_t *cinfo = recpt->get_collectinfo_ptr (collectproto, args["c"], logout);
+  if (!get_formatstring (args["dcl"], classifier_type, cinfo->format, formatstring))
+  {
+    formatstring = bptr->get_default_formatstring();
+  }
+  format_t *formatlistptr = new format_t();
+  text_tset metadata;
+  bool getParents = false;
+  parse_formatstring (formatstring, formatlistptr, metadata, getParents);
+  bool use_table = is_table_content (formatlistptr);
+
+  // Request the necessary metadata for the documents
+  FilterResponse_t document_OIDs_response;
+  get_info (document_OIDs, args["c"], args["l"], metadata, getParents, collectproto, document_OIDs_response, logout);
+
+  // Display the document nodes
+  bptr->output_section_group (document_OIDs_response, args, args["c"], document_nodes_indent, formatlistptr, use_table, metadata, getParents, collectproto, disp, outconvert, textout, logout);
+}
Index: gsdl/trunk/src/recpt/dynamicclassifieraction.h
===================================================================
--- gsdl/trunk/src/recpt/dynamicclassifieraction.h	(revision 15947)
+++ gsdl/trunk/src/recpt/dynamicclassifieraction.h	(revision 15949)
@@ -62,4 +62,27 @@
 		  outconvertclass &outconvert, ostream &textout, 
 		  ostream &logout);
+
+  void output_top_level_page (text_t metadata_element_name, cgiargsclass &args,
+			      recptproto *collectproto, browsermapclass *browsers,
+			      displayclass &disp, outconvertclass &outconvert,
+			      ostream &textout, ostream &logout);
+
+  void output_internal_page (text_t metadata_element_name, cgiargsclass &args,
+			     recptproto *collectproto, browsermapclass *browsers,
+			     displayclass &disp, outconvertclass &outconvert,
+			     ostream &textout, ostream &logout);
+
+  void output_classifier_node (text_t classifier_node_OID, text_t classifier_node_label,
+			       text_t classifier_node_numleafdocs, int classifier_node_indent,
+			       cgiargsclass &args, recptproto *collectproto,
+			       browsermapclass *browsers, displayclass &disp,
+			       outconvertclass &outconvert, ostream &textout,
+			       ostream &logout);
+
+  void output_document_nodes (text_tarray document_OIDs, int document_nodes_indent,
+			      cgiargsclass &args, recptproto *collectproto,
+			      browsermapclass *browsers, displayclass &disp,
+			      outconvertclass &outconvert, ostream &textout,
+			      ostream &logout);
 };
 
