Index: signup_status.admin.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/signup_status/signup_status.admin.inc,v
retrieving revision 1.2
diff -u -p -r1.2 signup_status.admin.inc
--- signup_status.admin.inc	19 Sep 2009 18:24:22 -0000	1.2
+++ signup_status.admin.inc	19 Sep 2009 20:49:27 -0000
@@ -202,36 +202,180 @@ function signup_status_admin_settings_fo
  */
 function signup_status_admin_delete(&$form_state, $cid) {
   $codes = signup_status_codes();
-  if (array_key_exists($cid, $codes)) {
-    $form['cid'] = array(
-      '#type' => 'value',
-      '#value' => $cid,
-    );
-    $form['name'] = array(
-      '#type' => 'value',
-      '#value' => $codes[$cid]['name'],
-    );
-    return confirm_form(
-      $form,
-      t('Are you sure you want to delete the status code %name?', array('%name' => $codes[$cid]['name'])),
-      'admin/settings/signup_status/list',
-      t('<p>This action cannot be undone.</p>'),
-      t('Delete'),
-      t('Cancel')
+  if (empty($codes[$cid])) {
+    drupal_set_message(t('The status you are trying to delete does not exist.'), 'error');
+    return drupal_goto('admin/settings/signup_status');
+  }
+
+  $name = $codes[$cid]['name'];
+  $form['cid'] = array(
+    '#type' => 'value',
+    '#value' => $cid,
+  );
+  $form['name'] = array(
+    '#type' => 'value',
+    '#value' => $name,
+  );
+
+  $total = db_result(db_query('SELECT COUNT(sid) AS total FROM {signup_log} WHERE status = %d', $cid));
+  if ($total > 0) {
+    foreach ($codes as $id => $status) {
+      $options[$id] = $status['name'];
+    }
+    $form['new_status'] = array(
+      '#type' => 'select',
+      '#title' => t('Reassign status'),
+      '#default_value' => $cid,
+      '#options' => $options,
+      '#description' => t('There are !total existing signups with the status of @name. Please select a new status for these signups.', array('!total' => $total, '@name' => $name)),
     );
   }
-  drupal_goto('admin/settings/signup_status/list');
+
+  return confirm_form(
+    $form,
+    t('Are you sure you want to delete the status code %name?', array('%name' => $name)),
+    'admin/settings/signup_status',
+    t('This action cannot be undone.'),
+    t('Delete status'),
+    t('Cancel')
+  );
+}
+
+/**
+ * Validation callback for the signup status code delete page.
+ */
+function signup_status_admin_delete_validate($form, &$form_state) {
+  if ($form_state['values']['new_status'] == $form_state['values']['cid']) {
+    form_set_error('new_status', t('Choose a new signup status for existing signups of status %name.', array('%name' => $form_state['values']['name'])));
+  }
 }
 
 /**
- * Submit hook for the signup status code delete page.
+ * Submit callback for the signup status code delete page.
  */
 function signup_status_admin_delete_submit($form, &$form_state) {
   $values = $form_state['values'];
-  if ($values['confirm'] && $values['cid']) {
-    db_query("DELETE FROM {signup_status_codes} WHERE cid = %d", $values['cid']);
-    drupal_set_message(t('Status code %name has been deleted.', array('%name' => $values['name'])));
-    watchdog('signup_status', 'Status code %name has been deleted.', array('%name' => $values['name']));
+  $codes = signup_status_codes();
+
+  db_query("DELETE FROM {signup_status_codes} WHERE cid = %d", $values['cid']);
+  drupal_set_message(t('Status code %name has been deleted.', array('%name' => $values['name'])));
+  watchdog('signup_status', 'Status code %name has been deleted.', array('%name' => $values['name']));
+
+  if (isset($values['new_status'])) {
+    // We could update all of the signups to the new status in a single query,
+    // but we need to invoke the hook that the status was changed, and that's
+    // potentially expensive, so we do it via the Batch API.
+    $old_status = $codes[$values['cid']];
+    $new_status = $codes[$values['new_status']];
+    signup_status_admin_reassign_status($old_status, $new_status);
+  }
+  else {
+    // Nothing to reassign, we're done.
+    $form_state['redirect'] ='admin/settings/signup_status';
+  }
+}
+
+/**
+ * Reassign all signups from one status to another using the Batch API.
+ *
+ * @param $old_status
+ *   Array defining the old status to assign from. This array must contain at
+ *   least the 'cid' and 'name' keys, as returned by signup_status_codes().
+ * @param $new_status
+ *   Array defining the new status to assign to. This array must contain at
+ *   least the 'cid' and 'name' keys, as returned by signup_status_codes().
+ *
+ * @see signup_status_codes()
+ * @see signup_status_admin_reassign_status_batch()
+ * @see signup_status_admin_reassign_status_finished()
+ */
+function signup_status_admin_reassign_status($old_status, $new_status) {
+  $batch = array(
+    'operations' => array(
+      array('signup_status_admin_reassign_status_batch', array($old_status, $new_status)),
+    ),
+    'finished' => 'signup_status_admin_reassign_status_finished',
+    'title' => $title,
+    'init_message' => $title,
+    'progress_message' => t('Reassigning signups from %old_status status to %new_status status...', array('%old_status' => $old_status['name'], '%new_status' => $new_status['name'])),
+    'error_message' => t('Error reassigning signups from %old_status status to %new_status status...', array('%old_status' => $old_status['name'], '%new_status' => $new_status['name'])),
+    'file' => drupal_get_path('module', 'signup_status') . '/signup_status.admin.inc',
+  );
+  batch_set($batch);
+}
+
+/**
+ * Batch worker to reassign signups from one status to another.
+ *
+ * @param $old_status
+ *   Array defining the old status to assign from. This array must contain at
+ *   least the 'cid' and 'name' keys, as returned by signup_status_codes().
+ * @param $new_status
+ *   Array defining the new status to assign to. This array must contain at
+ *   least the 'cid' and 'name' keys, as returned by signup_status_codes().
+ * @param $context
+ *   Reference to a Batch API context array to track progress of the batch.
+ *
+ * @see signup_status_admin_reassign_status()
+ * @see signup_status_admin_reassign_status_finished()
+ */
+function signup_status_admin_reassign_status_batch($old_status, $new_status, &$context) {
+  if (empty($context['sandbox']['signups'])) {
+    // Initialize the work to do -- remember all the signups we need to change
+    // the status on.
+    $query = db_query('SELECT sid FROM {signup_log} WHERE status = %d', $old_status['cid']);
+    while ($sid = db_result($query)) {
+      $context['sandbox']['signups'][] = $sid;
+    }
+    $context['finished'] = 0;
+    $context['sandbox']['max'] = count($context['sandbox']['signups']);
+    $context['sandbox']['progress'] = 0;
+    $context['message'] = t('Reassigning signups from %old_status status to %new_status status...', array('%old_status' => $old_status['name'], '%new_status' => $new_status['name']));
+    $context['results']['updated'] = 0;
+    $context['results']['processed'] = 0;
+    $context['results']['old_status'] = $old_status;
+    $context['results']['new_status'] = $new_status;
+
+    // In case of a race condition, ensure there's something to process.
+    if (empty($context['sandbox']['max'])) {
+      $context['finished'] = 1;
+      return;
+    }
+  }
+
+  // If there's work to do, process a signup.
+  if (!empty($context['sandbox']['signups'])) {
+    $sid = array_pop($context['sandbox']['signups']);
+    $signup = signup_load_signup($sid);
+    $signup->old_status = $signup->status;
+    $signup->status = $new_status['cid'];
+    db_query("UPDATE {signup_log} SET status = %d WHERE sid = %d", $signup->status, $signup->sid);
+    _signup_status_change('update', $signup);
+    $context['results']['updated']++;
+  }
+  $context['sandbox']['progress']++;
+  $context['results']['processed']++;
+  $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
+}
+
+/**
+ * Batch API callback once all signups have been reassigned to a new status.
+ *
+ * @see signup_status_admin_reassign_status()
+ * @see signup_status_admin_reassign_status_batch()
+ */
+function signup_status_admin_reassign_status_finished($success, $results, $operations) {
+  if ($success) {
+    if (!empty($results)) {
+      drupal_set_message(format_plural($results['updated'], 'Reassigned one signup from the %old_status status to the %new_status status.', 'Reassigned @count signups from the %old_status status to the %new_status status.', array('%old_status' => $results['old_status']['name'], '%new_status' => $results['new_status']['name'])));
+    }
+  }
+  else {
+    // An error occurred.
+    // $operations contains the operations that remained unprocessed.
+    $error_operation = reset($operations);
+    drupal_set_message(t('An error occurred while processing with arguments: @error', array('@error' => var_export($error_operation[0], TRUE))), 'error');
   }
+  drupal_goto('admin/settings/signup_status');
 }
 
