--- C:/Documents and Settings/Administrator/Desktop/archive.module	Fri Dec 01 06:24:43 2006
+++ C:/Apache2/myblog/modules/archive/archive.module	Sun Feb 25 19:14:19 2007
@@ -31,11 +31,18 @@
   $items = array();
 
   if ($may_cache) {
-    $items[] = array('path' => 'archive',
+    $items[] = array('path' => variable_get('archive_page_path', 'archive'),
       'title' => t('Archives'),
       'access' => user_access('access content'),
       'callback' => 'archive_page',
-      'type' => MENU_SUGGESTED_ITEM);
+      'type' => MENU_SUGGESTED_ITEM);
+    $items[] = array(
+      'path' => 'admin/settings/archive',
+      'title' => t('Archives'),
+      'description' => t('Describes what the settings generally do.'),
+      'callback' => 'drupal_get_form',
+      'callback arguments' => array('archive_admin_settings'),
+      'type' => MENU_NORMAL_ITEM);
   }
   else {
     drupal_add_css(drupal_get_path('module', 'archive') .'/archive.css');
@@ -44,34 +51,64 @@
 }
 
 /**
- * Fetch nodes for the selected date, or current date if none selected.
- *
+ * Fetch nodes of $type for the selected date, or current date if none selected.
+ *
+ * @param $type
+ *   Node type name
  * @param $year
  *   Number of year
  * @param $month
  *   Number of month
- * @param $month
+ * @param $day
  *   Number of day
  * @return
  *   A string with the themed page
  */
-function archive_page($year = NULL, $month = NULL, $day = NULL) {
-  $date = _archive_date($year, $month, $day);
-  $output = theme('archive_navigation', $date);
+function archive_page($type = 'all', $year = NULL, $month = NULL, $day = NULL) {
+  $date = _archive_date($type, $year, $month, $day);
+  $output = theme('archive_navigation', $type, $date);
 
   $nodes = variable_get('default_nodes_main', 10);
-  $query = _archive_query($date);
+  $query = _archive_query($type, $date);
   $result = pager_query(array_shift($query), $nodes, 0, NULL, $query);
 
+  // If we have results, display them
   if (db_num_rows($result)) {
     while ($node = db_fetch_object($result)) {
       $output .= node_view(node_load($node->nid), TRUE);
     }
     $output .= theme('pager', NULL, $nodes);
+  }else if($date->days[$date->day] > 0){ // Otherwise redirect the user to the same day viewing all node types
+    drupal_goto(_archive_url('all', $date->year, $date->month, $date->day));
+  }else if($date->months[$date->month] > 0){ // Otherwise redirect the user to the same month viewing all node types
+    drupal_goto(_archive_url('all', $date->year, $date->month));
+  }else if($date->year[$date->year] > 0){ // Otherwise redirect the user to the same year viewing all node types
+    drupal_goto(_archive_url('all', $date->year));
   }
-
+  
   return $output;
 }
+
+function archive_admin_settings(){
+	
+  $types = node_get_types();
+  $final_types = array();
+  foreach($types as $key => $value){
+    $final_types[$key] = $value->name;
+  }
+    
+  $form['archive_type_filters'] = array('#type' => 'checkboxes',
+          '#title' => t('What nodes are available as filters'),
+          '#default_value' => variable_get('archive_type_filters', array_keys($final_types)),
+		  '#options' => $final_types,
+          '#description' => t('Whichever node type you choose here will be available as filters to the user.'));
+  $form['archive_page_path'] = array('#type' => 'textfield',
+          '#title' => t('Choose a path for your main archives page'),
+          '#default_value' => variable_get('archive_page_path', 'archive'),
+          '#description' => t('Choose a path for the main archives site. Something like <em>archives</em> would work nicely.'));
+          
+  return system_settings_form($form);
+}
 
 /**
  * Parses the current URL and populates an archive
@@ -86,9 +123,8 @@
  * @return
  *   A date object with GMT date values and a timezone value
  */
-function _archive_date($year = NULL, $month = NULL, $day = NULL) {
+function _archive_date($type, $year = NULL, $month = NULL, $day = NULL) {
   static $date = null;
-
   if ($date != null) {
     return $date;
   }
@@ -110,15 +146,28 @@
   }
   else {
     $date->year = gmdate('Y', $date->now + $date->tz);
-  }
-
-  $date->start_of_month = gmmktime(0, 0, 0, $date->month, 1, $date->year);
-  $date->month_last_day = gmdate('t', $date->start_of_month);
-  $date->end_of_month   = gmmktime(23, 59, 59, $date->month, $date->month_last_day, $date->year);
-
-  $date->years  = _archive_years($date);
-  $date->months = _archive_months($date);
-  $date->days   = _archive_days($date);
+  }
+  
+  // Set timespan to year, month, or day depending...
+  if($date->day){
+    $date->start_of_timespan = gmmktime(0, 0, 0, $date->month, $date->day, $date->year);
+    $date->end_of_timespan   = gmmktime(23, 59, 59, $date->month, $date->day, $date->year);
+  }else if($date->month){
+    $date->start_of_timespan = gmmktime(0, 0, 0, $date->month, 1, $date->year);
+    $date->end_of_timespan   = gmmktime(23, 59, 59, $date->month, date('t', $date->start_of_timespan), $date->year);
+  }else if($date->year){
+    $date->start_of_timespan = gmmktime(0, 0, 0, 1, 1, $date->year);
+    $date->end_of_timespan   = gmmktime(23, 59, 59, 12, 31, $date->year);
+  }else{
+  	$year = date('Y');
+    $date->start_of_timespan = gmmktime(0, 0, 0, 1, 1, $year);
+    $date->end_of_timespan   = gmmktime(23, 59, 59, 12, 31, $year);    
+  }
+
+  // Arrays of dates that have nodes
+  $date->years  = _archive_years($type, $date);
+  $date->months = _archive_months($type, $date);
+  $date->days   = _archive_days($type, $date);
 
   return $date;
 }
@@ -126,43 +175,63 @@
 /**
  * Builds an SQL query array (query and parameters) to use
  * to display an archive page for the specified date.
- *
+ *
+ * @param $type
+ *    The type of nodes to return
  * @param $date
  *    A date object obtained from _archive_date()
  * @return
  *    An array of (query, param_start, param_end)
  */
-function _archive_query($date) {
+function _archive_query($type, $date) {
+  $final_types = _archive_types_sql_string($type);
+  return array('SELECT n.nid, t.type FROM {node} n JOIN {node_type} t ON t.type = n.type WHERE n.status = 1 ' . $final_types . 'AND n.created >= %d AND n.created < %d ORDER BY n.created DESC', $date->start_of_timespan - $date->tz, $date->end_of_timespan - $date->tz);
+}
 
-  if ($date->day > 0 && $date->month > 0) {
-    // Confine the display interval to only one day
-    $start = gmmktime(0, 0, 0, $date->month, $date->day, $date->year);
-    $end   = gmmktime(0, 0, 0, $date->month, $date->day + 1, $date->year);
-  }
-  elseif ($date->month > 0) {
-    // Confine the display interval to one month
-    $start = gmmktime(0, 0, 0, $date->month, 1, $date->year);
-    $end   = gmmktime(0, 0, 0, $date->month + 1, 1, $date->year);
+/**
+ * Builds a SQL statement to check that the appropriate
+ * node types are being returned 
+ *
+ * @param $type
+ *    The current type we're filtering
+ * @return
+ *    A SQL string
+ */
+function _archive_types_sql_string($type){
+  // Validate type and specify node types to include
+  $final_types = '';
+  if(_archive_validate_type($type) && $type != 'all'){
+  	$final_types = $type; 
+  }else{
+	$types = variable_get('archive_type_filters', array());
+	if(!array_key_exists('0', $types)){ // If no checkboxes selected
+	  foreach($types as $key => $value){
+	    if(!$value){
+	      unset($types[$key]);
+	    }
+	  }
+      $final_types = join(array_keys($types), '", "');
+	}
   }
-  else {
-    // Confine the display interval to one year
-    $start = gmmktime(0, 0, 0, 1, 1, $date->year);
-    $end   = gmmktime(0, 0, 0, 1, 1, $date->year + 1);
+  if(strlen($final_types) > 0){
+    $final_types = 'AND t.type IN ("' . $final_types . '") ';
   }
-
-  return array('SELECT nid, type FROM {node} WHERE status = 1 AND created >= %d AND created < %d ORDER BY created DESC', $start - $date->tz, $end - $date->tz);
+  return $final_types;
 }
 
 /**
  * Returns the range of years with nodes.
- *
+ *
+ * @param $type
+ *    The current type we're filtering
  * @param $date
  *    A date object obtained from _archive_date()
  * @return
  *    An array of the (first year with posts, last year with posts).
  */
-function _archive_years($date) {
-  $result = db_query(db_rewrite_sql('SELECT MIN(created) min_date, MAX(created) max_date FROM {node} n WHERE n.status = 1'));
+function _archive_years($type, $date) {
+  $final_types = _archive_types_sql_string($type);
+  $result = db_query(db_rewrite_sql('SELECT MIN(n.created) AS min_date, MAX(n.created) AS max_date FROM {node} n JOIN {node_type} t ON t.type = n.type WHERE ' . $final_types . 'n.status = 1'));
   $min_max = db_fetch_object($result);
   return array(gmdate('Y', $min_max->min_date + $date->tz), gmdate('Y', $min_max->max_date + $date->tz));
 }
@@ -170,18 +239,21 @@
 /**
  * Returns the months of a given year which have nodes.
  * Note: FROM_UNIXTIME could be used, but it is MySQL only and has timezone issues.
- *
+ *
+ * @param $type
+ *    The current type we're filtering
  * @param $date
  *    A date object obtained from _archive_date()
  * @return
  *    An array of months with number of posts for each.
  */
-function _archive_months($date) {
+function _archive_months($type, $date) {
+  $final_types = _archive_types_sql_string($type);
   $months_with_posts = array();
   foreach (range(1, 12) as $month) {
     $start  = gmmktime(0, 0, 0, $month, 1, $date->year) - $date->tz;
-    $end    = gmmktime(0, 0, 0, $month + 1, 1, $date->year) - $date->tz;
-    $result = db_query(db_rewrite_sql('SELECT COUNT(*) count FROM {node} n WHERE n.status = 1 AND n.created >= %d AND n.created < %d'), $start, $end);
+    $end    = gmmktime(23, 59, 59, $month, date('t', $start), $date->year) - $date->tz;
+    $result = db_query(db_rewrite_sql('SELECT COUNT(*) count FROM {node} n JOIN {node_type} t ON t.type = n.type WHERE n.status = 1 ' . $final_types . 'AND n.created >= %d AND n.created < %d'), $start, $end);
     $row = db_fetch_object($result);
     $months_with_posts[$month] = $row->count;
   }
@@ -196,9 +268,13 @@
  * @return
  *    An array of days having posts with number of posts for each.
  */
-function _archive_days($date) {
-
-  $result = db_query(db_rewrite_sql('SELECT n.nid, n.created FROM {node} n WHERE n.status = 1 AND n.created BETWEEN %d AND %d ORDER BY n.created'), $date->start_of_month - $date->tz, $date->end_of_month - $date->tz);
+function _archive_days($type, $date) {
+  $final_types = _archive_types_sql_string($type);
+  // Get month beginning, end
+  $month_start = gmmktime(0, 0, 0, $date->month, 1, $date->year);
+  $month_end = gmmktime(0, 0, 0, $date->month, date('t', $month_start), $date->year);
+  
+  $result = db_query(db_rewrite_sql('SELECT n.nid, n.created FROM {node} n JOIN {node_type} t ON t.type = n.type WHERE n.status = 1 ' . $final_types . 'AND n.created BETWEEN %d AND %d ORDER BY n.created'), $month_start - $date->tz, $month_end - $date->tz);
 
   $days_with_posts = array();
   while ($day_with_post = db_fetch_object($result)) {
@@ -210,10 +286,48 @@
       $days_with_posts[$daynum] = 1;
     }
   }
-
   return $days_with_posts;
 }
 
+/**
+ * Returns the different node types that have nodes
+ *
+ * @param $include_all
+ *   A Boolean representing whether the fake node-type "All" should be included
+ * @return
+ *    An array of node-types to number of posts of that type
+ */
+function _archive_node_types($date) {
+	
+  $types = variable_get('archive_type_filters', array());
+  if($types[0] == '1'){
+    return array();
+  }
+  foreach($types as $key => $value){
+  	if(!$value){
+  	  unset($types[$key]);
+  	}else{
+      $types[$key] = 0;
+  	}
+  }
+  
+  $result = db_query('SELECT t.type, t.name, COUNT(n.nid) AS node_count FROM {node} n JOIN {node_type} t ON t.type = n.type WHERE n.status = 1 AND t.type IN ("' . join(array_keys($types), '", "') . '") AND n.created BETWEEN %d AND %d GROUP BY n.type ORDER BY n.created', $date->start_of_timespan - $date->tz, $date->end_of_timespan - $date->tz);
+  
+  $types['all'] = array('count' => 0,
+  						'name' => t('All'));
+  						
+  while($row = db_fetch_array($result)){
+    $types[$row['type']] = array('count'=> $row['node_count'],
+    							 'name' => $row['name']);
+    $types['all']['count'] += $row['node_count'];
+  }
+  
+  // Alphabetize our list
+  ksort($types);
+  
+  return $types;
+}
+
 /**
  * Check if given year is valid for a Drupal archive
  *
@@ -262,6 +376,26 @@
   }
 }
 
+/**
+ * Check if given node type is valid for a Drupal archive
+ *
+ * @param $type
+ *    The year to check
+ * @return
+ *    TRUE or FALSE
+ */
+function _archive_validate_type($type) {
+  $types = variable_get('archive_type_filters', array());
+  foreach($types as $key => $value){
+  	if(!$value){
+  	  unset($types[$key]);
+  	}else{
+      $types[$key] = 0;
+  	}
+  }
+  return in_array($type, array_keys($types));
+}
+
 /**
  * Generate an archive URL based on the $y, $m and $d
  * provided, falling back on the $date properties if
@@ -270,7 +404,9 @@
  * Validation checking included for $date properties,
  * because those could be zero, if not defined from the
  * URL.
- *
+ *
+ * @param $type
+ *    The type to use if valid
  * @param $y
  *    The year to use if valid
  * @param $m
@@ -280,9 +416,14 @@
  * @return
  *    A string with the generated archive URL
  */
-function _archive_url($date, $y = 0, $m = 0, $d = 0) {
-  $url = 'archive';
-
+function _archive_url($type, $y = 0, $m = 0, $d = 0) {
+  $url = variable_get('archive_page_path', 'archive');
+  if(_archive_validate_type($type)){
+    $url .= '/' . $type;
+  }else{
+    $url .= '/all';
+  }
+  
   if (_archive_validate_year($y)) {
     $url .= '/'. $y;
     if (_archive_validate_month($m)) {
@@ -292,18 +433,21 @@
       }
     }
   }
-  elseif (_archive_validate_year($date->year) && _archive_validate_month($m)) {
-    $url .= '/'. $date->year .'/'. $m;
-    if (_archive_validate_day($date->year, $m, $d)) {
-      $url .= '/'. $d;
-    }
-  }
-  elseif (_archive_validate_year($date->year) && _archive_validate_month($date->month)) {
-    $url .= '/'. $date->year .'/'. $date->month;
-    if (_archive_validate_day($date->year, $date->month, $d)) {
-      $url .= '/'. $d;
+  elseif (_archive_validate_year($date->year)){
+  	$url .= '/'. $date->year; 
+    if(_archive_validate_month($m)) {
+      $url .= '/'. $m;
+	  if (_archive_validate_day($date->year, $m, $d)) {
+	    $url .= '/'. $d;
+	  }
+    }else if(_archive_validate_month($date->month)){
+      $url .= '/'. $date->month;
+      if (_archive_validate_day($date->year, $date->month, $date->day)) {
+	    $url .= '/'. $date->day;
+	  }
     }
   }
+  
   return $url;
 }
 
@@ -327,16 +471,22 @@
  * Theme the archive navigation with years, months and dates by default.
  * @ingroup themeable
  */
-function theme_archive_navigation($date) {
-  $output  = "<div id=\"archive-container\"><dl><dt>". t('Date') ."</dt><dd>\n";
-  $output .= theme('archive_navigation_years', $date);
+function theme_archive_navigation($type, $date) {
+  $output  = "<div id=\"archive-container\"><dl><dt>". t('Date') . "</dt><dd>\n";
+  $output .= theme('archive_navigation_years', $type, $date);
   if (_archive_validate_year($date->year)) {
-    $output .= theme('archive_navigation_months', $date);
+    $output .= theme('archive_navigation_months', $type, $date);
   }
   if (_archive_validate_month($date->month)) {
-    $output .= theme('archive_navigation_days', $date);
+    $output .= theme('archive_navigation_days', $type, $date);
+  }
+  $output .= "</dd>";
+  if(sizeof(_archive_node_types($date)) != 0){
+    $output .= "<dt>". t('Type') ."</dt><dd>\n";
+    $output .= theme('archive_navigation_node_types', $type, $date);
+    $output .= "</dd>";
   }
-  $output .= "</dd></dl></div>\n";
+  $output .= "</dl></div>\n";
   return $output;
 }
 
@@ -344,7 +494,7 @@
  * Theme the list of years for the archive navigation.
  * @ingroup themeable
  */
-function theme_archive_navigation_years($date) {
+function theme_archive_navigation_years($type, $date) {
   $num_to_display = 3;
   $right_offset = min(gmdate('Y', $date->now + $date->tz) - $date->year, 2);
   $left_offset  = $num_to_display - $right_offset;
@@ -362,7 +512,7 @@
 
     $name = gmdate('Y', gmmktime(0, 0, 0, 1, 1, $year));
     if (min($date->years) <= $year && $year <= max($date->years)) {
-        $output .= "<li$class>". l($name, _archive_url($date, $year)). "</li>\n";
+        $output .= "<li$class>". l($name, _archive_url($type, $date->year)). "</li>\n";
     }
     else {
       $output .= "<li$class>$name</li>\n";
@@ -377,12 +527,12 @@
  * Theme the list of months for the archive navigation.
  * @ingroup themeable
  */
-function theme_archive_navigation_months($date) {
+function theme_archive_navigation_months($type, $date) {
   $output = "<ul id=\"archive-months\">\n";
   foreach (range(1, 12) as $month) {
     $class = ($month == $date->month) ? ' class="selected"' : '';
     $name = t(gmdate('M', gmmktime(0, 0, 0, $month, 1, $date->year)));
-    $output .= "<li$class>". ($date->months[$month] > 0 ? l($name, _archive_url($date, 0, $month), array('title' => format_plural($date->months[$month], "1 post", "%count posts"))) : $name) ."</li>\n";
+    $output .= "<li$class>". ($date->months[$month] > 0 ? l($name, _archive_url($type, $date->year, $month), array('title' => format_plural($date->months[$month], "1 post", "@count posts"))) : $name) ."</li>\n";
   }
   $output .= "</ul>\n";
   return $output;
@@ -392,22 +542,49 @@
  * Theme the list of days for the archive navigation.
  * @ingroup themeable
  */
-function theme_archive_navigation_days($date) {
+function theme_archive_navigation_days($type, $date) {
   $output = "";
   $day_stop = gmdate('t', gmmktime(0, 0, 0, $date->month, 1, $date->year));
   $output = "<ul id=\"archive-days\">\n";
-
   for ($day = 1; $day <= $day_stop; $day++) {
     $class = ($day == $date->day ? ' class="selected"' : '');
 
-    $name = gmdate('d', gmmktime(0, 0, 0, $date->month, $day, $date->year));
     if (isset($date->days[$day]) && $date->days[$day] > 0) {
-      $output .= "<li$class>". l($name, _archive_url($date, 0, 0, $day), array("title" => format_plural($date->days[$day], "1 post", "%count posts"))) ."</li>\n";
+      $output .= "<li$class>". l($day, _archive_url($type, $date->year, $date->month, $day), array("title" => format_plural($date->days[$day], "1 post", "@count posts"))) ."</li>\n";
     }
     else {
+      $output .= "<li$class>$day</li>\n";
+    }
+  }
+  $output .= "</ul>\n";
+  return $output;
+}
+
+/**
+ * Theme the list of node types for the archives
+ * @ingroup themeable
+ */
+function theme_archive_navigation_node_types($type, $date) {
+  
+  $output = "";
+  $output = "<ul id=\"archive-node_types\">\n";
+
+  $types_count = _archive_node_types($date);
+  foreach($types_count as $ft_key => $ft_value) {
+  	if(!$ft_value['count']){
+  	  continue;
+  	}
+    $class = ($ft_key == $type ? ' class="selected"' : '');
+    $name = $ft_value['name'];
+    if($types_count[$ft_key]['count'] > 0) {
+      $output .= "<li$class>". l($name, _archive_url($ft_key, $date->year, $date->month, $date->day), array("title" => format_plural($types_count[$ft_key]['count'], "1 post", "@count posts"))) ."</li>\n";
+    }else {
       $output .= "<li$class>$name</li>\n";
     }
   }
   $output .= "</ul>\n";
   return $output;
-}
+}
+
+
+
