Index: apachesolr.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/apachesolr/apachesolr.module,v
retrieving revision 1.1.2.12.2.167
diff -u -r1.1.2.12.2.167 apachesolr.module
--- apachesolr.module	14 Oct 2009 19:08:19 -0000	1.1.2.12.2.167
+++ apachesolr.module	21 Oct 2009 18:55:54 -0000
@@ -1444,8 +1444,11 @@
     drupal_add_js(drupal_get_path('module', 'apachesolr') . '/apachesolr.js');
     // Split items array into displayed and hidden.
     $hidden_items = array_splice($items, $display_limit);
-    foreach ($hidden_items as $link) {
-      $items[] = array('data' => $link, 'class' => 'apachesolr-hidden-facet');
+    foreach ($hidden_items as $hidden_item) {
+      if (!is_array($hidden_item)) {
+        $hidden_item = array('data' => $hidden_item);
+      }
+      $items[] = $hidden_item + array('class' => 'apachesolr-hidden-facet');
     }
   }
   $admin_link = '';
Index: apachesolr_search.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/apachesolr/apachesolr_search.module,v
retrieving revision 1.1.2.6.2.115
diff -u -r1.1.2.6.2.115 apachesolr_search.module
--- apachesolr_search.module	14 Oct 2009 13:28:40 -0000	1.1.2.6.2.115
+++ apachesolr_search.module	21 Oct 2009 18:57:56 -0000
@@ -569,6 +569,7 @@
         // Get information needed by the taxonomy blocks about limits.
         $initial_limits = variable_get('apachesolr_facet_query_initial_limits', array());
         $limit_default = variable_get('apachesolr_facet_query_initial_limit_default', 10);
+        $reflect_hierarchy = apachesolr_search_get_hierarchical_vocabularies();
 
         // Handle taxonomy vocabulary facets
         if ((strpos($delta, 'im_vid_') === 0) && module_exists('taxonomy')) {
@@ -576,71 +577,88 @@
           if (is_object($response->facet_counts->facet_fields->$delta)) {
             $contains_active = FALSE;
             $terms = array();
+            $vid = substr($delta, 7);
+            if (is_numeric($vid)) {
+              $vocab = taxonomy_vocabulary_load($vid);
+              $terms = array();          
+              foreach ($response->facet_counts->facet_fields->$delta as $tid => $count) {
+                if ($tid == '_empty_') {
+                  // TODO - for now we don't handle facet missing.
+                  continue;
+                }
+                $unclick_link = '';
+                unset($active);
+                $parents = array();
+                if ($reflect_hierarchy[$delta]) {
+                  $parents = taxonomy_get_parents_all($tid);
+                  if (!empty($parents[1]) && !$query->has_filter('tid', $parents[1]->tid)) {
+                    continue;
+                  }
+                }
+                else if ($term = taxonomy_get_term($tid)) {
+                  $parents[] = $term;
+                }
 
-            foreach ($response->facet_counts->facet_fields->$delta as $tid => $count) {
-              $options = array();
-              if ($tid == '_empty_') {
-                // TODO - for now we don't handle facet missing.
-                continue;
-              }
-              $unclick_link = '';
-              unset($active);
-              $term = taxonomy_get_term($tid);
-              $new_query = clone $query;
-              if ($active = $query->has_filter('tid', $tid)) {
-                $contains_active = TRUE;
-                $new_query->remove_filter('tid', $term->tid);
-                $options['query'] = $new_query->get_url_queryvalues();
-                $link = theme('apachesolr_unclick_link', $term->name, $new_query->get_path(), $options);
-              }
-              else {
-                $new_query->add_filter('tid', $term->tid);
-                $options['query'] = $new_query->get_url_queryvalues();
-                $link = theme('apachesolr_facet_link', $term->name, $new_query->get_path(), $options, $count, $active, $response->response->numFound);
-              }
-              $countsort = $count == 0 ? '' : 1 / $count;
-              // if numdocs == 1 and !active, don't add.
-              if ($response->response->numFound > 1 || $active) {
-                $terms[$term->vid][$active ? $countsort . $term->name : 1 + $countsort . $term->name] = $link;
+                $parents = array_reverse($parents);
+
+                foreach ($parents as $key => $term) {
+                  $parents[$key] = $term;
+                }
+
+                $options = array();
+                $active = $query->has_filter('tid', $tid);
+                if ($active) {
+                  $remove = array(array('#name' => 'tid', '#value' => $tid));
+
+                  if ($reflect_hierarchy[$delta]) {
+                    $childs = taxonomy_get_tree($vid, $tid);
+                    foreach ($childs as $child) {
+                      $remove[] = array('#name' => 'tid', '#value' => $child->tid);
+                    }
+                  }
+
+                  $link = apachesolr_search_get_unclick_link($query, $term->name, $remove);
+                }
+                else {
+                  $new_query = clone $query;
+                  $new_query->add_filter('tid', $tid);
+                  $options = array('query' => $new_query->get_url_queryvalues());
+                  $link = theme('apachesolr_facet_link', $term->name, $new_query->get_path(), $options, $count, $active, $response->response->numFound);
+                }
+
+                // if numdocs == 1 and !active, don't add.
+                if ($response->response->numFound > 1 || $active) {
+                  $sort_key = '';
+                  $term = NULL;
+                  foreach ($parents as $term) {
+                    $count = $response->facet_counts->facet_fields->$delta->{$term->tid};
+                    $countsort = $count == 0 ? '' : 1 / $count;
+                    $countsort = $query->has_filter('tid', $term->tid) ? $countsort : 1 + $countsort;
+                    $sort_key .= ($sort_key ? '|' : '') . $countsort . ':' . $term->name;
+                  }
+                 $terms[$term->vid][$sort_key] = $link;
+                }
               }
             }
-          }
-          $vid = substr($delta, 7);
-          $vocab = taxonomy_vocabulary_load($vid);
-          if (is_numeric($vid) && is_array($terms) && isset($terms[$vid]) && is_array($terms[$vid])) {
-            ksort($terms[$vid]);
-            $limit = isset($initial_limits['apachesolr_search'][$delta]) ? $initial_limits['apachesolr_search'][$delta] : $limit_default;
-            return array(
-              'subject' => t('Filter by @name', array('@name' => $vocab->name)),
-              'content' => theme('apachesolr_facet_list', $terms[$vid], $limit),
-            );
+            // Process all terms into an item list
+            if (is_array($terms) && isset($terms[$vid]) && is_array($terms[$vid])) {
+
+              // Create array of nested items
+              $items = apachesolr_search_nested_facet_items($terms[$vid]);
+              $limit = isset($initial_limits['apachesolr_search'][$delta]) ? $initial_limits['apachesolr_search'][$delta] : $limit_default;
+              return array(
+                'subject' => t('Filter by @name', array('@name' => $vocab->name)),
+                'content' => theme('apachesolr_facet_list', $items, $limit),
+              );
+
+            }
           }
           return;
         }
 
         switch ($delta) {
           case 'currentsearch':
-            $fields = $query->get_filters();
-            $path = $query->get_path();
-            $options = array();
-            if (!$fields) {
-              $options['attributes']['class'] = 'active';
-            }
-            $links[] = apachesolr_l($query->get_query_basic(), $path, $options);
-            foreach($fields as $field) {
-              if ($field['#name']) {
-                $new_query = clone $query;
-                $new_query->remove_filter($field['#name'], $field['#value']);
-                $options['query'] = $new_query->get_url_queryvalues();
-                $fielddisplay = theme("apachesolr_breadcrumb_". $field['#name'], $field['#value']);
-                if (!$fielddisplay) {
-                  $fielddisplay = $field['#value'];
-                }
-                $links[] = theme('apachesolr_unclick_link', $fielddisplay, $new_query->get_path(), $options);
-              }
-            }
-            $content = theme('apachesolr_currentsearch', $response->response->numFound, $links);
-            return array('subject' => t('Current search'), 'content' => $content);
+            return apachesolr_search_currentsearch_block($query);
           case 'is_book_bid':
             return apachesolr_facet_block($response, $query, 'apachesolr_search', $delta, $delta, t('Filter by book'), 'apachesolr_search_get_book');
           case 'language':
@@ -683,6 +701,43 @@
 }
 
 /**
+ * Creates a link to trigger a new search, removing at least one of the active 
+ * search filters.
+ *
+ * @param $query 
+ *   A Solr query object.
+ * @param $facet_text 
+ *   Facet value shown to the user.
+ * @param $remove 
+ *   Array of field names and values to remove upon clicking link to build.
+ * @return 
+ *   A string containing the themed unclick link.
+ */
+function apachesolr_search_get_unclick_link($query, $facet_text, $remove) {
+  static $unclick_queries = array();
+
+  sort($remove);
+  $unclick_query_key = array_reduce($remove, 'apachesolr_search_get_unclick_query_key');
+  $new_query = clone $query;
+
+  if (empty($unclick_queries[$unclick_query_key])) {
+    foreach($remove as $field) {
+      $new_query->remove_filter($field['#name'], $field['#value']);
+    }
+    $unclick_queries[$unclick_query_key]['query'] = $new_query->get_url_queryvalues();
+  }
+
+  return theme('apachesolr_unclick_link', $facet_text, $new_query->get_path(), $unclick_queries[$unclick_query_key]);
+}
+
+/**
+ * Callback for array_reduce() in apachesolr_search_get_unclick_link().
+ */
+function apachesolr_search_get_unclick_query_key($result, $val) {
+  return $result . $val['#name'] . $val['#value'];
+}
+
+/**
  * Callback function for the 'Filter by book' facet block.
  */
 function apachesolr_search_get_book($facet, &$options) {
@@ -696,6 +751,38 @@
 }
 
 /**
+ * Recursive function that returns a nested array of facet values for use with
+ * theme_item_list().
+ *
+ * @param $links_array
+ *   Array of links to nest; each element's index denotes its plcae in hierarchy.
+ * @param $parent
+ *   String with name of current level to process.
+ * @param $level
+ *   Integer with the current level to process.
+ */
+function apachesolr_search_nested_facet_items($links_array, $parent = '', $level = 0) {
+  if (!is_array($links_array)) {
+    return array();
+  }
+  if ($level == 0) {
+    ksort($links_array);
+  }
+  $result = array();
+  foreach ($links_array as $key => $item) {
+    // For items on current level, and their $key is son of $parent
+    if (substr_count($key, "|") == $level && ($parent == '' || strpos($key, $parent) === 0)) {
+      // Add this item and all items on next level
+      $result[$key] = array(
+        'data' => $item,
+        'children' => apachesolr_search_nested_facet_items($links_array, $key, $level+1)
+      );
+    }
+  }
+  return $result;
+}
+
+/**
  * Callback function for the 'Filter by name' facet block.
  */
 function apachesolr_search_get_username($facet) {
@@ -1030,3 +1117,97 @@
   return implode(' ... ', $snippets) .' ...';
 }
 
+
+/**
+ * Return the contents of the "Current search" block.
+ *
+ * @param $query
+ *   The Solr query object.
+ */
+function apachesolr_search_currentsearch_block($query) {
+  $content = '';
+  $response = apachesolr_static_response_cache();
+  $reflect_hierarchy = apachesolr_search_get_hierarchical_vocabularies();
+  $fields = $query->get_filters();
+  $links = array();
+  $active_facets = array();
+  $active_facets_unclick = array();
+  $options = array();
+  if (!$fields) {
+    $options['attributes']['class'] = 'active';
+  }
+  $links[] = apachesolr_l($query->get_query_basic(), $query->get_path(), $options);
+  foreach($fields as $field) {
+    if ($field['#name']) {
+      $processed = FALSE;
+
+      if (module_exists('taxonomy') && 'tid' == $field['#name']) {
+        $term = taxonomy_get_term($field['#value']);
+        $facet_fieldname = 'im_vid_' . $term->vid;
+        if ($reflect_hierarchy[$facet_fieldname]) {
+          
+          // Build data to theme this active facet hierarchically (using this term's parents)
+          $key = '';
+          $parents = taxonomy_get_parents_all($term->tid);
+          $parents = array_reverse($parents);
+          foreach ($parents as $parent) {
+            
+            // Build field values to remove (the term's children and itself)
+            $children = taxonomy_get_tree($parent->vid, $parent->tid);
+            $children[] = $parent;
+            $remove = array();
+            foreach ($children as $child) {
+              $remove[] = array('#name' => 'tid', '#value' => $child->tid);
+            }
+            // Key is a string denoting hierarchy, and includes the term name
+            //   so it can be sorted for UX clarity.
+            $key .= ($key != '' ? '|' : '') . $parent->name . ':tid:' . $parent->tid;
+            
+            // Generate unclick link
+            if (! $fielddisplay = theme('apachesolr_breadcrumb_tid', $parent->tid)) {
+              $fielddisplay = $parent->tid;
+            }
+            $active_facets_unclick[$facet_fieldname][$key] = apachesolr_search_get_unclick_link($query, $fielddisplay, $remove);
+          }
+          $processed = TRUE;
+        }
+      } 
+      
+      // If not a hierarchic taxonomy term, or not a taxonomy term, add to $links[] now 
+      if (! $processed) {
+        $remove = array($field);
+        if (! $fielddisplay = theme('apachesolr_breadcrumb_' . $field['#name'], $field['#value'])) {
+          $fielddisplay = $field['#value'];
+        }
+        $links[] = apachesolr_search_get_unclick_link($query, $fielddisplay, $remove);
+      }
+    }
+  }
+  
+  // Process each $active_facets_unclick[vid] into $links[]
+  foreach ($active_facets_unclick as $facet_unclick) {
+    $links += apachesolr_search_nested_facet_items($facet_unclick);
+  }
+  
+  $content = theme('apachesolr_currentsearch', $response->response->numFound, $links);
+  return array('subject' => t('Current search'), 'content' => $content);
+}
+
+/**
+ * Return an array of taxonomy facets that should be displayed hierarchically.
+ */
+function apachesolr_search_get_hierarchical_vocabularies() {
+  static $result = array(), $processed = FALSE;
+  if ($processed) {
+    return $result;
+  }
+  $vocabularies = taxonomy_get_vocabularies($type);
+  foreach ($vocabularies as $voc) {
+    // If the vocabulary is not multiple-parent hierarchical and not freetagging.
+    if ($voc->hierarchy != 2 && $voc->tags != 1) {
+      $result['im_vid_' . $voc->vid] = 1;
+    }
+  }
+  $processed = TRUE;
+  return $result;
+}

