? .DS_Store
? LICENSE.txt
? contrib/apachesolr_commentsearch/apachesolr_commentsearch.info
? contrib/apachesolr_commentsearch/apachesolr_commentsearch.install
? contrib/apachesolr_commentsearch/apachesolr_commentsearch.module
? contrib/apachesolr_image/apachesolr_image.info
? contrib/apachesolr_image/apachesolr_image.module
? contrib/apachesolr_nodeaccess/apachesolr_nodeaccess.info
? contrib/apachesolr_nodeaccess/apachesolr_nodeaccess.module
? contrib/apachesolr_nodeaccess/tests
? contrib/apachesolr_og/apachesolr_og.info
? contrib/apachesolr_og/apachesolr_og.install
? contrib/apachesolr_og/apachesolr_og.module
Index: Solr_Base_Query.php
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/apachesolr/Solr_Base_Query.php,v
retrieving revision 1.1.4.40.2.10
diff -u -p -p -r1.1.4.40.2.10 Solr_Base_Query.php
--- Solr_Base_Query.php	26 Dec 2009 13:08:51 -0000	1.1.4.40.2.10
+++ Solr_Base_Query.php	16 Mar 2010 16:15:22 -0000
@@ -409,7 +409,6 @@ class Solr_Base_Query implements Drupal_
 
     // Gets information about the fields already in solr index.
     $index_fields = $this->solr->getFields();
-
     foreach ((array) $index_fields as $name => $data) {
       // Look for a field alias.
       $alias = isset($this->field_map[$name]) ? $this->field_map[$name] : $name;
Index: apachesolr.admin.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/apachesolr/apachesolr.admin.inc,v
retrieving revision 1.1.2.28.2.23
diff -u -p -p -r1.1.2.28.2.23 apachesolr.admin.inc
--- apachesolr.admin.inc	27 Dec 2009 17:29:34 -0000	1.1.2.28.2.23
+++ apachesolr.admin.inc	16 Mar 2010 16:15:23 -0000
@@ -249,6 +249,9 @@ function apachesolr_enabled_facets_form_
   foreach ($form_state['values']['apachesolr_enabled_facets'] as $module => $facets) {
     $enabled[$module] = array_filter($facets);
   }
+  // This cache being stale can prevent new facet filters from working.
+  $solr = apachesolr_get_solr();
+  $solr->clearCache();
   variable_set('apachesolr_enabled_facets', $enabled);
   drupal_set_message($form_state['values']['submit_message'], 'warning');
 }
@@ -265,9 +268,12 @@ function apachesolr_enabled_facets_form(
   $module_facets = array();
   $module_list = array();
   foreach (module_implements('apachesolr_facets') as $module) {
-    $module_facets[$module] = module_invoke($module, 'apachesolr_facets');
-    uasort($module_facets[$module], 'apachesolr_sort_facets');
-    $module_list[$module] = $module;
+    $return = module_invoke($module, 'apachesolr_facets');
+    if (!empty($return)) {
+      $module_facets[$module] = $return; 
+      uasort($module_facets[$module], 'apachesolr_sort_facets');
+      $module_list[$module] = $module;
+    }
   }
 
   $enabled_facets = apachesolr_get_enabled_facets();
@@ -284,6 +290,7 @@ function apachesolr_enabled_facets_form(
     }
   }
   foreach($module_facets as $module => $facets) {
+    
     $form['apachesolr_enabled_facets'][$module] = array(
       '#type' => 'fieldset',
       '#title' => check_plain($module_list[$module]['name']),
@@ -381,8 +388,8 @@ function apachesolr_clear_index_submit($
     $form_state['redirect'] = 'admin/settings/apachesolr/index/batch/confirm';
   }
   else {
-  $form_state['redirect'] = 'admin/settings/apachesolr/index/clear/confirm';
-}
+    $form_state['redirect'] = 'admin/settings/apachesolr/index/clear/confirm';
+  }
 }
 
 /**
Index: apachesolr.index.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/apachesolr/apachesolr.index.inc,v
retrieving revision 1.1.2.6.2.18
diff -u -p -p -r1.1.2.6.2.18 apachesolr.index.inc
--- apachesolr.index.inc	2 Jan 2010 23:44:04 -0000	1.1.2.6.2.18
+++ apachesolr.index.inc	16 Mar 2010 16:15:23 -0000
@@ -110,43 +110,28 @@ function apachesolr_node_to_document($no
 
     // Get CCK fields list
     $cck_fields = apachesolr_cck_fields();
+    // NOTE: One CCK field might result in multiple Solr fields.
     foreach ($cck_fields as $key => $cck_info) {
       if (isset($node->$key)) {
         // Got a CCK field. See if it is to be indexed.
         $function = $cck_info['indexing_callback'];
+        $fields = NULL;
         if ($cck_info['indexing_callback'] && function_exists($function)) {
-          $field = $function($node, $key);
+          // NOTE: This function should always return an array.
+          $fields = $function($node, $key, $cck_info);
         }
-        else {
-          $field = $node->$key;
-        }
-        $index_key = apachesolr_index_key($cck_info);
-        if (is_array($field)) {
-          foreach ($field as $value) {
-            // Don't index NULLs or empty strings
-            // We can use 'value' rather than 'safe' since we strip tags and later check_plain().
-            // Furthermore, what is being indexed is the KEY for the CCK value. It will need
-            // a trip through content_format() later to display the value.
-            switch ($cck_info['field_type']) {
-              case 'nodereference':
-                $index_value = (isset($value['nid']) && strlen($value['nid'])) ? $value['nid'] : FALSE;
-                break;
-  
-              case 'userreference':
-                $index_value = (isset($value['uid']) && strlen($value['uid'])) ? $value['uid'] : FALSE;
-                break;
-  
-              default:
-                $index_value = (isset($value['value']) && strlen($value['value'])) ? $value['value'] : FALSE;
-                break;
+        // NOTE: This is now being done in the mandatory indexing callback.
+        // $index_key = apachesolr_index_key($cck_info);
+        if (is_array($fields)) {
+          // NOTE: If this were done as $key => $value, and the $index_key were
+          // done within the loop, could we support indexing one CCK field to
+          // multiple Solr fields?
+          foreach ($fields as $field) {
+            if ($cck_info['multiple']) {
+              $document->setMultiValue($field['key'], apachesolr_clean_text($field['value']));
             }
-            if ($index_value) {
-              if ($cck_info['multiple']) {
-                $document->setMultiValue($index_key, apachesolr_clean_text($index_value));
-              }
-              else {
-                $document->$index_key = apachesolr_clean_text($index_value);
-              }
+            else {
+              $document->{$field['key']} = apachesolr_clean_text($field['value']);
             }
           }
         }
@@ -169,6 +154,38 @@ function apachesolr_node_to_document($no
   return $document;
 }
 
+function apachesolr_cck_nodereference_indexing_callback($node, $field_name, $cck_info) {
+  $fields = array();
+  if (isset($node->{$field_name})) {
+    $index_key = apachesolr_index_key($cck_info);
+    foreach ($node->$field_name as $field) {
+      if ($index_value =  (isset($field['nid']) && strlen($field['nid'])) ? $field['nid'] : FALSE) {
+        $fields[] = array(
+          'key' => $index_key,
+          'value' => $index_value,
+        );
+      }
+    }
+  }
+  return $fields;
+}
+
+function apachesolr_cck_userreference_indexing_callback($node, $field_name, $cck_info) {
+  $fields = array();
+  if (isset($node->$field_name)) {
+    $index_key = apachesolr_index_key($cck_info);
+    foreach ($node->{$field_name} as $field) {
+      if ($index_value =  (isset($field['uid']) && strlen($field['uid'])) ? $field['uid'] : FALSE) {
+        $fields[] = array(
+          'key' => $index_key,
+          'value' => $index_value,
+        );
+      }
+    }
+  }
+  return $fields;
+}
+
 /**
  * Extract taxonomy from $node and add to dynamic fields.
  */
@@ -251,7 +268,7 @@ function apachesolr_add_tags_to_document
 /**
  * Additional index utility functions
  */
- 
+
 /**
  * hook_cron() helper to try to make {apachesolr_search_node} consistent with {node}.
  */
@@ -303,7 +320,7 @@ function apachesolr_cron_check_node_tabl
     }
   }
 }
- 
+
 function apachesolr_nodeapi_mass_update($nodes) {
   if (empty($nodes)) {
     return TRUE;
@@ -330,7 +347,7 @@ function apachesolr_nodeapi_mass_update(
     return FALSE;
   }
 }
- 
+
 function apachesolr_nodeapi_mass_delete($nodes) {
   if (empty($nodes)) {
     return TRUE;
@@ -354,4 +371,3 @@ function apachesolr_nodeapi_mass_delete(
     return FALSE;
   }
 }
-
Index: apachesolr.info
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/apachesolr/apachesolr.info,v
retrieving revision 1.1.2.1.2.8
diff -u -p -p -r1.1.2.1.2.8 apachesolr.info
--- apachesolr.info	4 Jun 2009 13:33:36 -0000	1.1.2.1.2.8
+++ apachesolr.info	16 Mar 2010 16:15:23 -0000
@@ -5,3 +5,10 @@ dependencies[] = search
 package = Apache Solr
 core = "6.x"
 php = 5.1.4
+
+; Information added by drupal.org packaging script on 2010-03-10
+version = "6.x-2.x-dev"
+core = "6.x"
+project = "apachesolr"
+datestamp = "1268179277"
+
Index: apachesolr.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/apachesolr/apachesolr.module,v
retrieving revision 1.1.2.12.2.155.2.58
diff -u -p -p -r1.1.2.12.2.155.2.58 apachesolr.module
--- apachesolr.module	9 Mar 2010 21:02:34 -0000	1.1.2.12.2.155.2.58
+++ apachesolr.module	16 Mar 2010 16:15:23 -0000
@@ -280,6 +280,7 @@ function apachesolr_rebuild_index_table(
     db_query("UPDATE {apachesolr_search_node} SET changed = %d WHERE changed > %d", $time, $time);
     apachesolr_clear_last_index();
   }
+  cache_clear_all('*', 'cache_apachesolr', TRUE);
 }
 
 function apachesolr_exclude_types($namespace) {
@@ -744,10 +745,12 @@ function apachesolr_get_facet_definition
     $operator_settings = variable_get('apachesolr_operator', array());
     foreach (module_implements('apachesolr_facets') as $module) {
       $facets = module_invoke($module, 'apachesolr_facets');
-      foreach ($facets as $delta => $info) {
-        $definitions[$module][$delta] = $info;
-        if(isset($definitions[$module][$delta])) {
-          $definitions[$module][$delta]['operator'] = isset($operator_settings[$module][$delta]) ? $operator_settings[$module][$delta] : 'AND';
+      if (!empty($facets)) {
+        foreach ($facets as $delta => $info) {
+          $definitions[$module][$delta] = $info;
+          if(isset($definitions[$module][$delta])) {
+            $definitions[$module][$delta]['operator'] = isset($operator_settings[$module][$delta]) ? $operator_settings[$module][$delta] : 'AND';
+          }
         }
       }
     }
@@ -756,6 +759,24 @@ function apachesolr_get_facet_definition
 }
 
 /**
+ * Returns a member of the facet definitions array if it contains
+ * $field as the 'field_name' element.
+ *
+ * @param string $field
+ *   The field_name being sought.
+ */
+function apachesolr_get_facet_definition_by_field($field) {
+  $definitions = apachesolr_get_facet_definitions();
+  foreach ($definitions as $module => $facets) {
+    foreach ($facets as $key => $values) {
+      if ($facet = array_search($field, $values)) {
+        return $definitions[$module][$key];
+      }
+    }
+  }
+}
+
+/**
  * Implementation of hook_form_[form_id]_alter().
  *
  * Hide the core 'title' field in favor of our 'name' field.
@@ -1112,8 +1133,7 @@ function apachesolr_date_gap_drilldown($
     'YEAR' => 'MONTH',
     'MONTH' => 'DAY',
     'DAY' => 'HOUR',
-    // For now, HOUR is a reasonable smallest gap.
-    // 'HOUR' => 'MINUTE',
+    'HOUR' => 'MINUTE',
   );
   return isset($drill[$gap]) ? $drill[$gap] : NULL;
 }
@@ -1145,7 +1165,7 @@ function apachesolr_facetcount_form($mod
     '#description' => t('The maximum number of filter links to show in this block.'),
     '#default_value' => isset($limits[$module][$delta]) ? $limits[$module][$delta] : variable_get('apachesolr_facet_query_limit_default', 20),
   );
-  
+
   // TODO: Generalize how we know what type a facet block is by putting field
   // type into the facet definition. 'created' and 'changed' are date blocks.
   if ($delta != 'created' && $delta != 'changed') {
@@ -1406,7 +1426,7 @@ function apachesolr_static_response_cach
 function apachesolr_drupal_query($keys = '', $filters = '', $solrsort = '', $base_path = '', $solr = NULL) {
   list($module, $class) = variable_get('apachesolr_query_class', array('apachesolr', 'Solr_Base_Query'));
   include_once drupal_get_path('module', $module) .'/'. $class .'.php';
-  
+
   if (empty($solr)) {
     $solr = apachesolr_get_solr();
   }
@@ -1546,14 +1566,17 @@ function apachesolr_cck_fields() {
       $mappings['nodereference'] = array(
         'nodereference_buttons' => array(
           'display_callback' => 'apachesolr_cck_nodereference_field_callback',
+          'indexing_callback' => 'apachesolr_cck_nodereference_indexing_callback',
           'index_type' => 'integer',
         ),
         'nodereference_select' => array(
           'display_callback' => 'apachesolr_cck_nodereference_field_callback',
+          'indexing_callback' => 'apachesolr_cck_nodereference_indexing_callback',
           'index_type' => 'integer',
         ),
         'nodereference_autocomplete' => array(
           'display_callback' => 'apachesolr_cck_nodereference_field_callback',
+          'indexing_callback' => 'apachesolr_cck_nodereference_indexing_callback',
           'index_type' => 'integer',
         ),
       );
@@ -1564,10 +1587,12 @@ function apachesolr_cck_fields() {
         ),
         'userreference_select' => array(
           'display_callback' => 'apachesolr_cck_userreference_field_callback',
+          'indexing_callback' => 'apachesolr_cck_userreference_indexing_callback',
           'index_type' => 'integer',
         ),
         'userreference_autocomplete' => array(
           'display_callback' => 'apachesolr_cck_userreference_field_callback',
+          'indexing_callback' => 'apachesolr_cck_userreference_indexing_callback',
           'index_type' => 'integer',
         ),
       );
@@ -1579,20 +1604,21 @@ function apachesolr_cck_fields() {
         // Only deal with fields that have option widgets (facets don't make sense otherwise), or fields that have specific mappings.
         if ((isset($mappings[$row->field_type][$row->widget_type]) ||  isset($mappings['per-field'][$row->field_name]))) {
           if (isset($mappings['per-field'][$row->field_name])) {
-            $fields[$row->field_name] = $mappings['per-field'][$row->field_name];
-            $row->index_type = $mappings['per-field'][$row->field_name]['index_type'];
-            $row->indexing_callback = $mappings['per-field'][$row->field_name]['indexing_callback'];
-            $row->display_callback = $mappings['per-field'][$row->field_name]['display_callback'];
+            $field = $mappings['per-field'][$row->field_name];
+            $fields[$row->field_name] = $field;
           }
           else {
-            $row->index_type = $mappings[$row->field_type][$row->widget_type]['index_type'];
-            $row->indexing_callback = $mappings[$row->field_type][$row->widget_type]['indexing_callback'];
-            $row->display_callback = $mappings[$row->field_type][$row->widget_type]['display_callback'];
+            $field = $mappings[$row->field_type][$row->widget_type];
           }
-          $row->multiple = (bool) $row->multiple;
           // It's important that we put the 'cck_' here because several points in the later processing
           // depend on it to route program flow to cck specific handlers.
-          $row->name = 'cck_' . $row->field_name;
+          $row->name                 = 'cck_' . $row->field_name;
+          $row->index_type           = $field['index_type'];
+          $row->indexing_callback    = $field['indexing_callback'];
+          $row->display_callback     = $field['display_callback'];
+          $row->facet_block_callback = $field['facet_block_callback'];
+          $row->multiple             = (bool) $row->multiple;
+
           $fields[$row->field_name] = array_merge((array) $fields[$row->field_name], (array) $row);
           $fields[$row->field_name]['content_types'][] = $row->content_type;
           unset($fields[$row->field_name]['content_type']);
@@ -1605,6 +1631,15 @@ function apachesolr_cck_fields() {
 }
 
 /**
+ * Implementation of hook_content_fieldapi
+ */
+function apachesolr_content_fieldapi($op) {
+  if ($op == 'update instance') {
+    cache_clear_all('*', 'cache_apachesolr', TRUE);   
+  }
+}
+
+/**
  * Use the content.module's content_format() to format the
  * field based on its value ($facet).
  *
@@ -1739,7 +1774,7 @@ function apachesolr_mlt_suggestions($set
       }
     }
     $query = apachesolr_drupal_query('id:' . $id);
-    
+
     $type_filters = array();
     if (is_array($settings['mlt_type_filters'])) {
       foreach ($settings['mlt_type_filters'] as $type_filter) {
Index: apachesolr_search.info
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/apachesolr/apachesolr_search.info,v
retrieving revision 1.1.2.1.2.7
diff -u -p -p -r1.1.2.1.2.7 apachesolr_search.info
--- apachesolr_search.info	20 Mar 2009 04:11:16 -0000	1.1.2.1.2.7
+++ apachesolr_search.info	16 Mar 2010 16:15:23 -0000
@@ -6,3 +6,10 @@ dependencies[] = apachesolr
 package = Apache Solr
 core = "6.x"
 php = 5.1.4
+
+; Information added by drupal.org packaging script on 2010-03-10
+version = "6.x-2.x-dev"
+core = "6.x"
+project = "apachesolr"
+datestamp = "1268179277"
+
Index: apachesolr_search.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/apachesolr/apachesolr_search.module,v
retrieving revision 1.1.2.6.2.111.2.45
diff -u -p -p -r1.1.2.6.2.111.2.45 apachesolr_search.module
--- apachesolr_search.module	4 Jan 2010 14:27:56 -0000	1.1.2.6.2.111.2.45
+++ apachesolr_search.module	16 Mar 2010 16:15:23 -0000
@@ -1,5 +1,5 @@
 <?php
-// $Id: apachesolr_search.module,v 1.1.2.6.2.111.2.45 2010/01/04 14:27:56 robertDouglass Exp $
+// $Id: apachesolr_search.module,v 1.1.2.6.2.111.2.44 2010/01/02 10:54:30 robertDouglass Exp $
 
 /**
  * @file
@@ -266,8 +266,9 @@ function apachesolr_search_browse($keys 
       if ($delta == 'currentsearch') {
         continue;
       }
-      if (count((array)$response->facet_counts->facet_fields->$facet_field) > 0) {
-        // This bit is modeled on block.modul, block_list().
+      if (count((array)$response->facet_counts->facet_fields->$facet_field) > 0 ||
+          count((array)$response->facet_counts->facet_dates->$facet_field) > 0) {
+        // This bit is modeled on block.module, block_list().
         $result = db_query(db_rewrite_sql("SELECT DISTINCT b.* FROM {blocks} b
           LEFT JOIN {blocks_roles} r ON b.module = r.module AND b.delta = r.delta
           WHERE b.module = '%s' AND b.delta = '%s' AND b.theme = '%s' AND b.status = 1
@@ -385,6 +386,7 @@ function apachesolr_search_execute($keys
   return apachesolr_search_process_response($response, $query, $params);
 }
 
+// NOTE: Why does this take the $query object?
 function apachesolr_search_basic_params($query) {
   $params = array(
     'fl' => 'id,nid,title,comment_count,type,created,changed,score,path,url,uid,name',
@@ -436,7 +438,18 @@ function apachesolr_search_add_facet_par
       if (apachesolr_block_visibility($query, $module, $delta)) {
         // TODO: generalize handling of date and range facets.
         // TODO: put field type in the facet definitions.
-        if ($module == 'apachesolr_search' && ($facet_field == 'created' || $facet_field == 'changed')) {
+        // NOTE: This is a dependency on the apachesolr_date module. Using function_exists to avoid problems.
+        if (in_array($facet_info[$module][$delta]['field_type'], array('date', 'datetime', 'datestamp'))
+              && function_exists('apachesolr_date_search_date_range')) {
+          list($start, $end, $gap) = apachesolr_date_search_date_range($query, $facet_field);
+          if ($gap) {
+            $params['facet.date'][] = $facet_field;
+            $params['f.'. $facet_field .'.facet.date.start'] = $start;
+            $params['f.'. $facet_field .'.facet.date.end'] = $end;
+            $params['f.'. $facet_field .'.facet.date.gap'] = $gap;
+          }
+        }
+        else if ($module == 'apachesolr_search' && ($facet_field == 'created' || $facet_field == 'changed')) {
           list($start, $end, $gap) = apachesolr_search_date_range($query, $facet_field);
           if ($gap) {
             $params['facet.date'][] = $facet_field;
@@ -698,10 +711,11 @@ function apachesolr_search_apachesolr_fa
     foreach ($fields as $name => $field) {
       // $delta can only be 32 chars, and the CCK field name may be this
       // long also, so we cannot add anything to it.
-      $facets[$field['field_name']] = array(
-        'info' => t('CCK @field_type field: Filter by @field', array('@field_type' => $field['field_type'], '@field' => $field['label'])),
-        'facet_field' => apachesolr_index_key($field),
-        'content_types' => $field['content_types'],
+      $facets[$field['field_name']] = array_merge($field, array(
+          'info' => t('CCK @field_type field: Filter by @field', array('@field_type' => $field['field_type'], '@field' => $field['label'])),
+          'facet_field' => apachesolr_index_key($field),
+          'content_types' => $field['content_types'],
+        )
       );
     }
   }
@@ -712,7 +726,6 @@ function apachesolr_search_apachesolr_fa
  * Implementation of hook_block().
  */
 function apachesolr_search_block($op = 'list', $delta = 0, $edit = array()) {
-
   switch ($op) {
     case 'list':
       $enabled_facets = apachesolr_get_enabled_facets('apachesolr_search');
@@ -731,6 +744,7 @@ function apachesolr_search_block($op = '
       return $blocks;
 
     case 'view':
+      dsm(debug_backtrace());
       if (apachesolr_has_searched()) {
         // Get the query and response. Without these no blocks make sense.
         $response = apachesolr_static_response_cache();
@@ -759,23 +773,30 @@ function apachesolr_search_block($op = '
           case 'is_book_bid':
             return apachesolr_facet_block($response, $query, 'apachesolr_search', $delta, $delta, t('Filter by book'), 'apachesolr_search_get_book');
           case 'language':
+            dsm("language");
             return apachesolr_facet_block($response, $query, 'apachesolr_search', $delta, $delta, t('Filter by language'), 'apachesolr_search_language_name');
            case 'uid':
+            dsm("user");
             return apachesolr_facet_block($response, $query, 'apachesolr_search', $delta, $delta, t('Filter by author'), 'apachesolr_search_get_username');
           case 'type':
+            dsm("type");
             return apachesolr_facet_block($response, $query, 'apachesolr_search', $delta, $delta, t('Filter by type'), 'apachesolr_search_get_type');
           case 'changed':
+            dsm("changed");
             return apachesolr_date_facet_block($response, $query, 'apachesolr_search', $delta, $delta, t('Filter by modification date'));
           case 'created':
+            dsm("created");
             return apachesolr_date_facet_block($response, $query, 'apachesolr_search', $delta, $delta, t('Filter by post date'));
 
           default:
+
            if ($fields = apachesolr_cck_fields()) {
             foreach ($fields as $name => $field) {
               if ($field['field_name'] == $delta) {
                 $index_key = apachesolr_index_key($field);
                 $callback = isset($field['display_callback']) ? $field['display_callback'] : FALSE;
-                return apachesolr_facet_block($response, $query, 'apachesolr_search', $delta, $index_key, t('Filter by @field', array('@field' => $field['label'])), $callback);
+                $block_function = (isset($field['facet_block_callback']) && function_exists($field['facet_block_callback'])) ? $field['facet_block_callback'] : 'apachesolr_facet_block';
+                return $block_function($response, $query, 'apachesolr_search', $delta, $index_key, t('Filter by @field', array('@field' => $field['label'])), $callback);
               }
             }
           }
@@ -889,10 +910,6 @@ function apachesolr_search_taxonomy_face
     $items = apachesolr_search_nested_facet_items($query, $facets, $response->response->numFound);
     // Process all terms into an item list
     if ($items && ($response->response->numFound > 1 || $contains_active)) {
-      // 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);
-
       $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)),
@@ -946,10 +963,18 @@ function apachesolr_search_language_name
  *   the facets will be returned in the order they were received.
  */
 function apachesolr_search_nested_facet_items($query, $facets, $num_found, $sort = TRUE) {
-
   $items = array();
   foreach($facets as $field) {
-    $facet_text = theme('apachesolr_breadcrumb_' . $field['#name'], $field, $field['#exclude']);
+    $facet_definition = apachesolr_get_facet_definition_by_field($field['#name']);
+    if (isset($facet_definition['display_callback'])) {
+      $function = $facet_definition['display_callback'];
+      if (function_exists($function)) {
+        $facet_text = $function($field['#value'], $field);
+      }
+    }
+    if (!$facet_text) {
+      $facet_text = theme('apachesolr_breadcrumb_' . $field['#name'], $field, $field['#exclude']);
+    }
     if (!$facet_text) {
       $facet_text = $field['#value'];
     }
@@ -1297,15 +1322,30 @@ function apachesolr_search_apachesolr_th
   }
 }
 
+/**
+ * Theme function for CCK fields in breadcrumbs.
+ * TODO: The logic for getting here is too convoluted, and
+ * there are too many bizarre naming conventions in play (_cck_, _end).
+ * The checks for _cck_ and _end MUST get refactored.
+ */
 function theme_apachesolr_breadcrumb_cck($field) {
   $matches = preg_split('/_cck_/', $field['#name']);
   if (isset($matches[1])) {
+    $match = $matches[1];
+
+    // TODO: If the apachesolr_date module is present we might
+    // have fields with the suffix '_end'. These are the end-dates
+    // and need the suffix removed.
+    if (module_exists('apachesolr_date')) {
+      $match = preg_replace('/_end{1}$/', '', $match);
+    }
+
     $mappings = apachesolr_cck_fields();
-    if (isset($mappings[$matches[1]]['display_callback'])) {
-      $function = $mappings[$matches[1]]['display_callback'];
+    if (isset($mappings[$match]['display_callback'])) {
+      $function = $mappings[$match]['display_callback'];
       if (function_exists($function)) {
         $facet = $field['#value'];
-        $options = array('delta' => $matches[1]);
+        $options = array_merge($mappings[$match], array('delta' => $matches[1]));
         return $function($facet, $options);
       }
     }
@@ -1416,7 +1456,6 @@ function apacehsolr_get_parent_terms($ti
 function apachesolr_search_currentsearch_block($response, $query) {
   $fields = $query->get_filters();
   $links = array();
-
   // If current search has keys, offer current search without them
   if ($keys = $query->get_query_basic()) {
     $links[] = theme('apachesolr_unclick_link', $keys, $query->get_path(''), array('query' => $query->get_url_queryvalues()));
Index: contrib/apachesolr_date/apachesolr_date.info
===================================================================
RCS file: contrib/apachesolr_date/apachesolr_date.info
diff -N contrib/apachesolr_date/apachesolr_date.info
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ contrib/apachesolr_date/apachesolr_date.info	16 Mar 2010 16:15:23 -0000
@@ -0,0 +1,9 @@
+; $Id: apachesolr.info,v 1.1.2.1.2.8 2009/06/04 13:33:36 robertDouglass Exp $
+name = Apache Solr Date
+description = Index and facet on CCK date fields.
+dependencies[] = apachesolr
+dependencies[] = apachesolr_search
+dependencies[] = date
+package = Apache Solr
+core = "6.x"
+php = 5.1.4
Index: contrib/apachesolr_date/apachesolr_date.module
===================================================================
RCS file: contrib/apachesolr_date/apachesolr_date.module
diff -N contrib/apachesolr_date/apachesolr_date.module
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ contrib/apachesolr_date/apachesolr_date.module	16 Mar 2010 16:15:23 -0000
@@ -0,0 +1,442 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ *   Integration with the Apache Solr search application. Provides
+ *   faceting for CCK Date fields.
+ */
+
+/**
+ * Implementation of hook_apachesolr_facets.
+ * Only handles end date facets.
+ * Start date facet definitions are handled later.
+ * @see function apachesolr_date_apachesolr_cck_fields_alter() 
+ */
+function apachesolr_date_apachesolr_facets() {
+  // Get CCK field facets.
+  $fields = apachesolr_cck_fields();
+  $facets = array();
+  if ($fields) {
+    foreach ($fields as $name => $field) {
+      if (in_array($field['field_type'], array('date', 'datetime', 'datestamp'))) {
+        $cck_info = content_fields($field['field_name']);
+        // Only fields with a value2 have end dates to facet upon.
+        if (isset($cck_info['columns']['value2'])) {
+          // $delta can only be 32 chars, and the CCK field name may be this
+          // long also, so we cannot add anything to it.
+          $facets[$field['field_name'] . '_end'] = array_merge($field, array(
+              'info' => t('CCK @field_type field: Filter by @field end', array('@field_type' => $field['field_type'], '@field' => $field['label'])),
+              // 'facet_field' will later be block deltas.
+              'facet_field' => apachesolr_index_key($field) . '_end',
+              'content_types' => $field['content_types'],
+            )
+          );
+        }
+      }
+    }
+  }
+  return $facets; 
+}
+
+/**
+ * Implementation of hook_block.
+ */
+function apachesolr_date_block($op = 'list', $delta = 0, $edit = array()) {
+  switch ($op) {
+    case 'list':
+      $enabled_facets = apachesolr_get_enabled_facets('apachesolr_date');
+      $facets = apachesolr_date_apachesolr_facets();
+      // Add the blocks
+      $blocks = array();
+      foreach ($enabled_facets as $delta => $facet_field) {
+        if (isset($facets[$delta])) {
+          $blocks[$delta] = $facets[$delta] + array('cache' => BLOCK_CACHE_PER_PAGE,);
+          // TODO: This is ugly. The only consolation is that the admin can
+          // override block titles anyway.
+          $blocks[$delta]['label'] = $blocks[$delta]['label']  . ' (end)';
+        }
+      }
+      return $blocks;
+
+    case 'view':
+      if (apachesolr_has_searched()) {
+        // Get the query and response. Without these no blocks make sense.
+        $response = apachesolr_static_response_cache();
+        if (empty($response)) {
+          return;
+        }
+        $query = apachesolr_current_query();
+
+        $facets = apachesolr_get_enabled_facets('apachesolr_date');
+        if (empty($facets[$delta])) {
+          return;
+        }
+
+        if (!apachesolr_block_visibility($query, 'apachesolr_date', $delta)) {
+          return;
+        }
+        // $delta comes to us with _end on the end, which we snip off right here.
+        $delta = substr($delta, 0, strlen($delta) - 4);
+        if ($fields = apachesolr_cck_fields()) {
+          if ($field = $fields[$delta]) {
+            $index_key = apachesolr_index_key($field) . '_end';
+            $callback = isset($field['display_callback']) ? $field['display_callback'] : FALSE;
+            $block_function = (isset($field['facet_block_callback']) && function_exists($field['facet_block_callback'])) ? $field['facet_block_callback'] : 'apachesolr_facet_block';
+            return $block_function($response, $query, 'apachesolr_search', $delta, $index_key, t('Filter by @field end', array('@field' => $field['label'])), $callback);
+          }
+        }
+      }
+      break;
+
+    case 'configure':
+      return apachesolr_facetcount_form('apachesolr_date', $delta);
+
+    case 'save':
+      apachesolr_facetcount_save($edit);
+      break;
+  }
+}
+
+/**
+ * Implementation of hook_apachesolr_prepare_query.
+ * Adds sorts for enabled date facets to the sorting block.
+ */
+function apachesolr_date_apachesolr_prepare_query(&$query) {
+  // Because we get the enabled facets just from apachesolr_search we're
+  // limiting sorting to start dates.
+  $enabled_facets = apachesolr_get_enabled_facets('apachesolr_search');
+  $facet_definitions = apachesolr_date_apachesolr_facets();
+  $facet_definitions += apachesolr_search_apachesolr_facets();
+  
+  foreach ($enabled_facets as $key => $value) {
+    if (strpos($value, 'tds_cck_field_date') !== FALSE) {
+      $cck_field = content_fields($facet_definitions[$key]['field_name']);
+      $query->set_available_sort($value, array(
+        'title' => $cck_field['widget']['label'], // how the sort is to appear in the sorts block
+        'default' => 'desc', 
+       ));
+    }
+  }
+}
+
+/**
+ * Implementation of hook_apachesolr_cck_fields_alter.
+ * This function adds the CCK date fields' definitions to let
+ * them be recognized as facets.
+ */
+function apachesolr_date_apachesolr_cck_fields_alter(&$mappings) {
+  $defaults = array(
+      'indexing_callback' => 'apachesolr_date_date_field_indexing_callback',
+      // Trie-Range date types.
+      'index_type' => 'tdate',
+      'facet_block_callback' => 'apachesolr_date_date_facet_block',
+      'display_callback'     => 'apachesolr_date_display_callback',
+  );
+  // NOTE: The structure of this array essentially blocks us from having
+  // multiple mappings per CCK field. For that we'd need a structure like
+  // $mappings['date']['date_select'][]      = $defaults;
+  $mappings['date']['date_select']      = $defaults;
+  $mappings['date']['date_text']        = $defaults;
+  $mappings['datetime']['date_select']  = $defaults;
+  $mappings['datetime']['date_text']    = $defaults;
+  $mappings['datestamp']['date_select'] = $defaults;
+  $mappings['datestamp']['date_text']   = $defaults;
+  $mappings['datestamp']['date_select']['indexing_callback'] = 'apachesolr_date_datestamp_field_indexing_callback';
+  $mappings['datestamp']['date_text']['indexing_callback']   = 'apachesolr_date_datestamp_field_indexing_callback';
+}
+
+/**
+ * This function is used during indexing to normalize the DATE and DATETIME
+ * fields into the appropriate format for Apache Solr.
+ */
+function apachesolr_date_date_field_indexing_callback($node, $field_name, $cck_info) {
+  $fields = array();
+  if (isset($node->$field_name)) {
+    $index_key = apachesolr_index_key($cck_info);
+    foreach ($node->$field_name as $field) {
+      // Construct a Solr-ready date string in UTC time zone based on the field's date string and time zone.
+      $tz = new DateTimeZone(isset($field['timezone']) ? $field['timezone'] : 'UTC');
+
+      // $fields may end up having two values; one for the start date
+      // and one for the end date.
+      if (isset($field['value'])) {
+        if ($date = date_create($field['value'], $tz)) {
+          $index_value = apachesolr_date_iso($date->format('U'));
+          $fields[] = array(
+            'key' => $index_key,
+            'value' => $index_value,
+          );
+        }
+      }
+      if (isset($field['value2'])) {
+        if ($date = date_create($field['value2'], $tz)) {
+          $index_value = apachesolr_date_iso($date->format('U'));
+          $fields[] = array(
+            // The value2 element is the end date. Therefore it gets indexed
+            // into its own Solr field.
+            'key' => $index_key . '_end',
+            'value' => $index_value,
+          );
+        }
+      }
+    }
+  }
+  return $fields;
+}
+
+/**
+ * This function is used during indexing to normalize the DATESTAMP fields
+ * into the appropriate format for Apache Solr.
+ */
+function apachesolr_date_datestamp_field_indexing_callback($node, $field_name, $cck_info) {
+  $fields = array();
+  if (isset($node->$field_name)) {
+    $index_key = apachesolr_index_key($cck_info);
+
+    // $fields may end up having two values; one for the start date
+    // and one for the end date.
+    foreach ($node->$field_name as $field) {
+      if (isset($field['value']) && $field['value'] != 0) {
+        $index_value = apachesolr_date_iso($field['value']);
+        $fields[] = array(
+          'key' => $index_key,
+          'value' => $index_value,
+        );
+      }
+      if (isset($field['value2']) && $field['value'] != 0) {
+        $index_value = apachesolr_date_iso($field['value2']);
+        $fields[] = array(
+          // The value2 element is the end date. Therefore it gets indexed
+          // into its own Solr field.
+          'key' => $index_key . '_end',
+          'value' => $index_value,
+        );
+      }
+    }
+  }
+  return $fields;
+}
+
+/**
+ * When faceting and filtering we need to infer ranges of dates.
+ * This function looks at a query and a facet field and returns a
+ * date range for use in querying.
+ *
+ * @param Drupal_Solr_Query_Interface $query
+ *   Current query object.
+ * @param $facet_field
+ *   The field for which a range must be generated.
+ *   
+ * @return array $gap
+ *   The array contains a start, end, and gap element.
+ *
+ *  Example return value:
+ *  array(
+ *    0 => '2007-01-05T13:05:00Z/YEAR',
+ *    1 => '2013-11-17T15:04:00Z+1YEAR/YEAR',
+ *    2 => '+1YEAR',
+ *  );
+ *
+ */
+function apachesolr_date_search_date_range($query, $facet_field) {
+  foreach ($query->get_filters($facet_field) as $filter) {
+    // If we had an ISO date library we could use ISO dates
+    // directly.  Instead, we convert to Unix timestamps for comparison.
+    // Only use dates if we are able to parse into timestamps.
+    $start = strtotime($filter['#start']);
+    $end = strtotime($filter['#end']);
+    if ($start && $end && ($start < $end)) {
+        $start_iso = $filter['#start'];
+        $end_iso = $filter['#end'];
+      // Determine the drilldown gap for this range.
+      $gap = apachesolr_date_gap_drilldown(apachesolr_date_find_query_gap($start_iso, $end_iso));
+    }
+  }
+
+  // If there is no $delta field in the query object, get initial
+  // facet.date.* params from the DB and determine the best search
+  // gap to use.
+  if (!isset($start_iso)) {
+    // NOTE: Finding the field namd and loading the field info is a hacky
+    // bit of string manipulation. We look once with what comes in ($field_name),
+    // and if that doesn't find any CCK field definition for us, we hack off
+    // the last four characters (presumed to be '_end' for an ending date),
+    // and try again. If that doesn't find anything we go home.
+    
+    $field_name = substr($facet_field, 8);
+    $field = content_fields($field_name);
+    $db_info = content_database_info($field);
+    $column = $db_info['columns']['value']['column'];
+    // This check is in place for the cases where the field name has
+    // _end appended to the end, and signifies that it is and end date.
+    if (!$field) {
+      $field_name = substr($field_name, 0, strlen($field_name) - 4);
+      $field = content_fields($field_name);
+      $db_info = content_database_info($field);
+      $column = $db_info['columns']['value2']['column'];
+    }
+    
+    // By this point we should have the following:
+    //   $field_name, a cck field name
+    //   $field, a cck field definition
+    //   $db_info, information from content.module about retrieving db data
+    //   $column, the column name in the db table for this field
+    if (!$field) {
+      return;
+    }
+ 
+    if (!empty($field['timezone_db'])) {
+      $tz = new DateTimeZone($field['timezone_db']);
+    }
+    else {
+      // The commented code takes the TZ from the computer the site is on.
+      //$tz = new DateTimeZone(date_default_timezone_get());
+      $tz = new DateTimeZone('UTC');
+    }
+    $table = $db_info['table'];
+    $start_value = db_result(db_query("SELECT MIN(cck.$column) FROM {{$table}} cck INNER JOIN {node} n WHERE n.status = 1"));
+    if (is_numeric($start_value)) {
+      $start_iso = apachesolr_date_iso($start_value);
+    }
+    else if ($date = date_create($start_value, $tz)) {
+      $start_iso = apachesolr_date_iso($date->format('U'));
+    }
+
+    $end_value = db_result(db_query("SELECT MAX(cck.$column) FROM {{$table}} cck INNER JOIN {node} n WHERE n.status = 1"));
+    if (is_numeric($end_value)) {
+      $end_iso = apachesolr_date_iso($end_value);
+    }
+    else if ($date = date_create($end_value, $tz)) {
+      $end_iso = apachesolr_date_iso($date->format('U'));
+    }
+
+    if (isset($start_iso) && isset($end_iso)) {
+      $gap = apachesolr_date_determine_gap($start_iso, $end_iso);
+    }
+    else {
+      // TODO: Find the gap.
+      $end_iso = $start_iso;
+      $gap = "YEAR";
+    }
+  }
+
+  // Return a query range from the beginning of a gap period to the beginning
+  // of the next gap period.  We ALWAYS generate query ranges of this form
+  // and the apachesolr_date_*() helper functions require it.
+  return array("$start_iso/$gap", "$end_iso+1$gap/$gap", "+1$gap");
+}
+
+/**
+ * Helper function for displaying a date facet blocks.
+ */
+function apachesolr_date_date_facet_block($response, $query, $module, $delta, $facet_field, $filter_by, $facet_callback = FALSE) {
+  // The items in the facet block (facet links and unclick links).
+  $items = array();
+  // The array that is ultimately sent into apachesolr_l(), @see apachesolr_l
+  $options = array();
+  // The display text for any given facet or unclick link.
+  $facet_text = '';
+
+  // Clone the query as we either add or remove a filter before generating
+  // the link.
+  $new_query = clone $query;
+  // Set the default gap.
+  $gap = 'YEAR';
+  foreach (array_reverse($new_query->get_filters($facet_field)) as $filter) {
+    $new_query->remove_filter($facet_field, $filter['#value']);
+    $gap = apachesolr_date_find_query_gap($filter['#start'], $filter['#end']);
+    $facet_text = apachesolr_date_format_iso_by_gap($gap, $filter['#start']);
+    $options['gap'] = $gap;
+    $options['query'] = $new_query->get_url_queryvalues();
+    array_unshift($items, theme('apachesolr_unclick_link', $facet_text, $new_query->get_path(), $options));
+  }
+
+  // Add links for additional date filters.
+  // NOTE: Date fields come in $response->facet_counts->facet_fields
+  // but others come in $response->facet_counts->facet_dates.
+  if (!empty($response->facet_counts->facet_dates->$facet_field)) {
+    $field = clone $response->facet_counts->facet_dates->$facet_field;
+  }
+  elseif (!empty($response->facet_counts->facet_fields->$facet_field)) {
+     $field = clone $response->facet_counts->facet_fields->$facet_field; 
+  }
+  if ($field) {
+    // A field will have this type of structure, where the main information
+    // is in the form DATE => COUNT:
+    // stdClass Object
+    // (
+    //    [2007-01-01T00:00:00Z] => 5
+    //    [2008-01-01T00:00:00Z] => 4
+    //    [2009-01-01T00:00:00Z] => 2
+    //    [2010-01-01T00:00:00Z] => 6
+    //    [2011-01-01T00:00:00Z] => 7
+    //    [2012-01-01T00:00:00Z] => 4
+    //    [2013-01-01T00:00:00Z] => 4
+    //    [gap] => +1YEAR
+    //    [end] => 2014-01-01T00:00:00Z
+    // )
+
+    // Isolate $end and $gap and clean the field to only have the actual
+    // date values.
+    $end = $field->end;
+    unset($field->end);
+
+    if (isset($field->gap)) {
+      $gap = $field->gap;
+      unset($field->gap);
+    }
+    // Treat each date facet as a range start, and use the next date
+    // facet as range end.  Use 'end' for the final end.
+    $range_end = array();
+    foreach ($field as $facet => $count) {
+      if (isset($prev_facet)) {
+        $range_end[$prev_facet] = $facet;
+      }
+      $prev_facet = $facet;
+    }
+    $range_end[$prev_facet] = $end;
+
+    foreach ($field as $facet => $count) {
+      // Solr sends this back if it's empty.
+      if ($facet == '_empty_' || $count == 0) {
+        continue;
+      }
+      if ($facet_callback && function_exists($facet_callback)) {
+        $facet_text = $facet_callback($facet, array('gap' => $gap));
+      }
+      else {
+        $facet_text = apachesolr_date_format_iso_by_gap($gap, $facet);
+      }
+      $new_query = clone $query;
+      $new_query->add_filter($facet_field, '['. $facet .' TO '. $range_end[$facet] .']');
+      $options['query'] = $new_query->get_url_queryvalues();
+      $items[] = theme('apachesolr_facet_link', $facet_text, $new_query->get_path(), $options, $count, FALSE, $response->response->numFound);
+    }
+  }
+  if (count($items) > 0) {
+    // Get information needed by the rest of the blocks about limits.
+    $initial_limits = variable_get('apachesolr_facet_query_initial_limits', array());
+    $limit = isset($initial_limits[$module][$delta]) ? $initial_limits[$module][$delta] : variable_get('apachesolr_facet_query_initial_limit_default', 10);
+    $output = theme('apachesolr_facet_list', $items, $limit, $delta);
+    return array('subject' => $filter_by, 'content' => $output);
+  }
+  return NULL;
+}
+
+/**
+ *  Handles facet text and breadcrumb displays for dates or date ranges.
+ *  @param $facet
+ *    A date string, eg: 2008-01-01T00:00:00Z or a date range, eg: [2007-01-01T00:00:00Z TO 2008-01-01T00:00:00Z]
+ *  @param $options
+ *    An array with a key 'gap' of the form +1YEAR, or +1MONTH etc.
+ *
+ *  TODO: Why is $options an array?
+ */
+function apachesolr_date_display_callback($facet, $options) {
+  if (preg_match('@[\[\{](\S+) TO (\S+)[\]\}]@', $facet, $match)) {
+    return apachesolr_date_format_range($match[1], $match[2]);
+  }
+  $gap = preg_replace('/^\+[0-9]+/', '', $options['gap']);
+  return apachesolr_date_format_iso_by_gap($gap, $facet);
+}
