<?php
/**
 * @file
 * Cleans up Workflow cruft that may build up over time.
 */

/**
 * Implements hook_menu().
 */
function workflow_cleanup_menu() {
  $items = array();

  $items['admin/config/workflow/workflow/cleanup'] = array(
    'title' => 'Workflow Clean Up',
    'access arguments' => array('administer workflow'),
    'page callback' => 'drupal_get_form',
    'page arguments' => array('workflow_cleanup_form'),
    'type' => MENU_CALLBACK,
    );

  return $items;
}

/**
 * Implements hook_theme().
 */
function workflow_cleanup_theme() {
  return array(
    'workflow_cleanup_form' => array('render element' => 'form'),
    );
}

/**
 * Implements hook_workflow_operations().
 * Might as well eat our own cooking.
 */
function workflow_cleanup_workflow_operations($op, $workflow = NULL, $state = NULL) {
  switch ($op) {
    case 'top_actions':
      $workflows = workflow_get_workflows();
      $alt = t('Clean up workflow cruft');
      $actions = array(
        'workflow-cleanup' => array(
          'title' => t('Clean up'),
          'href' => 'admin/config/workflow/workflow/cleanup',
          'attributes' => array('alt' => $alt, 'title' => $alt),
          ),
        );

      return $actions;
  }
}

/**
 * The main cleanup page.
 */
function workflow_cleanup_form($form, $form_state) {
  $bc = array(l(t('Home'), '<front>'));
  $bc[] = l(t('Configuration'), 'admin/config');
  $bc[] = l(t('Workflow'), 'admin/config/workflow');
  $bc[] = l(t('Workflow'), 'admin/config/workflow/workflow');
  drupal_set_breadcrumb($bc);

  $form = array();

  // Get all of the states, indexed by sid.
  $states = $orphans = $inactive = array();
  foreach (workflow_get_workflow_states() as $state) {
    $states[$state->sid] = $state;
    // Is it associated with a workflow?
    if (empty($state->name)) {
      $orphans[$state->sid] = $state->state;
    }
    else {
      // Is it associated with a workflow?
      if (!$state->status) {
        $inactive[$state->sid] = $state->state;
      }
    }
  }

  // Deal with no orphan states.
  if (!$orphans) {
    $orphans[0] = t('None');
  }

  // Deal with no inactive states.
  if (!$inactive) {
    $inactive[0] = $states[0] = t('None');
  }

  $form['#workflow_states'] = $states;

  $form['no_workflow'] = array(
    '#type' => 'container',
    '#title' => t('Orphaned States'),
    '#description' => t('These states no longer belong to an existing workflow.'),
    '#tree' => TRUE,
    );

  foreach ($orphans as $sid => $state) {
    $form['no_workflow'][$sid]['check'] = array(
      '#type' => 'checkbox',
      '#return_value' => $sid,
      );

    $form['no_workflow'][$sid]['name'] = array(
      '#type' => 'markup',
      '#markup' => check_plain($state),
      );
  }

  $form['inactive'] = array(
    '#type' => 'container',
    '#title' => t('Inactive (Deleted) States'),
    '#description' => t('These states belong to a workflow, but have been marked inactive (deleted).'),
    '#tree' => TRUE,
    );

  foreach ($inactive as $sid => $state) {
    $form['inactive'][$sid]['check'] = array(
      '#type' => 'checkbox',
      '#return_value' => $sid,
      );

    $form['inactive'][$sid]['name'] = array(
      '#type' => 'markup',
      '#markup' => check_plain($state),
      );

    $form['inactive'][$sid]['wf'] = array(
      '#type' => 'markup',
      '#markup' => check_plain($states[$sid]->name),
      );
  }

  $form['submit'] = array('#type' => 'submit', '#value' => t('Delete selected states'));

  return $form;
}

/**
 * Theme the main form.
 */
function theme_workflow_cleanup_form($variables) {
  $form = $variables['form'];
  $output = '';
  $header = array(t('select'), t('State'));

  $rows = array();
  foreach (element_children($form['no_workflow']) as $sid) {
    $rows[] = array(
      drupal_render($form['no_workflow'][$sid]['check']),
      drupal_render($form['no_workflow'][$sid]['name']),
      );
  }

  $output .= '<h3>' . $form['no_workflow']['#title'] . '</h3>';
  $output .= '<div class="description">' . $form['no_workflow']['#description'] . '</div>';
  $output .= theme('table', array('header' => $header, 'rows' => $rows, 'attributes' => array('style' => 'width: auto;')));

  $header[] = t('Workflow');
  $rows = array();
  foreach (element_children($form['inactive']) as $sid) {
    $rows[] = array(
      drupal_render($form['inactive'][$sid]['check']),
      drupal_render($form['inactive'][$sid]['name']),
      drupal_render($form['inactive'][$sid]['wf']),
      );
  }

  $output .= '<h3>' . $form['inactive']['#title'] . '</h3>';
  $output .= '<div class="description">' . $form['inactive']['#description'] . '</div>';
  $output .= theme('table', array('header' => $header, 'rows' => $rows, 'attributes' => array('style' => 'width: auto;')));

  $output .= drupal_render_children($form);
  return $output;
}

/**
 * Submission handler for main cleanup form.
 */
function workflow_cleanup_form_submit($form, $form_state) {
  $states = $form['#workflow_states'];
  foreach (array('no_workflow', 'inactive') as $section) {
    foreach ($form_state['values'][$section] as $sid => $data) {
      // FAPI returns either a 0 or the sid.
      if ($data['check']) {
        // Delete any transitions this state is involved in.
        $trans_del = db_delete('workflow_transitions')->condition('target_sid', $sid)->execute();
        $trans_del += db_delete('workflow_transitions')->condition('sid', $sid)->execute();
        if ($trans_del) {
          drupal_set_message(t('@count transitions for the "@state" state have been deleted.',
            array('@state' => $states[$sid]->state, '@count' => $trans_del)));
        }

        // Remove history records too.
        $hist_del = db_delete('workflow_node_history')->condition('sid', $sid)->execute();
        if ($hist_del) {
          drupal_set_message(t('@count history records for the "@state" state have been deleted.',
            array('@state' => $states[$sid]->state, '@count' => $hist_del)));
        }

        // Go ahead and delete the state.
        db_delete('workflow_states')->condition('sid', $sid)->execute();
        drupal_set_message(t('The "@state" state has been deleted.', array('@state' => $states[$sid]->state)));
      }
    }
  }
}
