<?php
// $Id: notifications_anonymous.module,v 1.1.2.11 2010/04/08 19:00:22 jareyero Exp $
/**
 * @file
 *   Notifications for anonymous users
 */

/**
 * Implementation of hook_menu()
 */
function notifications_anonymous_menu() {
    // Subscribe links. For this items access will be checked later in the page
  $items['notifications/anonymous/subscribe'] = array(
    'type' => MENU_CALLBACK,
    'page callback' => 'notifications_anonymous_page_subscribe',
    'access callback' => 'notifications_anonymous_subscription_access',
    'access arguments' => array('create'),
    'file' => 'notifications_anonymous.pages.inc',
  );
  // Present form to request subscriptions
  $items['notifications/anonymous/request'] = array (
    'title' => 'Manage subscriptions',
    'page callback' => 'notifications_anonymous_request_page',
    'access callback' => TRUE,
    'file' => 'notifications_anonymous.pages.inc',
    'type' => MENU_CALLBACK,
  );
  // Destination operations
  foreach (array('edit', 'delete', 'manage') as $op) {
    $items['notifications/anonymous/destination/%messaging_destination/' . $op] = array (
      'title' => 'Edit destination',
      'page callback' => 'notifications_anonymous_destination_page',
      'page arguments' => array(3, 4),
      'access callback' => 'notifications_anonymous_destination_access',
      'access arguments' => array(4, 3),
      'file' => 'notifications_anonymous.pages.inc',
      'type' => MENU_CALLBACK,
    );
  }
  // Subscription operations
  foreach (array('edit', 'unsubscribe') as $op) {
    $items['notifications/anonymous/subscription/%notififications_subscription/' . $op] = array (
      'title' => 'Edit subscription',
      'page callback' => 'notifications_anonymous_subscription_page',
      'page arguments' => array(3, 4),
      'access callback' => 'notifications_anonymous_subscription_access',
      'access arguments' => array(4, 3),
      'file' => 'notifications_anonymous.pages.inc',
      'type' => MENU_CALLBACK,
    );
  }
  // Admin settings page
  $items['admin/messaging/notifications/anonymous'] = array(
    'title' => 'Anonymous',
    'description' => 'Settings for anonymous subscriptions',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('notifications_anonymous_admin_settings_form'),
    'access arguments' => array('administer notifications'),
    'type' => MENU_LOCAL_TASK,
    'file' => 'notifications_anonymous.pages.inc',
  );
  return $items;
}

/**
 * Menu access callback for subscriptions
 */
function notifications_anonymous_subscription_access($op = 'create', $subscription = NULL, $account = NULL) {  
  global $user;
  $account = $account ? $account : $user;
  switch ($op) {
    case 'create':
      return user_access('create anonymous subscriptions', $account) && notifications_anonymous_send_methods();
    case 'unsubscribe':
      return !$subscription->uid;
  }
}

/**
 * Menu access callback for destinations
 */
function notifications_anonymous_destination_access($op, $destination = NULL, $account = NULL) {  
  global $user;
  $account = $account ? $account : $user;
  // Access will be granted if anonymous destination or administrator
  if (user_access('administer notifications')) {
    return TRUE;
  }
  elseif (!$destination->uid) {
    switch ($op) {
      case 'manage':
        return user_access('manage own subscriptions', $account);
      case 'edit':
        return user_access('maintain own subscriptions', $account);
      case 'confirm': 
      case 'delete':
        return TRUE;
    }
  }
  else {
    return FALSE;
  }
}

/**
 * Implementation of hook_block()
 */
function notifications_anonymous_block($op = 'list', $delta = 0) {
  global $user;
  // This block needs notifications_ui
  if (!module_exists('notifications_ui')) {
    return;
  }
  elseif ($op == 'list') {
    $blocks[0]['info'] = t('Anonymous subscription links');
    $blocks[0]['cache'] = BLOCK_NO_CACHE;
    return $blocks;
  }
  else if ($op == 'view' && !$user->uid) {
    if ((arg(0) == 'node') && is_numeric(arg(1)) && ($node = node_load(arg(1))) && notifications_ui_node_options($node->type, 'block')) {
      // Only display if we have something for the form
      if ($node_options = notifications_ui_subscribe_options($user, 'node', $node)) {
        $block['subject'] = t('Subscribe to');
        $block['content'] = drupal_get_form('notifications_ui_options_form', $node_options, FALSE);
        return $block;
      }      
    }
    elseif (arg(0) == 'user' && is_numeric(arg(1)) && notifications_ui_account_options('block')) {
      // Only display if we have something for the form
      if (($account = user_load(arg(1))) && ($options = notifications_ui_subscribe_options($user, 'user', $account))) {
        $block['subject'] = t('Subscribe to');
        $block['content'] = drupal_get_form('notifications_ui_options_form', $options, FALSE);
        return $block;
      }       
    }
  }  
}

/**
 * Get list of possible and existing subscriptions for anonymous user
 * 
 * @param $type
 *   Subscription type to get options: 'user', 'node'
 * @param $object
 *   The object to subscribe. It may be $node or $user
 * 
 * @return
 *   Array of subscription options
 *   The enabled ones will have a 'subscriptions' element loaded
 */
function notifications_anonymous_subscribe_options($type, $object) {
  $account = drupal_anonymous_user();
  // Get allowed node options and current subscriptions
  $subscribe_options = notifications_module_information("$type options", $account, $object);
  $allowed_options = array();
  // Get subscription types checking for user access
  $allowed_types = notifications_subscription_types(NULL, NULL, TRUE);
  // We also keep track of event types for each subscription type
  $event_types = array('node' => TRUE);
  foreach ($subscribe_options as $index => $option) {
    if (isset($allowed_types[$option['type']]) && notifications_user_allowed('subscription', $account, (object)$option)) {
      $allowed_options[] = $option;
      // We add the event type to our list
      $event_types[$allowed_types[$option['type']]['event_type']] = TRUE;
    }
  }
  return $allowed_options;
}

/**
 * Get available sending methods for anonymous users
 */
function notifications_anonymous_send_methods() {
  $list = &messaging_static(__FUNCTION__);
  if (!isset($list)) {
    $list = array();
    $allowed = variable_get('notifications_anonymous_send_methods', array('mail'));
    foreach (messaging_method_list() as $method => $name) {
      if (in_array($method, $allowed)) {
        $list[$method] = $name;
      }
    }
  }
  return $list;
}

/**
 * Get available send intervals for anonymous users
 */
function notifications_anonymous_send_intervals() {
  $list = &messaging_static(__FUNCTION__);
  if (!isset($list)) {
    $list = array();
    $allowed = variable_get('notifications_anonymous_send_intervals', array(0));
    foreach (notifications_send_intervals() as $interval => $name) {
      if (in_array($interval, $allowed)) {
        $list[$interval] = $name;
      }
    }
  }
  return $list;
}

/**
 * Implementation of hook_perm()
 */
function notifications_anonymous_perm() {
  return array('create anonymous subscriptions');
}

/**
 * Implementation of hook_form_alter()
 */
function notifications_anonymous_form_alter(&$form, $form_state, $form_id) {
  global $user;
  
  switch ($form_id) {
    case 'notifications_ui_options_form':
      $account = $form['subscriptions']['account'];
      if (!$account->uid && !$user->uid) {
        notifications_include('destination.inc');
        $form += notifications_destination_address_subform($account);
        //$form['destination']['#weight'] = -10;
      }
      break;
  }
}

/**
 * Get link for anonymous subscriptions / destinations
 * 
 * @param $op
 *   Operation: subscribe, unsubscribe, manage, edit
 * @param $params
 *   Array of mixed parameters. Same as notifications_get_links() plus:
 *   - type = 'subscription' | 'destination'
 *   - oid = object id (sid, mdid)
 */
function notifications_anonymous_get_link($op, $params) {
  $params += array(
    'absolute' => TRUE,
  );
  // Diference subscription / destination
  switch ($op) {
    case 'subscribe':
      $elements = array(
        'anonymous',
        'subscribe',
        $params['type'],
        implode(',', array_keys($params['fields'])),
        implode(',', $params['fields'])     
      );
      break;
    case 'confirm':
    case 'edit':
    case 'manage':
    case 'delete':
    case 'unsubscribe': 
      $elements = array(
        'anonymous',
        $params['type'],
        $params['oid'],
        $op,
      );
      // Anonymous links are signed as default
      $params += array('signed' => TRUE);
      break;
  }
  return _notifications_get_link($elements, $params);
}

/**
 * Get raw links to manage subscription / destination
 */
function _notifications_anonymous_manage_links($type, $object) {
  $links = array();
  $params = array(
    'absolute' => TRUE,
    'signed' => TRUE,
    'type' => $type, // subscription / destination
  );
  if ($type == 'destination') {
    $params['oid'] = $params['mdid'] = $object->mdid;
    $link_types = array(
      'manage' => t('Manage'),
      'edit' => t('Edit'),
      'delete' => t('Delete'),
    );
  }
  elseif ($type == 'subscription') {
    $params['oid'] = $params['sid'] = $object->sid;
    $link_types = array(
      'unsubscribe' => t('Unsubscribe'),
      'edit' => t('Edit'),
    );
  }
  foreach ($link_types as $op => $name) {
    if (_notifications_anonymous_access($type, $object, $op)) {
      $links[$op] = notifications_anonymous_get_link($op, $params);
      $links[$op]['title'] = $name;
    }
  }
  return $links;
}

/**
 * Check for object access
 */
function _notifications_anonymous_access($type, $object, $op) {
  if (function_exists($function = 'notifications_anonymous_' . $type . '_access')) {
    return $function($op, $object);
  }
}
/**
 * Get formatted links to manage subscription / destination
 * 
 * @param $format
 *   Format to return the links
 *   - 'link', Full built link
 *   - 'url', Plain url 
 */
function notifications_anonymous_manage_links($type, $object, $format = 'link') {
  $items = array();
  foreach (_notifications_anonymous_manage_links($type, $object) as $key => $link) {
    switch ($format) {
      case 'link':
        $items[$key] = l($link['title'], $link['href'], $link['options']);
        break;
      case 'url':
        $items[$key] = url($link['href'], $link['options']);
        break;
    }
    
  }
  return $items;
}

/**
 * Create signed URLs for all pages
 */
function notifications_anonymous_url($url, $options = array()) {
  $elements = explode('/' , $url);
  $options += array('absolute' => TRUE);
  $options['query']['signature'] =  _notifications_signature($elements);
  return url($url, $options);
}

/**
 * Implementation of notifications_hook()
 * 
 * Check access permissions to subscriptions
 */
function notifications_anonymous_notifications($op, &$arg0, $arg1 = NULL, $arg2 = NULL) {
  global $user;

  switch ($op) {
    case 'access':
      if (!$user->uid && $arg0 == 'subscription') {
        $account = $arg1;
        $subscription = $arg2;
        // Check flood control
        if (!flood_is_allowed('notifications_anonymous', variable_get('notifications_anonymous_hourly_threshold', 3))) {
          drupal_set_message(t("You cannot create more than %number subscriptions per hour. Please try again later.", array('%number' => variable_get('notifications_anonymous_hourly_threshold', 3))), 'warning');
          return array(FALSE);
        }      
      }
      break;   
  } 
}

/**
 * Implementation of hook_messaging()
 * 
 * This hook provides information about the mensaje templates this module uses and related tokens.
 * 
 * Depending on $op, this hook takes different parameters and returns different pieces of information:
 * 
 * - 'message groups'
 *   Get array of message groups, each of which will have one or more keys for different templates
 *   Each group should have a unique key, so it should start with the module name
 * - 'message keys'
 *   Get message template parts for a given group ($arg1)
 *   Return array of key => name for each part
 * - 'messages'
 *   Get default message templates for a given group ($arg1).
 *   It should return default texts, indexed by message key that will be the default templates
 *   These templates may be edited on the 'Messaging templates' page
 * - 'tokens'
 *   Get available tokens for a given message group and key ($arg1).
 *   Return array of token keys that will be available for this message templates
 *   The tokens themselves may be default tokens (provided by token module) or we can add new
 *   tokens implementing hook_token_list() and hook_token_value()
 * 
 * @param $op
 *   Operation, type of information to retrieve
 * @param $arg1, $arg2...
 *   Different parameters depending on $op
 */
function notifications_anonymous_messaging($op, $arg1 = NULL, $arg2 = NULL, $arg3 = NULL, $arg4 = NULL) {
  switch ($op) {
    case 'message types':
      $info['notifications-anonymous'] = array(
        'name' => t('Anonymous Notifications'),
        'description' => t('Confirmation messages for anonymous users'),
      );
      return $info;
    case 'message groups':
      // Generic notifications event
      $info['notifications-anonymous-subscribe'] = array(
        'module' => 'notifications_anonymous',
        'name' => t('Confirm subscription'),
        'description' => t('Common parts for all Notifications messages for a single event. This is useful for defining a common header and/or footer for all these messages.'),
      );
      $info['notifications-anonymous-unsubscribe'] = array(
        'module' => 'notifications_anonymous',
        'name' => t('Cancel subscription'),
        'description' => t('Depending on your settings for each Send interval, Notifications may be digested, this is grouped and summarized in a single message. These are the common parts for Notifications digests.'),
      );
      return $info;
    case 'message keys':      
      $type = $arg1;
      switch ($type) {
        case 'notifications-anonymous':
          return array(
            'subject' => t('Subject'),
            'footer' => t('Footer'),
          );          
        case 'notifications-anonymous-subscribe':
        case 'notifications-anonymous-unsubscribe':
        case 'notifications-anonymous-manage':
          // Anonymous confirmation mails
          return array(
            'subject' => t('Subject'),
            'header' => t('Header'),
            'main' => t('Content'),
            'footer' => t('Footer'),
          );
      }
      break;
    case 'messages':
      switch ($arg1) {
        case 'notifications-anonymous':
          return array(
            'subject' => t('Message from [site-name]'),
            'footer' => array(
                t('This is an automatic message from [site-name]'),
                t('To manage your subscriptions, browse to [destination-manage-url]'),
                t('You can unsubscribe at [destination-unsubscribe-url]'),
            ),        
          );
        // Subscribe confirmation
        case 'notifications-anonymous-subscribe':
          return array(
            'subject' => t('Confirm your subscription to [site-name]'),
            'header' => t("Someone has subscribed to [site-name] using [destination-address],"),
            'main' => t("To confirm your subscription, browse to [subscription-confirm]"),
          );
        // Unsubscribe all message for a destination
        case 'notifications-anonymous-cancel':
          return array(
            'subject' => t('Cancel all subscriptions to [site-name]'),
            'header' => t('Someone has requested to cancel all subscriptions for [destination-address]'),
            'main' => array(
              t("To cancel all your subscriptions, browse to [destination-unsubscribe-url]"),
              t('To edit your subscriptions, browse to [destination-manage-url]'),
            ),      
          );
        // Unsubscribe all message for a destination
        case 'notifications-anonymous-unsubscribe':
          return array(
            'subject' => t('Cancel subscription to [site-name]'),
            'header' => t('Someone has requested to cancel all subscriptions for [destination-address]'),
            'main' => array(
              t("To cancel your subscription, browse to [subscription-unsubscribe-url]"),
              t('To edit your subscription, browse to [subscription-edit-url]'),
            ),      
          );
        case 'notifications-anonymous-manage':
          return array(
            'subject' => t('Edit your subscriptions to [site-name]'),
            'header' => t('Someone has requested to change the subscriptions for [destination-address]'),
            'main' => array(
              t('To edit your subscriptions, browse to [destination-manage-url]'),
              t("To cancel all your subscriptions, browse to [destination-unsubscribe-url]"),
            ),      
          );
      }
      break;
    case 'tokens':
      $type = explode('-', $arg1);
      $tokens = array();
      // These are the token groups that will be used for this module's messages
      if (strpos($arg1, 'notifications-anonymous') === 0) {
        $tokens = array('subscription', 'destination');
      }
      return $tokens;
  }
}

/**
 * Build message for destination
 * 
 * @param $type
 *   Message type
 *   - subscribe, Confirm subscription
 *   - unsubscribe, Cancel a single subscription
 *   - cancel, Cancel all your subscriptions
 *   - edit, Edit a subscription
 *   - manage, Edit all subscriptions for destination
 */
function notifications_anonymous_message_build($type , $destination, $objects = array(), $confirm = TRUE) {
  notifications_include('process.inc');
  $template = 'anonymous';
  $objects += array('destination' => $destination);
  $send_method = $destination->method;
  $text = array(
    'subject' => notifications_message_part($template, 'subject', $send_method, $type),
    'header' => notifications_message_part($template , 'header', $send_method, $type),
    'main'  => notifications_message_part($template, 'main', $send_method, $type),
    'footer' => notifications_message_part($template, 'footer', $send_method, $type),
  );
  // Run token replacement 
  $text = messaging_template_text_replace($text, $objects);
  // Get subject out of text and build the message array
  $subject = $text['subject'];
  unset($text['subject']);
  $message = messaging_message_build(array('subject' => $subject, 'body' => array_filter($text)));
  $message->add_destination($destination);
  return $message;
}

/**
 * Implementation of hook_token_list().
 */
function notifications_anonymous_token_list($type = 'all') {
  $tokens = array();
  if ($type == 'destination' || $type == 'all') {
    // Nore destination tokens provided by messaging module
    $tokens['destination']['destination-unsubscribe-url'] = t('URL to unsubscribe to the destination.');
    $tokens['destination']['destination-manage-url'] = t('URL to manage all subscriptions for the destination.');
    $tokens['destination']['destination-edit-url'] = t('URL to edit the destination.');
  }
  return $tokens;
}

/**
 * Implementation of hook_token_values()
 * 
 * Provide user-like tokens for anonymous users
 */
function notifications_anonymous_token_values($type, $object = NULL, $options = array()) {
  switch ($type) {
    case 'subscription':
      // Tokens only for anonymous users
      if (($subscription = $object) && empty($subscription->uid)) {
        $missing = '';
        $links = notifications_anonymous_manage_links('subscription', $subscription, 'url');
        $values['subscription-unsubscribe-url'] = isset($links['delete']) ? $links['delete'] : $missing;
        $values['subscription-edit-url'] = isset($links['edit']) ? $links['edit'] : $missing;
        // Old token, populate it for old templates
        $values['unsubscribe-url'] = $values['subscription-unsubscribe-url'];
        return $values;      
      }
      break;
    case 'destination':
      $values = array();
      // Just for anonymous destinations, for the others the notifications module will do the job
      if (($destination = $object) && empty($destination->uid)) {
        $missing = '';
        $links = notifications_anonymous_manage_links('destination', $destination, 'url');
        $values['destination-unsubscribe-url'] = isset($links['delete']) ? $links['delete'] : $missing;
        $values['destination-manage-url'] = isset($links['manage']) ? $links['manage'] : $missing;
        $values['destination-edit-url'] = isset($links['edit']) ? $links['edit'] : $missing;
        // This user token goes with destination for anonymous
        $values['unsubscribe-url-global'] = $values['destination-unsubscribe-url'];
        $values['subscriptions-manage'] = $values['destination-manage-url'];
      }
      return $values;
  }
}
