<?php

/**
 * @file
 * Alter the newsletter subscription process to make personal newsletters.
 */

/**
 * Implementation of hook_help().
 */
function simplenews_realname_help($path, $arg) {
  switch ($path) {
    case 'admin/help#simplenews_realname':
      $help = "<p>". t('Simplenews RealName allows you to send personalized newsletters with the Simplenews module by collecting the name of the subscribers, which will be available in the messages as token.') ."</p>";
      return $help;
  }
}

/**
 * Implementation of hook_user().
 */
function simplenews_realname_user($op, &$edit, &$account, $category = NULL) {
  if ($op == 'after_update' && module_exists('realname') && variable_get('simplenews_sync_account', TRUE)) {
    _simplenews_realname_set_realname($account->mail, $account->realname);
  }
}

/**
 * Implementation of hook_mail_alter().
 */
function simplenews_realname_mail_alter(&$message) {
  if (strpos($message['id'], 'simplenews') !== FALSE) {
    $realname = _simplenews_realname_get_realname($message['to']);
    // Replace receiver's name.
    if (isset($message['params']['context']['account'])) {
      $message['params']['context']['account']->name = $realname;
    }
    // Windows based PHP systems don't accept formatted emails.
    if (drupal_substr(PHP_OS, 0, 3) !== 'WIN') {
      $message['to'] = '"'. mime_header_encode($realname) .'" <'. $message['to'] .'>';
    }
  }
}

/**
 * Implementation of hook_token_list().
 */
function simplenews_realname_token_list($type = 'all') {
  $tokens = array();
  switch ($type) {
    case 'all':
    case 'simplenews':
    case 'simplenews_subscription':
      $tokens['simplenews']['simplenews-receiver-realname'] = t('Real name of the newsletter receiver.');
      break;
  }
  return $tokens;
}

/**
 * Implementation of hook_token_value().
 */
function simplenews_realname_token_values($type, $object = NULL, $options = array()) {
  $values = array();
  switch ($type) {
    case 'all':
    case 'simplenews':
    case 'simplenews_subscription':
      $account = $object['account'];
      $realname = _simplenews_realname_get_realname($account->mail);
      $values['simplenews-receiver-realname'] = $realname;
      break;
  }
  return $values;
}

/**
 * Implementation of hook_form_alter().
 */
function simplenews_realname_form_alter(&$form, $form_state, $form_id) {
  global $user;
  // Add textfield for real name to subscription forms.
  if (strpos($form_id, 'simplenews_block_form') !== FALSE
      || $form_id == 'simplenews_subscription_page_form'
      || $form_id == 'simplenews_subscriptions_multi_block_form'
      || $form_id == 'simplenews_subscriptions_admin_form') {
    $realname_field = array(
      '#type' => 'textfield',
      '#title' => t('Name'),
      '#size' => 20,
      '#maxlength' => 255,
      '#required' => TRUE,
      '#default_value' => ($user->uid) ? _simplenews_realname_get_realname($user->mail) : '',
    );
  }
  // Subscription blocks.
  if (strpos($form_id, 'simplenews_block_form') !== FALSE ) {
    if (!simplenews_user_is_subscribed($user->mail, $form['#tid'])) {
      $form['realname'] = $realname_field;
      $form['realname']['#weight'] = -1;
    }
    // Make sure our submit callback executes first.
    array_unshift($form['#submit'], 'simplenews_realname_block_form_submit');
  }
  switch ($form_id) {
    // Subscriptions list.
    case 'simplenews_subscription_admin':
        // Table header. Used as tablesort default.
        $header = array(
          array('data' => t('Email'), 'field' => 'ss.mail', 'sort' => 'asc'),
          array('data' => t('Username'), 'field' => 'u.name'),
          array('data' => t('Real name'), 'field' => 'sr.realname'),
          array('data' => t('Status'), 'field' => 'ss.activated'),
          t('Operations')
        );
        // Data collection with filter and sorting applied.
        $filter = simplenews_build_subscription_filter_query();
        $query = '
          SELECT ss.*, u.name, sr.realname
          FROM {simplenews_subscriptions} ss
          LEFT JOIN {users} u ON ss.uid = u.uid
          LEFT JOIN {simplenews_realname} sr ON ss.mail = sr.mail
          INNER JOIN {simplenews_snid_tid} s ON ss.snid = s.snid
          '. $filter['where'];
        // $count_query used to count distinct records only.
        $count_query = preg_replace('/SELECT.*/', 'SELECT COUNT(DISTINCT ss.snid)', $query);
        $query .= tablesort_sql($header);
        $result = pager_query($query, 30, 0, $count_query);
        // Clear the current state to be able to ordering the table fields.
        unset($form['admin']['mail'], $form['admin']['name'], $form['admin']['status'], $form['admin']['operations']);
        $snids = array();
        // Subscription table and table pager.
        $languages = language_list();
        while ($subscription = db_fetch_object($result)) {
          $snids[$subscription->snid] = '';
          $form['admin']['mail'][$subscription->snid] = array('#value' => $subscription->mail);
          $form['admin']['name'][$subscription->snid] =  array('#value' => isset($subscription->uid) ? l($subscription->name, 'user/'. $subscription->uid) : $subscription->name);
          $form['admin']['realname'][$subscription->snid] = array('#value' => $subscription->realname);
          $form['admin']['status'][$subscription->snid] = array('#value' => theme('simplenews_status', $subscription->activated, 'activated'));
          if (variable_get('language_count', 1) > 1) {
            $form['admin']['language'][$subscription->snid] = array('#value' => $languages[$subscription->language]->name);
          }
          $form['admin']['operations'][$subscription->snid] = array('#value' => l(t('edit'), 'admin/content/simplenews/users/edit/'. $subscription->snid, array(), drupal_get_destination()));
        }
        $form['admin']['snids'] = array('#type' => 'checkboxes', '#options' => $snids);
        break;
    // Mass subscribe.
    case 'simplenews_subscription_list_add':
        unset($form['emails']);
        $form['items'] = array(
          '#type' => 'textarea',
          '#title' => t('Subscription items'),
          '#cols' => 60,
          '#rows' => 5,
          '#weight' => 0,
          '#description' => t('One subscription item per each line. Email addresses and names must be separated by semicolon. <strong>Example</strong>: John Doe;email@example.com'),
        );
        $form['#submit'] = array('simplenews_realname_subscription_list_add_submit');
        break;
    // Subscription settings.
    case 'simplenews_admin_settings_subscription':
        $form['simplenews_subscription']['account']['simplenews_sync_account']['#description'] .= ' '. t('<em>Note:</em> If checked, when accounts are updated, the subscriber\'s real name with the same email address will be updated.');
        break;
    // Export.
    case 'simplenews_subscription_list_export':
        $form['#after_build'] = array('simplenews_realname_admin_export_after_build');
        break;
    // Multi-subscription block.
    case 'simplenews_subscriptions_multi_block_form':
      $form['realname'] = $realname_field;
      $form['realname']['#weight'] = 9;
      // Add after_build callback to skip "Name" validation on unsubscription.
      $form['#after_build'] = array('simplenews_realname_multiblock_form_after_build');
      // Make sure our submit callback executes first.
      array_unshift($form['#submit'], 'simplenews_realname_multiblock_form_submit');
      break;
    // Subscription page (for anonymous users).
    case 'simplenews_subscriptions_admin_form':
        $form['subscriptions']['realname'] = $realname_field;
        $form['subscriptions']['realname']['#default_value'] = _simplenews_realname_get_realname($form['subscriptions']['mail']['#value']);
        // Add after_build callback to skip "Name" validation on unsubscription.
        $form['#after_build'] = array('simplenews_realname_subscriptions_page_form_after_build');
        // Make sure our submit callback executes first.
        array_unshift($form['#submit'], 'simplenews_realname_subscriptions_page_form_submit');
        break;
    // Subscriptions page.
    case 'simplenews_subscriptions_page_form':
        $form['subscriptions']['realname'] = $realname_field;
        // Add after_build callback to skip "Name" validation on unsubscription.
        $form['#after_build'] = array('simplenews_realname_subscriptions_page_form_after_build');
        // Make sure our submit callback executes first.
        array_unshift($form['#submit'], 'simplenews_realname_subscriptions_page_form_submit');
        break;
    // Delete multiple subscriptions.
    case 'simplenews_subscription_multiple_delete_confirm':
        // Make sure that our own submit callback executed first.
        array_unshift($form['#submit'], 'simplenews_realname_subscription_multiple_delete_confirm_submit');
        break;
  }
}

/**
 * Menu callback: Export names and email address of subscriptions.
 */
function simplenews_realname_admin_export_after_build($form, $form_element) {
  if (isset($form_element['values']['op']) && $form_element['values']['op'] == t('Export')) {
    $states = array_filter($form_element['values']['states']);
    $newsletters = array_filter($form_element['values']['newsletters']);

    // Build where clause for active/inactive state and newsletter selection.
    if (isset($states['active'])) {
      $where[] = 's.activated = 1';
    }
    if (isset($states['inactive'])) {
      $where[] = 's.activated = 0';
    }
    $where = isset($where) ? implode(' OR ', $where) : NULL;
    foreach (simplenews_get_newsletters(variable_get('simplenews_vid', ''), TRUE) as $newsletter) {
      if (isset($newsletters[$newsletter->tid])) {
        $where_tid[] = 't.tid = '. $newsletter->tid;
      }
    }
    $where_tid = isset($where_tid) ? implode(' OR ', $where_tid) : NULL;

    // Get subscription data
    if (isset($where) && isset($where_tid)) {
      $query = '
        SELECT DISTINCT r.realname, s.mail
        FROM {simplenews_realname} r
        INNER JOIN {simplenews_subscriptions} s ON r.mail = s.mail
        INNER JOIN {simplenews_snid_tid} t ON s.snid = t.snid AND t.status = 1
        WHERE ('. $where .') AND ('. $where_tid .')';
      $result = db_query($query);
      while ($item = db_fetch_array($result)) {
        $items[] = implode(";", $item);
      }
    }

    // Build form field containing exported emails.
    // The field will be included in the form where at the ['emails'] place holder.
    if (isset($items)) {
      $exported_items = implode("\n", $items);
    }
    else {
      $exported_items .= t('No addresses were found.');
    }
    $form['emails'] = array(
      '#type' => 'textarea',
      '#title' => t('Export results'),
      '#cols' => 60,
      '#rows' => 5,
      '#value' => $exported_items,
    );
  }
  return $form;
}

/**
 * Handle submission of the mass subscription form and saving of the data to the database.
 */
function simplenews_realname_subscription_list_add_submit($form, &$form_state) {
  $tree = taxonomy_get_tree(variable_get('simplenews_vid', ''));
  $added = array();
  $invalid = array();
  $checked_newsletters = array_filter($form_state['values']['newsletters']);
  $langcode = $form_state['values']['language'];

  $items = preg_split("/[\n]/", $form_state['values']['items']);
  foreach ($items as $subscription) {
    $subscriptions[] = preg_split("/[;]+/", $subscription);
  }

  foreach ($subscriptions as $subscription) {
    // Check if we have just one segment, most likely the address.
    if (empty($subscription[1])) {
      $realname = '';
      $mail = trim($subscription[0]);
    }
    else {
      $realname = $subscription[0];
      $mail = trim($subscription[1]);
    }
    if (valid_email_address($mail)) {
      foreach ($checked_newsletters as $tid) {
        $newsletter = taxonomy_get_term($tid);
        _simplenews_realname_set_realname($mail, $realname);
        simplenews_subscribe_user($mail, $newsletter->tid, FALSE, 'mass subscribe', $langcode);
        $added[] = $mail;
      }
    }
    else {
      $invalid[] = $mail;
    }
  }

  if ($added) {
    $added = implode(", ", $added);
    drupal_set_message(t('The following addresses were added or updated: %added.', array('%added' => $added)));

    $newsletter_names = array();
    foreach ($checked_newsletters as $tid) {
      $newsletter = taxonomy_get_term($tid);
      $newsletter_names[] = $newsletter->name;
    }
    drupal_set_message(t('The addresses were subscribed to the following newsletters: %newsletters.', array('%newsletters' => implode(', ', $newsletter_names))));
  }
  else {
    drupal_set_message(t('No addresses were added.'));
  }

  if ($invalid) {
    $invalid = implode(", ", $invalid);
    drupal_set_message(t('The following addresses were invalid: %invalid.', array('%invalid' => $invalid)), 'error');
  }
}

/**
 * Handle saving of the additional data to the database.
 */
function simplenews_realname_block_form_submit($form, &$form_state) {
  switch ($form_state['values']['action']) {
    case 'subscribe':
      simplenews_realname_subscription_blocks_form_submit($form, $form_state);
      break;
  }
}

/**
 * Handle saving of the additional data to the database.
 */
function simplenews_realname_multiblock_form_submit($form, &$form_state) {
  switch ($form_state['values']['op']) {
    case t('Subscribe'):
    case t('Update'):
      simplenews_realname_subscription_blocks_form_submit($form, $form_state);
      break;
  }
}

/**
 * Handle saving of the additional data to the database for subscription blocks.
 */
function simplenews_realname_subscription_blocks_form_submit($form, &$form_state) {
  $mail = $form_state['values']['mail'];
  $realname = $form_state['values']['realname'];
  $update = isset($form_state['values']['op']) && $form_state['values']['op'] == t('Update');
  if ($update || !_simplenews_realname_has_realname($mail)) {
    _simplenews_realname_set_realname($mail, $realname);
  }
}

/**
 * After build callback to skip "Name" validation on unsubscription.
 */
function simplenews_realname_multiblock_form_after_build($form, &$form_state) {
  switch ($form_state['values']['op']) {
    case t('Unsubscribe'):
      unset($form['realname']['#required']);
      break;
  }
  return $form;
}

/**
 * Handle saving of the additional data to the database.
 */
function simplenews_realname_subscriptions_page_form_submit($form, &$form_state) {
  switch ($form_state['values']['op']) {
    case t('Subscribe'):
    case t('Update'):
      _simplenews_realname_set_realname($form_state['values']['mail'], $form_state['values']['realname']);
      break;
  }
}

/**
 * After build callback to skip "Name" validation on unsubscription.
 */
function simplenews_realname_subscriptions_page_form_after_build($form, &$form_state) {
  switch ($form_state['values']['op']) {
    case t('Unsubscribe'):
      unset($form['subscriptions']['realname']['#required']);
      break;
    case t('Update'):
      $checked_newsletters = array_filter($form_state['values']['newsletters']);
      if (!count($checked_newsletters)) {
        unset($form['subscriptions']['realname']['#required']);
      }
      break;
  }
  return $form;
}

/**
 * Handle deleting of the additional data to the database.
 */
function simplenews_realname_subscription_multiple_delete_confirm_submit($form, &$form_state) {
  if ($form_state['values']['confirm']) {
    foreach ($form_state['values']['snids'] as $snid => $value) {
      $mail = db_result(db_query('SELECT mail FROM {simplenews_subscriptions} WHERE snid = %d', $snid));
      _simplenews_realname_set_realname($mail, '', TRUE);
    }
  }
}

/**
 * Theme subscription administration overview.
 */
function phptemplate_simplenews_subscription_list($form) {
  // Subscription table header.
  $header = array(
    theme('table_select_header_cell'),
    array('data' => t('Email'), 'field' => 'ss.mail', 'sort' => 'asc'),
    array('data' => t('Username'), 'field' => 'u.name'),
    array('data' => t('Real name'), 'field' => 'sr.realname'),
    array('data' => t('Status'), 'field' => 'ss.activated'),
  );
  if (variable_get('language_count', 1) > 1) {
    $header[] = array('data' => t('Language'), 'field' => 'ss.language');
  }
  $header[] = t('Operations');

  $colcount = 6;
  if (variable_get('language_count', 1) > 1) {
    $colcount = 7;
  }

  // Subscription table.
  $output = drupal_render($form['options']);
  if (isset($form['mail']) && is_array($form['mail'])) {
    foreach (element_children($form['mail']) as $key) {
      $row = array();
      $row[] = drupal_render($form['snids'][$key]);
      $row[] = drupal_render($form['mail'][$key]);
      $row[] = drupal_render($form['name'][$key]);
      $row[] = drupal_render($form['realname'][$key]);
      $row[] = drupal_render($form['status'][$key]);
      if (variable_get('language_count', 1) > 1) {
        $row[] = drupal_render($form['language'][$key]);
      }
      $row[] = drupal_render($form['operations'][$key]);
      $rows[] = $row;
    }
  }
  else  {
    $rows[] = array(array('data' => t('No subscriptions available.'), 'colspan' => $colcount));
  }

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

  return $output;
}

/**
 * Helper function to set the real name of the user.
 */
function _simplenews_realname_set_realname($mail, $realname, $remove = FALSE) {
  if ($remove) {
    db_query("DELETE FROM {simplenews_realname} WHERE mail = '%s'", $mail);
  }
  else {
    $update = _simplenews_realname_has_realname($mail) ? 'mail' : array();
    $values = array('mail' => $mail, 'realname' => $realname);
    drupal_write_record('simplenews_realname', $values, $update);
  }
}

/**
 * Helper function to get the real name of the user.
 */
function _simplenews_realname_get_realname($mail) {
   // Check if we have a name for the given email address.
  $result = _simplenews_realname_has_realname($mail);
  // The user is already subscribed once.
  if ($result) {
    $realname = $result;
  }
  else {
    $account = user_load(array('mail' => $mail));
    // Maybe the subscriber is a registered user and has a real name.
    if ($account && $account->uid != 0) {
      // Use the name provided by the RealName module if possible.
      if (module_exists('realname') && isset($account->realname)) {
        $realname = $account->realname;
      }
      // Otherwise use the username as default.
      else {
        $realname = $account->name;
      }
    }
    // The subscriber is anonymous after all.
    else {
      $realname = t('Subscriber');
    }
  }

  return check_plain($realname);
}

/**
 * Helper function to determine if the user has a real name.
 */
function _simplenews_realname_has_realname($mail) {
  return db_result(db_query("SELECT realname FROM {simplenews_realname} sr WHERE sr.mail = '%s'", $mail));
}
