<?php
require_once drupal_get_path('module', 'notifications') . '/tests/notifications_test_case.inc';
/**
 * Class for testing notifications templates and message composition.
 *
 */
class NotificationsTemplatesTests extends NotificationsTestCase {

  function getInfo() {
    return array(
      'name' => 'Notifications Templates',
      'group' => 'Notifications',
      'description' => 'Notifications templates and message composition' );
  }

  function setUp() {
    parent::setUp('messaging_simple', 'notifications_digest', 'notifications_content');
    // Set some defaults
    // Default send interval will be: immediately
    variable_set('notifications_default_send_interval', 0);
    variable_set('notifications_default_send_method', 'debug');
    // Set fake site name for comparison after token replacement
    variable_set('site_name', 'Test Site');
  }

  /**
   * Play with creating, retrieving, deleting a pair subscriptions
   */
  function testNotificationsTemplates() {
    global $language;
    // Create user to subscribe and get notifications
    $user = $this->drupalCreateUser();
    $send_method = 'simple';
    $destination = messaging_account_build_destination($user, $send_method);
    $site_name = 'Test Site';
    // Create content types for test nodes
    $ctype1 = $this->drupalCreateContentType();
    $ctype2 = $this->drupalCreateContentType();
    // Author and node for testing, will be admin
    $author = $this->drupalCreateUser();
    $node1 = $this->drupalCreateNode(array(
      'title' => 'Title 1',
      'body' => 'Body 1',
      'type' => $ctype1->type,
      'uid' => $author->uid,
      'status' => 1,
    ));
    $node2 = $this->drupalCreateNode(array(
      'title' => 'Title 2',
      'body' => 'Body 2',
      'type' => $ctype2->type,
      'uid' => $author->uid,
      'status' => 1,
    ));
    // Add name to nodes to avoid annoying notifices
    $node1->name = $node2->name = $author->name;
    // Build some fake objects
    $event1 = $this->notificationsCreateNodeEvent('insert', $node1);
    $event2 = $this->notificationsCreateNodeEvent('update', $node2);

    // Basic api, text parts and info functions
    $interval_nodigest = 0;
    $interval_short = 1;
    $interval_long = 2;
    variable_set('notifications_digest_methods', array($interval_short => 'short', $interval_long => 'long'));

    $digest = notifications_build_method(1);
    $this->assertEqual($digest['type'], 'short', 'Get information about intervals and digest methods.');

    $info = $event1->get_type();
    $this->assertEqual($info['digest'], array('node', 'type'), 'Get event information about digest fields');

    $info = notifications_digest_event_info($event1);
    $this->assertEqual($info, array('type' => 'node', 'field' => 'type', 'value' => $node1->type, 'object' => $node1, 'module' => 'notifications'), 'Get digest information for first event.');
    //$this->printObject('digest information', $info);
    $info = notifications_digest_event_info($event2);
    $this->assertEqual($info, array('type' => 'node', 'field' => 'nid', 'value' => $node2->nid, 'object' => $node2, 'module' => 'notifications'), 'Get digest information for second event.');
    //$this->printObject('digest information', $info);

    // Text parts, text replacement, etc...
    $event1->text['test'] = 'Text part';
    $digest_line = 'type key [type-name] [title] [site-name]';
    $event1->text['digest'] = $digest_line;
    $part = $event1->message_part('test', 'test', $language);
    $this->assertEqual($part, 'Text part', 'Retrieved message part from event');
    $digest_info = notifications_digest_event_info($event1); // Fields will be type, action
    // function notifications_digest_message_part($key, $method, $type, $field, $module = 'notifications')
    $part = notifications_digest_line($event1, 'test', $language);
    $this->assertEqual($part, $digest_line, 'Retrieved testing message part: '. $part);
    $text = messaging_template_text_replace('[title] [type-name] [site-name]', array('node' => $node1));
    $this->assertEqual($text, "$node1->title $node1->type Test Site", 'Text replacement for node object');

    // Now lets get into the scary part, events and event digesting
    $text = array(
      'subject' => 'Subject [title]',
      'header' => 'Update for [type-name] [title]',
      'main' => 'The body is [node-body-raw]',
      'footer' => 'My site is [site-name]',
      'digest' => 'Digest line [title]',
    );

    $target = array(
      'subject' => "Subject $node1->title",
      'body' => array(
        'header' => "Update for $ctype1->name $node1->title",
        'event' => "The body is $node1->body",
        'footer' => 'My site is Test Site',
        ),
      'language' => $language->language,
    );
    $event1->text = $event2->text = $text;
    // Build event and subscriptions array
    $event_list = array($event1->eid => $event1);
    $subscriptions[$event1->eid] = array();
    $subscriptions[$event2->eid] = array();
    $messages = notifications_queue()->process_compose($send_method, $destination, $event_list, $subscriptions, $interval_nodigest);
    $message = current($messages);
    $result = array('subject' => $message->subject, 'body' => $message->body, 'language' => $message->language);
    $this->assertEqual($result, $target, 'Message composition for single event'. $this->compareTexts($result, $target));

    // Test digesting, prepare events and build event list
    $node3 = $this->drupalCreateNode(array(
      'title' => 'Title 3',
      'body' => 'Body 3',
      'type' => $ctype1->type,
      'uid' => $author->uid,
      'status' => 1,
    ));
    $node3->name = $author->name;

    // This should be digested by node type with the first one
    $event3 = $this->notificationsCreateNodeEvent('insert', $node3);
    // This should be digested by node with the second one, it's the same node update
    $event4 = $this->notificationsCreateNodeEvent('update', $node2);
    $subscriptions[$event3->eid] = array();
    $subscriptions[$event4->eid] = array();
    // Set known event texts
    $event3->text = $event4->text = $text;
    $event_list = array(
      $event1->eid => $event1, $event2->eid => $event2,
      $event3->eid => $event3, $event4->eid => $event4
    );

    // This should produce a short digest, build the target to compare
    $items = array();
    $items['subject'] = "[site-name] subscription update for [user]";
    $items['header'] = "Greetings, [user].\n\nThese are your messages";
    $items['footer'] = "This is an automatic message from [site-name]\nTo manage your subscriptions, browse to [subscriptions-manage]";
    $objects = array('user' => $user, 'subscription' => NULL);
    $texts = messaging_template_text_replace($items, $objects);
    // Node post events are digested by node type
    $lines = array();
    $lines['node'][$ctype1->type] = array(
      'group' => array(
        'title' => "New content of type $ctype1->name has been submitted",
        'footer' => ""
      ),
      'line' => array(
        1 => "Digest line $node1->title", //"$node1->title\nRead more " . url('node/' . $node1->nid, array('absolute' => TRUE)),
        2 => "Digest line $node3->title", //"$node3->title\nRead more " . url('node/' . $node3->nid, array('absolute' => TRUE)),
      ),
    );
    // Node updates and comments are digested by nid
    $lines['node'][2] = array(
      'group' => array(
        'title' => "Updates for $ctype2->name: $node2->title",
        'footer' => "Read more " . url('node/' . $node2->nid, array('absolute' => TRUE))
      ),
      'line' => array(
        1 => "Digest line $node2->title", //"$node2->title\nRead more " . url('node/' . $node2->nid, array('absolute' => TRUE)),
        2 => "Digest line $node2->title", //"$node3->title\nRead more " . url('node/' . $node2->nid, array('absolute' => TRUE)),
      ),
    );
    $target = array(
      'subject' => $texts['subject'],
      'body' => theme('notifications_digest_short_body', $texts, $lines),
    );
    $digest = notifications_queue()->process_compose($send_method, $destination, $event_list, $subscriptions, $interval_short);
    $message = array('subject' => $digest[0]->subject, 'body' => $digest[0]->body);
    $this->assertEqual($message, $target, 'Message composition for short digest.'. $this->compareTexts($message, $target));
    //$this->printObject($target, 'Target');
    //$this->printObject($message, 'Message');

    // This should be a long digest, interval 2, build target to compare
    $event_list = array($event1->eid => $event1, $event2->eid => $event2);
    $body = array(
      "Subject $node1->title",
      "The body is $node1->body",
      "Subject $node2->title",
      "The body is $node2->body",
    );
    $target = array(
      'subject' => $texts['subject'],
      'body' => theme('notifications_digest_long_body', $texts['header'], $body, $texts['footer']),
    );
    $digest = notifications_queue()->process_compose($send_method, $destination, $event_list, $subscriptions, $interval_long);
    $message = array('subject' => $digest[0]->subject, 'body' => $digest[0]->body);
    $this->assertEqual($message, $target, 'Message composition for long digest.'. $this->compareTexts($message, $target));
    //$this->printObject($target, 'Target');
    //$this->printObject($message, 'Message');
  }

  // Notifications helper functions
  function notificationsCreateNodeEvent($action, $node) {
    static $eid = 0;

    $event = new Notifications_Event(array(
      'type' => 'node', 'action' => $action,
      'node' => $node, 'params' => array('nid' => $node->nid),
      'objects' => array('node' => $node),
    ));
    $event->save();
    return $event;
  }

  // Helper function to compare two text arrays and print the differences side by side
  function compareTexts($text1, $text2) {
    if ($diff = $this->diffTexts($text1, $text2)) {
      return theme('table', array(), $diff);
    }
    else {
      return '';
    }
  }

  // Diff two text arrays and return rows key, value1, value2
  function diffTexts($text1, $text2) {
    $diff = array();
    foreach ($text1 as $key => $value) {
      if (!isset($text2[$key])) {
        $diff[] = array($key, str_replace("\n", '\n', $value), '--');
      }
      elseif (is_array($value)) {
        if ($compare = $this->compareTexts($value, $text2[$key])) {
          $diff[] = array($key, array('data' => $compare, 'colspan' => 2));
        }
      }
      elseif ($value != $text2[$key]) {
        $diff[] = array($key, str_replace("\n", '\n', $value), str_replace("\n", '\n', $text2[$key]));
      }
    }
    return $diff;
  }

  // Helper option for debugging
  function printDebug($data) {
    $string = is_array($data) || is_object($data) ? print_r($data, TRUE) : $data;
    $this->assertTrue(TRUE, 'DEBUG: '. $string);
  }
}
