<?php
// $Id: notifications.manage.inc,v 1.1.2.3.2.7.2.9 2010/04/08 19:00:23 jareyero Exp $

/**
 * @file
 *   Common functions for bulk management of subscriptions
 */

/**
 * Menu callback: user subscriptions management
 */
function notifications_manage_user_subscriptions($form_state, $account) {
  module_load_include('inc', 'notifications', 'notifications.pages');
  if (isset($form_state['values']['operation']) && $form_state['values']['operation'] == 'delete') {
    $form = notifications_multiple_delete_confirm($form_state, array_filter($form_state['values']['subscriptions']));
    return $form;
  }
  $form = notifications_subscriptions_filter_form();
  $form['filters']['#title'] = t('Filter');
  // Display collapsed only when no filters set
  $form['filters'] += array('#collapsible' => TRUE, '#collapsed' => empty($_SESSION['subscriptions_overview_filter']));
  $form['#theme'] = 'notifications_subscriptions_filter_form';
  $form['admin']  = notifications_manage_subscriptions_form($account);

  return $form;
}

/**
 * Check access for current user to manage subscriptions
 * 
 * @param $sids
 *   Array of subscription ids
 */
function notifications_manage_subscriptions_access($sids) {
  global $user;
  
  if (user_access('administer notifications') || user_access('manage all subscriptions')) {
    return TRUE;
  }
  else {
    $params = array_merge(array($user->uid), array_values($sids));
    $count = db_result(db_query("SELECT COUNT(*) FROM {notifications} WHERE uid = %d AND sid IN (" . db_placeholders($sids) . ')', $params));
    return $count == count($sids);
  }
} 

/**
 * Administer user subscriptions
 * 
 * @param $account
 *   User account or destination
 */
function notifications_manage_subscriptions_form($account = NULL, $full = TRUE) {
  $filter = notifications_subscriptions_build_filter_query($account);
  if ($account) {
    $result = pager_query('SELECT n.*, d.method, d.address FROM {notifications} n INNER JOIN {messaging_destination} d ON n.mdid = d.mdid '. $filter['join'] . $filter['where'] .' ORDER BY n.sid DESC', 50, 0, NULL, $filter['args']);
  } else {
    $result = pager_query('SELECT n.*, d.method, d.address, u.name AS user_name FROM {notifications} n INNER JOIN {messaging_destination} d ON n.mdid = d.mdid '. $filter['join'] .' INNER JOIN {users} u ON n.uid = u.uid '. $filter['where'] .' ORDER BY n.sid DESC', 50, 0, NULL, $filter['args']);
  }
  $form = notifications_manage_subscriptions_form_options($account);
  $form_destination = drupal_get_destination();
  $subscriptions = array();
  $status = _notifications_subscription_status();
  $send_methods = messaging_method_info(NULL, 'name');
  $send_intervals = notifications_send_intervals();
  while ($object = db_fetch_object($result)) {
    $sub = notifications_load_subscription($object);
    $subscriptions[$sub->sid] = '';
    // Naming for this specific subscription, formatted strings    
    $form['type'][$sub->sid] = array('#value' => $sub->get_type('title'));
    // If full loading, load full subscription and add description
    if ($full) {
      //$format = notifications_format_subscription($sub, 'array');
      $form['description'][$sub->sid] = array('#value' => $sub->get_name());
    }
    // If not account, this is an admin form for multiple users, print full account and address
    if (!$account) {
      if ($sub->uid) {
        $username = $sub->get_user_name();
      }
      else {
        // Anonymous subscription, print destination instead
        $dest = $sub->get_destination();
        $username = $dest->address_name() . ' ' . l($dest->format_address(FALSE), 'notifications/destination/' . $sub->mdid . '/manage') ;
      }
      $form['username'][$sub->sid] = array('#value' => $username);
    }
    $form['send_method'][$sub->sid] = array('#value' => !empty($send_methods[$sub->send_method]) ? $send_methods[$sub->send_method] : $sub->send_method);
    $form['send_interval'][$sub->sid] = array('#value' => !empty($send_intervals[$sub->send_interval]) ? $send_intervals[$sub->send_interval] : $sub->send_interval);  
    $form['status'][$sub->sid] =  array('#value' => $status[$sub->status]);
    // These links will be different depending on whether we are under admin or user account
    if ($account) {
      $operations = array(
        l(t('edit'), 'user/'. $account->uid .'/notifications/subscriptions/edit/' . $sub->sid, array('query' => $form_destination)),
        l(t('drop'), 'user/'. $account->uid .'/notifications/subscriptions/delete/' . $sub->sid, array('query' => $form_destination)),
      );
    }
    else {
      $operations = array(
        l(t('edit'), 'notifications/subscription/' . $sub->sid, array('query' => $form_destination)),
        l(t('drop'), 'notifications/unsubscribe/sid/' . $sub->sid, array('query' => $form_destination)),
      );
    }
    $form['operations'][$sub->sid] = array('#value' => implode(', ', $operations));
  }
  $form['subscriptions'] = array('#type' => 'checkboxes', '#options' => $subscriptions);
  $form['pager'] = array('#value' => theme('pager', NULL, 50, 0));
  $form['#theme'] = 'notifications_manage_subscriptions';
  return $form;
}

/**
 * Form options
 */
function notifications_manage_subscriptions_form_options($account) {
  $form['options'] = array(
    '#type' => 'fieldset',
    '#title' => t('Update options'),
    '#prefix' => '<div class="container-inline">',
    '#suffix' => '</div>',
  );
  $options = array();
  foreach (notifications_subscriptions_operations($account) as $operation => $array) {
    if (!empty($array['parent'])) {
      $options[$array['parent']][$operation] = $array['label'];
    } else {  
      $options[$operation] = $array['label'];
    }
  }
  $form['options']['operation'] = array(
    '#type' => 'select',
    '#options' => $options,
    '#default_value' => 'approve',
  );
  $form['options']['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Update'),
    '#validate' => array('notifications_manage_subscriptions_form_validate'),
    '#submit' => array('notifications_manage_subscriptions_form_submit'),
  );
  return $form;  
}

/**
 * Validate notifications_admin_subscriptions form submissions.
 * 
 * Check if any items have been selected to perform the chosen
 * 'Update option' on.
 */
function notifications_manage_subscriptions_form_validate($form, &$form_state) {
  $items = array_filter($form_state['values']['subscriptions']);
  if (count($items) == 0) {
    form_set_error('', t('No items selected.'));
  }
  else if (!notifications_manage_subscriptions_access(array_keys($items))) {
    form_set_error('', t('You don\'t have permissions to manage these subscriptions'));
  }
}

/**
 * Handle manage form submissions, run batch operations
 */
function notifications_manage_subscriptions_form_submit($form, &$form_state) {
  $operations = notifications_subscriptions_operations();
  $operation = $operations[$form_state['values']['operation']];
  // Filter out unchecked subscriptions
  $items = array_filter($form_state['values']['subscriptions']);
 
  if ($function = $operation['callback']) {
    // Add in callback arguments if present.
    if (isset($operation['callback arguments'])) {
      $args = array_merge(array($items), $operation['callback arguments']);
    }
    else {
      $args = array($items);
    }
    call_user_func_array($function, $args);
  }
  else {
    // We need to rebuild the form to go to a second step.  For example, to
    // show the confirmation form for the deletion of subscriptions.
    $form_state['rebuild'] = TRUE;
  }
}

/**
 * Manage destination form. Edit subscriptions for a destination
 */
function notifications_manage_destination_form($form_state, $destination) {
  module_load_include('inc', 'notifications', 'notifications.pages');
  notifications_include('destination.inc');
  if (isset($form_state['values']['operation']) && $form_state['values']['operation'] == 'delete') {
    $form = notifications_multiple_delete_confirm($form_state, array_filter($form_state['values']['subscriptions']));
    return $form;
  }
  //$form = notifications_destination_view_subform($destination);
  $form['description'] = notifications_destination_subform($destination);
  $form['admin'] = notifications_destination_manage_subform($destination);
  $form['admin'] += notifications_manage_subscriptions_form_options($destination);
  $form['extra'] = notifications_manage_destination_extra($destination); 
  return $form;
}

/**
 * Manage destination extra options for administrators
 */
function notifications_manage_destination_extra($destination) {
  if (user_access('administer notifications') && function_exists('notifications_anonymous_manage_links')) {
    foreach (_notifications_anonymous_manage_links('destination', $destination) as $link) {
      $url = url($link['href'], $link['options']);
      $rows[] = array(
        $link['title'],
        l($url, $url),
      );
    }
    $form['links'] = array(
      '#type' => 'item',
      '#title' => t('Anonymous links for this destination'),
      '#value' => theme('table', array(), $rows),
    );
    return $form;
  }
  else {
    return array();
  }
}
/**
 * Build query for node administration filters based on session.
 */
function notifications_subscriptions_build_filter_query($account = NULL) {
  $filters = notifications_subscriptions_filters();

  // Build query
  $where = $args = array();
  $join = '';
  // If account passed, will be the first condition
  if ($account) {
    $where[] = "n.uid = %d";
    $args[] = $account->uid;
  }
  foreach ($_SESSION['subscriptions_overview_filter'] as $index => $filter) {
    list($key, $value) = $filter;
    switch ($key) {
      case 'status':
      case 'send_interval':
        $where[] = "n.$key = %d";
        $args[] = $value;
        break;
      case 'send_method':
      case 'type':
        $where[] = "n.$key = '%s'";
        $args[] = $value;
        break;
    }
    $args[] = $value;
  }
  $where = count($where) ? 'WHERE '. implode(' AND ', $where) : '';

  return array('where' => $where, 'join' => $join, 'args' => $args);
}

/**
 * List node administration filters that can be applied.
 * 
 * @param $admin
 *   Whether this is for the site admin page, will display more options
 */
function notifications_subscriptions_filters($admin = FALSE) {
  global $user;

  $filters['status'] = array(
    'title' => t('status'),
    'options' => _notifications_subscription_status(),
  );
  $filters['type'] = array(
    'title' => t('type'),
    // If not admin page, check access to each type
    'options' => notifications_subscription_types(NULL, 'title', !$admin),
  );
  $filters['send_method'] = array(
    'title' => t('method'),
    // If not admin mode, filter for current user
    'options' => _notifications_send_methods($admin ? NULL : $user),
  );
  $filters['send_interval'] = array(
    'title' => t('interval'), 
    'options' => notifications_send_intervals(),
  );
  // Take out the filters when only one option
  foreach ($filters as $key => $data) {
    if (empty($data['options']) || count($data['options']) == 1) {
      unset($filters[$key]);
    }
  }
  return $filters;
}

/**
 * Subscription mass operations.
 * 
 * @param $account
 *   User account if we are administering subscriptions for this user
 */
function notifications_subscriptions_operations($account = NULL) {
  $operations = array(
    'activate' => array(
      'label' => t('Activate'),
      'callback' => 'notifications_subscriptions_mass_update',
      'callback arguments' => array('updates' => array('status' => NOTIFICATIONS_SUBSCRIPTION_ACTIVE)),
    ),
    'deactivate' => array(
      'label' => t('Deactivate'),
      'callback' => 'notifications_subscriptions_mass_update',
      'callback arguments' => array('updates' => array('status' => NOTIFICATIONS_SUBSCRIPTION_INACTIVE)),
    ),
    'delete' => array(
      'label' => t('Delete'),
      'callback' => NULL,
    ),
  );
  // Block option only for administrators
  if (user_access('administer notifications') || user_access('manage all subscriptions')) {
    $operations['block'] = array(
      'label' => t('Block'),
      'callback' => 'notifications_subscriptions_mass_update',
      'callback arguments' => array('updates' => array('status' => NOTIFICATIONS_SUBSCRIPTION_BLOCKED)),
    );
  }
  // Sending methods, not for destination
  if (!empty($account->mdid)) {
    $parent = t('Change send method to');
    foreach (_notifications_send_methods($account) as $key => $name) {
      $operations['send_method-' . $key] = array(
        'label' => $name,
        'parent' => $parent,
        'callback' => 'notifications_subscriptions_mass_update',
        'callback arguments' => array('updates' => array('send_method' => $key)),
      );
    }
  }
  $parent = t('Change send interval to');
  foreach (notifications_send_intervals() as $key => $name) {
    $operations['send_method-' . $key] = array(
      'label' => $name,
      'parent' => $parent,
      'callback' => 'notifications_subscriptions_mass_update',
      'callback arguments' => array('updates' => array('send_interval' => $key)),
    );
  }

  // Intervals
  return $operations;
}

/**
 * Make mass update of subscriptions, changing all nodes in the $nodes array
 * to update them with the field values in $updates.
 *
 * IMPORTANT NOTE: This function is intended to work when called
 * from a form submit handler. Calling it outside of the form submission
 * process may not work correctly.
 *
 * @param array $subscriptions
 *   Array of subscriptions nid to update.
 * @param array $updates
 *   Array of key/value pairs with node field names and the
 *   value to update that field to.
 */
function notifications_subscriptions_mass_update($subscriptions, $updates) {
  foreach ($subscriptions as $id) {
    _notifications_subscriptions_mass_update_helper($id, $updates);
  }
  drupal_set_message(t('The update has been performed.'));
}

function _notifications_subscriptions_mass_update_helper($sid, $updates) {
  $subs = notifications_load_subscription($sid);
  foreach ($updates as $name => $value) {
    $subs->$name = $value;
  }
  notifications_save_subscription($subs);
  return $subs;  
}

/**
 * Form for multiple delete. When account passed check that all subscriptions belong to the user account
 */
function notifications_multiple_delete_confirm(&$form_state, $items, $destination = NULL) {
  $destination = $destination ? $destination : $_GET['q'];
  if (notifications_manage_subscriptions_access(array_keys($items))) {
    $form['items'] = array('#prefix' => '<ul>', '#suffix' => '</ul>', '#tree' => TRUE);
    // array_filter returns only elements with TRUE values
    foreach ($items as $id => $value) {
      // Load the subscription to display a friendly name
      $subscription = notifications_load_subscription($id);      
      $title = notifications_format_subscription($subscription, 'long');
      $form['items'][$id] = array(
        '#type' => 'hidden',
        '#value' => $id,
        '#prefix' => '<li>',
        '#suffix' => $title ."</li>\n",
      );
    }    
    $form['operation'] = array('#type' => 'hidden', '#value' => 'delete');
    $form['#submit'][] = 'notifications_multiple_delete_confirm_submit';
    $form['#validate'][] = 'notifications_multiple_delete_confirm_validate';
    $form['#redirect'] = $destination;
    return confirm_form($form,
                      t('Are you sure you want to delete these items?'),
                      $destination, t('This action cannot be undone.'),
                      t('Delete all'), t('Cancel'));
  }
  else {
    drupal_set_message(t('Validation error. You don\'t have permission to delete some of these subscriptions'), 'error');
    drupal_access_denied();
  }
}

/**
 * Validate permissions to delete all the subscriptions
 */
function notifications_multiple_delete_confirm_validate($form, &$form_state) {
  if (!notifications_manage_subscriptions_access(array_keys($form_state['values']['items']))) {
    form_set_error('', t('You don\'t have permission to manage all these subscriptions'));
  }
}

/**
 * Submit multiple delete from
 */
function notifications_multiple_delete_confirm_submit($form, &$form_state) {
  if ($form_state['values']['confirm']) {
    foreach ($form_state['values']['items'] as $id => $value) {
      notifications_delete_subscription($id);
    }
    drupal_set_message(t('The subscriptions have been deleted.'));
  }
  return;
}

/**
 * Return form for node administration filters.
 * 
 * @param $admin
 *   Whether this is for the site admin page, will display more options
 */
function notifications_subscriptions_filter_form($admin = FALSE) {
  $session = &$_SESSION['subscriptions_overview_filter'];
  $session = is_array($session) ? $session : array();
  $filters = notifications_subscriptions_filters($admin);

  $i = 0;
  $form['filters'] = array(
    '#type' => 'fieldset',
    '#title' => t('Show only items where'),
    '#theme' => 'node_filters', // We reuse this theme from node admin pages
  );
  $form['#submit'][] = 'notifications_subscriptions_filter_form_submit';
  foreach ($session as $filter) {
    list($type, $value) = $filter;
    $value = $filters[$type]['options'][$value];
    $form['filters']['current'][] = array('#value' => t('<strong>%a</strong> is <strong>%b</strong>', array('%a' => $filters[$type]['title'], '%b' => $value)));
  }

  foreach ($filters as $key => $filter) {
    $names[$key] = $filter['title'];
    $form['filters']['status'][$key] = array('#type' => 'select', '#options' => $filter['options']);
  }

  $form['filters']['filter'] = array('#type' => 'radios', '#options' => $names, '#default_value' => 'status');
  $form['filters']['buttons']['submit'] = array('#type' => 'submit', '#value' => (count($session) ? t('Refine') : t('Filter')));
  if (count($session)) {
    $form['filters']['buttons']['undo'] = array('#type' => 'submit', '#value' => t('Undo'));
    $form['filters']['buttons']['reset'] = array('#type' => 'submit', '#value' => t('Reset'));
  }

  drupal_add_js('misc/form.js', 'core');

  return $form;
}

/**
 * Process result from node administration filter form.
 */
function notifications_subscriptions_filter_form_submit($form, &$form_state) {
  $filters = notifications_subscriptions_filters();
  switch ($form_state['values']['op']) {
    case t('Filter'):
    case t('Refine'):
      if (isset($form_state['values']['filter'])) {
        $filter = $form_state['values']['filter'];
        // Flatten the options array to accommodate hierarchical/nested options.
        $flat_options = form_options_flatten($filters[$filter]['options']);
        if (isset($flat_options[$form_state['values'][$filter]])) {
          $_SESSION['subscriptions_overview_filter'][] = array($filter, $form_state['values'][$filter]);
        }
      }
      break;
    case t('Undo'):
      array_pop($_SESSION['subscriptions_overview_filter']);
      break;
    case t('Reset'):
      $_SESSION['subscriptions_overview_filter'] = array();
      break;
  }
}

/**
 * Theme subscriptions management form
 *
 * @ingroup themeable
 */
function theme_notifications_manage_subscriptions($form) {
  // If there are rows in this form, then $form['title'] contains a list of
  // the title form elements.
  $has_posts = isset($form['type']) && is_array($form['type']);
  $select_header = $has_posts ? theme('table_select_header_cell') : '';
  $header = array($select_header);
  $header[] = t('Type');
  if (!empty($form['description'])) {
    $header[] = t('Description');
  }
  if (!empty($form['username'])) {
    $header[] = t('User');
  }
  if (!empty($form['send_method'])) {
    $header[] = t('Send method');
  }
  if (!empty($form['send_interval'])) {
    $header[] = t('Send interval');
  }
  $header[] = t('Status');
  $header[] = t('Operations');
  $output = '';

  $output .= drupal_render($form['options']);
  if ($has_posts) {
    foreach (element_children($form['type']) as $key) {
      $row = array();
      $row[] = drupal_render($form['subscriptions'][$key]);
      $row[] = drupal_render($form['type'][$key]);
      if (isset($form['description'])) {
        $row[] = drupal_render($form['description'][$key]);
      }
      if (isset($form['username'])) {
        $row[] = drupal_render($form['username'][$key]);
      }
      if (isset($form['send_method'])) {
        $row[] = drupal_render($form['send_method'][$key]);
      }
      if (isset($form['send_interval'])) {
        $row[] = drupal_render($form['send_interval'][$key]);
      }   
      $row[] = drupal_render($form['status'][$key]);
      $row[] = drupal_render($form['operations'][$key]);
      $rows[] = $row;
    }

  }
  else {
    $rows[] = array(array('data' => t('No subscriptions available.'), 'colspan' => '6'));
  }

  $output .= theme('table', $header, $rows);
  if ($form['pager']['#value']) {
    $output .= drupal_render($form['pager']);
  }

  $output .= drupal_render($form);

  return $output;
}

/**
 * Theme node administration filter form.
 *
 * @ingroup themeable
 */
function theme_notifications_subscriptions_filter_form($form) {
  $output = '';
  $output .= '<div id="notifications-admin-filter">';
  $output .= drupal_render($form['filters']);
  $output .= '</div>';
  $output .= drupal_render($form);
  return $output;
}
