From dcf429ee2e4e9f914b8199e95dbe29089559bf12 Mon Sep 17 00:00:00 2001
From: Dave Hall <dave.hall@skwashd.com>
Date: Fri, 2 Mar 2012 23:09:26 +1100
Subject: [PATCH] Issue #769412 by skwashd: Port rollup hours / grouped
 formatting to D7

---
 office_hours.module    |    6 ++
 office_hours.theme.inc |  152 +++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 155 insertions(+), 3 deletions(-)

diff --git a/office_hours.module b/office_hours.module
index c34f08a..d159e92 100644
--- a/office_hours.module
+++ b/office_hours.module
@@ -19,6 +19,7 @@ function office_hours_theme ($existing, $type, $theme, $path) {
   );
   $themes = array(
     'office_hours_formatter_default' => $base + array('render element' => 'element'),
+    'office_hours_formatter_grouped' => $base + array('render element' => 'element'),
     'office_hours' => $base + array('render element' => 'element'),
     'field_multiple_value_form' => $base + array('render element' => 'element'),
     'office_hours_select' => $base + array('render element' => 'element'),
@@ -278,6 +279,11 @@ function office_hours_field_formatter_info() {
       'field types' =>  array('office_hours_formatter_default', 'office_hours', 'office_hours_multiple_values', 'office_hours_select'),
       'multiple values' => FIELD_BEHAVIOR_DEFAULT,
     ),
+    'grouped' => array(
+      'label' => 'grouped',
+      'field types' => array('office_hours'),
+      'multiple values' => FIELD_BEHAVIOR_DEFAULT,
+    ),
   );
 }
 
diff --git a/office_hours.theme.inc b/office_hours.theme.inc
index 2af886f..74936bd 100644
--- a/office_hours.theme.inc
+++ b/office_hours.theme.inc
@@ -9,11 +9,18 @@
  * Theme function for 'default' text field formatter.
  */
 function office_hours_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
+  switch ($display['type']) {
+    case 'grouped':
+      $theme = 'office_hours_formatter_grouped';
+      break;
+
+    default:
+      $theme = 'office_hours_formatter_default';
+  }
+
   $element = array();
-  $settings = $display['settings'];
-  $formatter = $display['type'];
   $element[0] = array(
-    '#markup' => theme($display['type'] . '_formatter_default', array('element' => $items, 'field' => $instance)),
+    '#markup' => theme($theme, array('element' => $items, 'field' => $instance)),
   );
   return $element;
 }
@@ -82,6 +89,99 @@ function theme_office_hours_formatter_default($vars) {
   return $output;
 }
 
+/**
+ * Theme function for 'grouped' text field formatter.
+ */
+function theme_office_hours_formatter_grouped($vars) {
+  $output = '';
+  $groups = array();
+  $first = variable_get('date_first_day', 0);
+  $field = field_info_field($vars['field']['field_name']);
+  $element = $vars['element'];
+  $show_closed = $field['settings']['showclosed'];
+  $weekdays = array(0 => t('Sunday'), 1 => t('Monday'), 2 => t('Tuesday'), 3 => t('Wednesday'), 4 => t('Thursday'), 5 => t('Friday'), 6 => t('Saturday') );
+
+  foreach (element_children($element) as $key => $arraykey) {
+    $item = $element[$arraykey];
+    $day = (int)($item['day'] / 2); // Keys are 0+1 for sunday, 2+3 for monday, etc. Each day may have normal hours + extra hours.
+    $day_name = $weekdays[$day];
+    $strhrs = _office_hours_mil_to_tf(check_plain($item['starthours']));
+    $endhrs = _office_hours_mil_to_tf(check_plain($item['endhours']));
+    if ($field['settings']['hoursformat']) {
+      $strhrs = _office_hours_convert_to_ampm($strhrs);
+      $endhrs = _office_hours_convert_to_ampm($endhrs);
+    }
+
+    // aggregate by hours
+    $group_id = "$strhrs::$endhrs";
+    if (!isset($groups[$group_id])) {
+      $groups[$group_id]['hours'] = array(array('strhrs' => $strhrs, 'endhrs' => $endhrs));
+    }
+    $groups[$group_id]['days'][$day_name] = $day;
+    $group_map[$day_name][$group_id] = $group_id;
+  }
+
+  // Add grouped closed days
+  foreach ($weekdays as $day_num => $day_name) {
+    if (!isset($group_map[$day_name])) {
+      $group_id = 'closed';
+      if (!isset($groups[$group_id])) {
+        $groups[$group_id]['hours'] = array(array('closed' => 'closed'));
+      }
+      $groups[$group_id]['days'][$day_name] = $day_num;
+      $group_map[$day_name][$group_id] = $group_id;
+    }
+  }
+
+  // Process groups
+  foreach ($groups as $group_id => &$group) {
+    // set combined days label
+    _office_hours_set_group_label($group);
+  }
+  unset($group);
+
+  // adjust translation weekday array for first day of week
+  $weekdays = date_week_days_ordered($weekdays);
+
+  // build output
+  $days_rendered = array();
+
+  // output with ordered weekdays to render groups in order
+  foreach ($weekdays as $day_num => $day_name) {
+    if (isset($days_rendered[$day_name]) || !isset($group_map[$day_name])) {
+      continue;
+    }
+
+    foreach ($group_map[$day_name] as $group_id) {
+      $group = $groups[$group_id];
+      foreach (array_keys($group['days']) as $rendered) {
+        $days_rendered[$rendered] = TRUE;
+      }
+
+      if (!$show_closed && 'closed' === $group_id) {
+        continue;
+      }
+
+      $hours = '';
+      if ('closed' === $group_id) {
+        $hours = '<span class="oh-display-hours oh-closed">' . t('Closed') . '</span>';
+      }
+      else {
+        $hours = '<span class="oh-display-hours">' . $group['hours'][0]['strhrs'] . ' - ' . $group['hours'][0]['endhrs'] . '</span>';
+      }
+      if (isset($group['hours'][1])) {
+        $hours .= ', <span class="oh-display-hours">' . $group['hours'][1]['strhrs'] . ' - ' . $group['hours'][1]['endhrs'] . '</span>';
+      }
+    }
+
+    if (!empty($hours)) {
+      $output .= '<div class="oh-display oh-display-grouped"><span class="oh-display-label">' . $group['label'] . '</span>: ' . $hours . '</div>';
+    }
+  }
+  return $output;
+}
+
+
 function theme_office_hours($vars) {
   return $vars['element']['#children'];
 }
@@ -162,3 +262,49 @@ function office_hours_field_multiple_value_form($variables) {
   }
   return $output;
 }
+
+/**
+ * Helper function to set combined days label for hour group
+ */
+function _office_hours_set_group_label(&$group) {
+  // reference days
+  $group_days = &$group['days'];
+  asort($group_days);
+
+  // initialize label
+  list($day_name, $prev_day_num) = each($group_days);
+  $label_start = $day_name;
+  $label_end = '';
+  $label = $label_start;
+
+  // build label
+  while (list($day_name, $day_num) = each($group_days)) {
+    $diff = $day_num - $prev_day_num;
+    if ($diff == 1) {
+      $label_end = $day_name;
+    }
+    else {
+      if ($label_end) {
+        $label .= ' - ' . $label_end;
+      }
+
+      $label_start = $day_name;
+      $label_end = '';
+      $label .= ', ' . $label_start;
+    }
+
+    $prev_day_num = $day_num;
+  }
+
+  // update label if all were consecutive
+  if ($label_end) {
+    $label .= ' - ' . $label_end;
+  }
+
+  // update group
+  $group['label'] = $label;
+
+  // clean up and return
+  unset($group_days);
+  return $label;
+}
-- 
1.7.5.4

