Index: resource_conflict.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/resource_conflict/resource_conflict.install,v
retrieving revision 1.2
diff -u -p -r1.2 resource_conflict.install
--- resource_conflict.install	10 Dec 2008 17:29:50 -0000	1.2
+++ resource_conflict.install	1 Jun 2010 14:30:07 -0000
@@ -7,9 +7,12 @@
 function resource_conflict_uninstall() {
   _resource_conflict_variable_delete_like('rc_type_%');
   _resource_conflict_variable_delete_like('rc_date_field_%');
+  _resource_conflict_variable_delete_like('rc_repeat_type_%');
+  _resource_conflict_variable_delete_like('rc_repeat_field_%');
   _resource_conflict_variable_delete_like('rc_reference_fields_%');
   
   variable_del('rc_types');
+  variable_del('rc_repeat_types');
 }
 
 /**
Index: resource_conflict.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/resource_conflict/resource_conflict.module,v
retrieving revision 1.8
diff -u -p -r1.8 resource_conflict.module
--- resource_conflict.module	30 May 2010 21:22:25 -0000	1.8
+++ resource_conflict.module	1 Jun 2010 14:30:07 -0000
@@ -11,54 +11,83 @@ function resource_conflict_nodeapi(&$nod
   switch ($op) {
     case 'validate':
       $type = $node->type;
-      if (!variable_get('rc_type_' . $type, FALSE)) {
-        // Conflict handling is not enabled for this node.
-        break;
-      }
-
-      // Find the date field to use for time overlapping_node_ids detection.
-      $date_field = variable_get('rc_date_field_' . $type, FALSE);
-
-      $overlapping_node_ids = array();
-
-      if (strpos($date_field, 'field_', 0) === 0) {
-        // Get the start and end Date of the current node
-        $start = $node->{$date_field}[0]['value'];
-        $end   = $node->{$date_field}[0]['value2'];
-
-        // Get all conflicting Date nodes
-        if (!empty($start) && !empty($end)) {
-          $overlapping_node_ids = _resource_conflict_overlaps_from_date($start, $end);
+      if (variable_get('rc_type_' . $type, FALSE)) {
+        // check if conflict handling is enabled for this node.
+        // Find the date field to use for time overlapping_node_ids detection.
+        $date_field = variable_get('rc_date_field_' . $type, FALSE);
+  
+        $overlapping_node_ids = array();
+        $overlapping_availability_node_ids = array();
+  
+        if (strpos($date_field, 'field_', 0) === 0) {
+          // Get the start and end Date of the current node
+          $start = $node->{$date_field}[0]['value'];
+          $end   = $node->{$date_field}[0]['value2'];
+  
+          // Get all conflicting Date nodes
+          if (!empty($start) && !empty($end)) {
+            $overlapping_node_ids = _resource_conflict_overlaps_from_date($start, $end);
+            $overlapping_availability_node_ids = _resource_availability_overlaps_from_date($node, $start, $end);
+          }
+          else {
+            // If we got here, someone broke the requirements, so turn off
+            // resource conflict for this type and notify an admin
+            _resource_conflict_disable($type);
+          }
         }
-        else {
-          // If we got here, someone broke the requirements, so turn off
-          // resource conflict for this type and notify an admin
-          _resource_conflict_disable($type);
+        if (!empty($node->event_start)) {
+          // Get all overlapping events
+          $overlapping_node_ids = array_unique(array_merge($overlapping_node_ids, _resource_conflict_overlaps_from_event($node->event_start, $node->event_end)));
+          $overlapping_availability_node_ids = array_unique(array_merge($overlapping_availability_node_ids, _resource_availability_overlaps_from_event($node, $node->event_start, $node->event_end)));
         }
-      }
-      if (!empty($node->event_start)) {
-        // Get all overlapping events
-        $tmp = _resource_conflict_overlaps_from_event($node->event_start, $node->event_end);
-        $overlapping_node_ids = array_unique(array_merge($overlapping_node_ids, $tmp));
-      }
-
-      // Load conflicting nodes
-      $conflicting_nodes = array();
-      foreach ($overlapping_node_ids as $nid) {
-        // Don't have the node conflict with itself
-        if ($nid != $node->nid) {
-          $conflicting_nodes[$nid] = node_load($nid);
+  
+        // Load conflicting nodes
+        $conflicting_nodes = array();
+        foreach ($overlapping_node_ids as $nid) {
+          // Don't have the node conflict with itself
+          if ($nid != $node->nid) {
+            $conflicting_nodes[$nid] = node_load($nid);
+          }
         }
+  
+        // Display conflict errors
+        _resource_conflict_display_conflict_errors($node, $conflicting_nodes);
+  
+        // Display availability errors
+        _resource_conflict_display_availability_errors($node, $overlapping_availability_node_ids);
       }
-
-      // Display conflict errors
-      _resource_conflict_display_conflict_errors($node, $conflicting_nodes);
       break;
   }
 }
 
 
 /**
+ * Compare our demand to the availability on the resource
+ * and display errors for no intersections
+ *
+ * @param $node the currently validating node
+ * @param $overlapping_availability_node_ids array of node and delta that have availability with this node
+ */
+function _resource_conflict_display_availability_errors($node, $overlapping_availability_node_ids) {
+  $availability_types = _resource_conflict_get_availability_enabled_types();
+  $availability_check = FALSE;
+  foreach (_resource_conflict_get_node_resource_demand($node) as $nid => $dummy) {
+    $noderef = node_load($nid);
+    $availability_check = TRUE;
+    foreach ($availability_types as $availability_type) {
+      // is the availability set on this type
+      $availability_check = $availability_check && variable_get('rc_repeat_type_' . $noderef->type, FALSE);
+    }
+  }
+  $error = t("There are no available time slots on the resource for the time span you have requested.");
+  // if admin enabled the ability for users to check - and did the user enable force non-overlapping
+  if (!count($overlapping_availability_node_ids) && $availability_check) {
+    $error_id = 'availability_error' . $node->nid;
+    form_set_error($error_id, $error);
+  }
+}
+
+/**
  * Compare our demand to the demand of overlapping nodes
  * and display errors for the intersections
  *
@@ -84,7 +113,7 @@ function _resource_conflict_display_conf
       if (strpos($date_field, 'field_', 0) === 0) {
         $type = DATE_ISO;
         // If date_start is not in DATE_ISO set the type to DATE_DATETIME.
-        if (!date_is_valid($date_start,DATE_ISO)) {
+        if (!date_is_valid($date_start, DATE_ISO)) {
           $type = DATE_DATETIME;
         }
 
@@ -106,7 +135,6 @@ function _resource_conflict_display_conf
           '%end' => $end,
         )
       );
-
       // This is a bit of a hack, but there's no way with FAPI to have
       // multiple form errors on the same field.  So, we just pass in
       // a bogus (but unique) ID for each error message, to ensure
@@ -114,6 +142,7 @@ function _resource_conflict_display_conf
       // nid of the conflicting resource (thing) appended with the nid
       // of the conflicting node (reservation event).
       $conflict_id = $conflicting_resource->nid . '_' . $conflicting_node->nid;
+
       form_set_error($conflict_id, $error);
     }
   }
@@ -145,6 +174,7 @@ function resource_conflict_form_alter(&$
     }
 
     $date_fields = array();
+    $date_repeat_fields = array();
     if ($type != NULL) {
       $type_info = content_types($type);
       $fields = $type_info['fields'];
@@ -153,9 +183,12 @@ function resource_conflict_form_alter(&$
         if ($field['type'] == 'nodereference') {
           $nodereference_fields[$field['field_name']] = $field['widget']['label'];
         }
-        elseif (($field['type'] == 'date' || $field['type'] == 'datetime') && $field['todate'] == 'required' && $field['required']) {
+        elseif ($field['type'] == 'date' && $field['todate'] == 'required' && $field['required'] && !$field['repeat']) {
           $date_fields[$field['field_name']] = $field['widget']['label'];
         }
+        elseif ($field['type'] == 'date' && $field['todate'] == 'required' && $field['required'] && $field['repeat']) {
+          $date_repeat_fields[$field['field_name']] = $field['widget']['label'];
+        }
       }
     }
 
@@ -175,7 +208,7 @@ function resource_conflict_form_alter(&$
       $date_fields += array('event' => t('Use Event Field from the Event Module'));
     }
 
-    if (empty($date_fields) && !$event_enabled) {
+    if (empty($date_fields) && !$event_enabled && !empty($date_repeat_fields)) {
       if (module_exists('event')) {
         $requirements['event'] = t('This content type is not event enabled. Please event-enable this content type if you wish to use Resource Conflict with the Event module.');
       }
@@ -186,7 +219,15 @@ function resource_conflict_form_alter(&$
       $requirements['date_api'] = t('This content type does not contain any suitable Date fields. Please add at least one Date field with required start and end dates if you wish to use Resource Conflict with the Date module.');
     }
 
-    if (!empty($requirements)) {
+    
+    // Specifically try to target the requirements on the conflict itself
+    if (empty($date_repeat_fields)) {
+      $repeat_requirements['date_repeat'] = t('Availability: This content type does not contain any date repeat fields - these can be used to restrict what times the resource to check conflicts only during availability.');
+      if (empty($date_fields)) {
+        $requirements['date_repeat'] = t('Availability: This content type does not contain any date repeat fields - these can be used to restrict what times the resource to check conflicts only during availability.');
+      }
+    }
+    if ((!empty($requirements)&&empty($repeat_requirements)) || (!empty($requirements)&&!empty($repeat_requirements)))     {
       _resource_conflict_disable($type, TRUE);
 
       $form['resource_conflict_set']['requirements'] = array(
@@ -228,6 +269,24 @@ function resource_conflict_form_alter(&$
       );
     }
 
+    if (empty($repeat_requirements)) {
+      $form['resource_conflict_set']['rc_repeat_type'] = array(
+        '#type' => 'checkbox',
+        '#title' => t('Enable availability resource conflict checking for this content type'),
+        '#default_value' => variable_get('rc_repeat_type_' . $type, 0),
+        '#weight' => -8,
+        '#description' => t('With this enabled when a resources is specified the date range on the resource will be verified for scheduling on it. Example: A room that is only available during certain times of the day - events can only be scheduled on that resource during acceptable times.'),
+      );
+      // split down in a different section - slide in/out on deps making a field have availability is exclusive from a     field using the resource (right?) 
+      $form['resource_conflict_set']['rc_repeat_field'] = array(
+        '#type' => 'select',
+        '#title' => t('Resource Availablity'),
+        '#options' => $date_repeat_fields,
+        '#default_value' => variable_get('rc_repeat_field_' . $type, FALSE),
+        '#description' => t("Select the repeat field to use to allocate availability on a resource."),
+      );
+    }
+
     //set custom validation and submit callbacks
     $form['#validate'][] = 'resource_conflict_form_validate';
     $form['#submit'][] = 'resource_conflict_form_submit';
@@ -239,14 +298,19 @@ function resource_conflict_form_alter(&$
  */
 function resource_conflict_form_validate($form, &$form_state) {
   if ($form_state['values']['form_id'] == 'node_type_form') {
-    if ($form_state['values']['rc_type']) {
+    if (isset($form_state['values']['rc_type'])&&$form_state['values']['rc_type']) {
       $resource_selected = FALSE;
+      if (isset($form_state['values']['rc_repeat_field'])) {
+        $resource_selected = TRUE;
+      }
+      else {
       foreach ($form_state['values']['rc_reference_fields'] as $field) {
         if ($field) {
           $resource_selected = TRUE;
           break;
         }
       }
+      }
       if (!$resource_selected) {
         form_set_error('rc_reference_fields', t("At least one resource field must be set if conflict handling is enabled."));
       }
@@ -258,22 +322,42 @@ function resource_conflict_form_validate
  * Submit the node_type_form
  */
 function resource_conflict_form_submit($form, &$form_state) {
-  $type = $form_state['values']['type'];
-  $old_type = $form_state['values']['old_type'];
-  $conflict_types = variable_get("rc_types", array());
-
-  //unset old entry
-  if (!empty($old_type)) {
-    $key = array_search($old_type, $conflict_types);
-    unset($conflict_types[$key]);
-  }
-
-  //make new entry if this type is conflict handled
-  if ($form_state['values']['rc_type']) {
-    $conflict_types[] = $type;
+  if (isset($form_state['values']['rc_repeat_type'])&&$form_state['values']['rc_repeat_type']) {
+    $type = $form_state['values']['type'];
+    $old_type = $form_state['values']['old_type'];
+    $repeated_types = variable_get("rc_repeat_types", array());
+
+    //unset old entry
+    if (!empty($old_type)) {
+      $key = array_search($old_type, $repeated_types);
+      unset($repeated_types[$key]);
+    }
+
+    //make new entry if this type is conflict handled
+    if ($form_state['values']['rc_repeat_type']) {
+      $repeated_types[] = $type;
+    }
+
+    variable_set("rc_repeat_types", $repeated_types);
+  }
+  else {
+    $type = $form_state['values']['type'];
+    $old_type = $form_state['values']['old_type'];
+    $conflict_types = variable_get("rc_types", array());
+  
+    //unset old entry
+    if (!empty($old_type)) {
+      $key = array_search($old_type, $conflict_types);
+      unset($conflict_types[$key]);
+    }
+  
+    //make new entry if this type is conflict handled
+    if ($form_state['values']['rc_type']) {
+      $conflict_types[] = $type;
+    }
+  
+    variable_set("rc_types", $conflict_types);
   }
-
-  variable_set("rc_types", $conflict_types);
 }
 
 /**
@@ -286,6 +370,16 @@ function _resource_conflict_get_conflict
   $conflict_types = variable_get("rc_types", array());
   return $conflict_types;
 }
+/**
+ * Get the conflict enabled types
+ *
+ * @return
+ *   An array of type names
+ */
+function _resource_conflict_get_availability_enabled_types() {
+  $availability_types = variable_get("rc_repeat_types", array());
+  return $availability_types;
+}
 
 /**
  * Get a conflict enabled node's resource demand
@@ -313,7 +407,7 @@ function _resource_conflict_get_node_res
       if (is_array($reference['nid'])) {
         form_set_error('no_resources', t('No bookable resources have been created. Please create resources to book before attempting to create a resource booking.'));
       }
-      else if (is_numeric($reference['nid'])){
+      elseif (is_numeric($reference['nid'])) {
         $demand[$reference['nid']] = TRUE;
       }
     }
@@ -322,7 +416,7 @@ function _resource_conflict_get_node_res
 }
 
 /**
- * Determine if any nodes conflict between the specified dates using Date API.
+ * Determine if the selected event falls within the availablity between the specified dates using Date API.
  *
  * @param $date_start
  *   The start date of the date to check
@@ -331,16 +425,42 @@ function _resource_conflict_get_node_res
  * @return
  *   An array of node ID's
  */
-function _resource_conflict_overlaps_from_date($date_start, $date_end) {
-  // Make the default type to DATE_ISO.
-  $type = DATE_ISO;
-  // If date_start is not in DATE_ISO set the type to DATE_DATETIME.
-  if (!date_is_valid($date_start,DATE_ISO)) {
-    $type = DATE_DATETIME;
+function _resource_availability_overlaps_from_date($node, $date_start, $date_end) {
+  $start = date_make_date($date_start, 'GMT', DATE_ISO);
+  $end = date_make_date($date_end, 'GMT', DATE_ISO);
+  return _resource_availability_overlaps($node, $start, $end);
   }
+/**
+ * Determine if any nodes conflict between the specified dates using Event.
+ *
+ * @param $event_start
+ *   The start date of the event to check
+ * @param $event_end
+ *   The end date of the event to check.
+ * @return
+ *   An array of node ID's
+ */
+function _resource_availability_overlaps_from_event($node, $event_start, $event_end) {
+  $start = date_make_date($event_start, 'GMT', DATE_UNIX);
+  $end = date_make_date($event_end, 'GMT', DATE_UNIX);
+  return _resource_availability_overlaps($node, $start, $end);
+}
+
 
-  $start = date_make_date($date_start, 'GMT', $type);
-  $end = date_make_date($date_end, 'GMT', $type);
+
+/**
+ * Determine if any nodes conflict between the specified dates using Date API.
+ *
+ * @param $date_start
+ *   The start date of the date to check
+ * @param $date_end
+ *   The end date of the date to check.
+ * @return
+ *   An array of node ID's
+ */
+function _resource_conflict_overlaps_from_date($date_start, $date_end) {
+  $start = date_make_date($date_start, 'GMT', DATE_ISO);
+  $end = date_make_date($date_end, 'GMT', DATE_ISO);
   return _resource_conflict_get_overlaps($start, $end);
 }
 
@@ -387,7 +507,7 @@ function _resource_conflict_get_overlaps
   foreach ($conflict_types as $type) {
     $date_field = variable_get('rc_date_field_' . $type, FALSE);
 
-    if(strpos($date_field, 'field_', 0) === 0) {
+    if (strpos($date_field, 'field_', 0) === 0) {
       $date_db_info = content_database_info(content_fields($date_field));
       $date_table = '{' . $date_db_info['table'] . '}';
 
@@ -413,7 +533,7 @@ function _resource_conflict_get_overlaps
       $result = db_query($query, $event_start, $event_start, $event_end, $event_end, $event_start, $event_end);
 
       // Create an array of all of the results
-      while($row = db_fetch_array($result)) {
+      while ($row = db_fetch_array($result)) {
         $rows[] = $row['nid'];
       }
     }
@@ -422,6 +542,53 @@ function _resource_conflict_get_overlaps
 }
 
 /**
+ * Determine if the event created falls within any of the available times on the resource
+ *
+ * 1. $start is within the event time
+ * 2. $end end is within the event time
+ * 3. The event encompasses $start and $end
+ * 4. Allow the end of one event to occur at the start of the next
+ * 
+ * @param $start
+ *   The start time of events to search as dateAPI object
+ * @param $end
+ *   The end time of events to search as dateAPI object
+ * @return
+ *   An array of node ID's
+ */
+function _resource_availability_overlaps($node, $start, $end) {
+  $date_start = date_convert($start, DATE_OBJECT, DATE_ISO);
+  $date_end = date_convert($end, DATE_OBJECT, DATE_ISO);
+  $event_start = date_convert($start, DATE_OBJECT, DATE_UNIX);
+  $event_end = date_convert($end, DATE_OBJECT, DATE_UNIX);
+
+  $rows = array();
+  $availability_types = _resource_conflict_get_availability_enabled_types();
+  foreach (_resource_conflict_get_node_resource_demand($node) as $nid => $dummy) {
+    $noderef = node_load($nid);
+    foreach ($availability_types as $availability_type) {
+      // is the availability set on this type
+      if (variable_get('rc_repeat_type_' . $noderef->type, FALSE)) {
+        if ($noderef->type == $availability_type) {
+          $avail_reference_field = variable_get('rc_repeat_field_' . $noderef->type, array());
+          foreach ($noderef->$avail_reference_field as $avail) {
+            if (($date_start >= $avail['value'])&&($date_end <= $avail['value2'])) {
+              $rows[] = $avail;
+            }
+            elseif (($event_start >= $avail['value'])&&($event_end <= $avail['value2'])) {
+              $rows[] = $avail;
+            }
+          }
+        }
+      }
+    }
+  }
+
+  return array_unique($rows);
+}
+
+
+/**
  * Disable resource conflict for a type, optionally notifying the user. A
  * message is always logged in the Drupal log. If the content type is not
  * conflict-enabled, nothing is changed.
