<?php

/**
 * Implements hook_init()
 * Set a cookie to track this user.
 */
function user_alert_init() {
	if (!isset($_COOKIE['UUID']) || !_user_alert_uuid_is_valid($_COOKIE['UUID'])) {
		$uuid = _user_alert_uuid_generate_php();
		global $cookie_domain;
		setcookie('UUID', $uuid, time() + 31536000, '/', $cookie_domain, FALSE, TRUE);
	}
	
	drupal_add_js(array('user_alert' => array('url_prefix' => variable_get('clean_url', 0) != 0 ? '' : '?q=')), 'setting');
}

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

  $items['admin/config/content/user-alert'] = array(
		'title' => 'User Alert',
		'description' => 'Configuration options for User Alert.',
		'type' => MENU_NORMAL_ITEM,
		'page callback' => 'drupal_get_form',
		'page arguments' => array('user_alert_admin_settings'),
		'access arguments' => array('administer user alert'),
		'file' => 'user_alert.admin.inc',
  );
  $items['admin/config/content/user-alert/list'] = array(
		'title' => 'User Alert',
		'type' => MENU_DEFAULT_LOCAL_TASK,
		'access arguments' => array('administer user alert'),
		'weight' => -15,
  );
  $items['js/user-alert/get-message'] = array(
		'page callback' => 'user_alert_display_alert',
		'delivery callback' => 'ajax_deliver',
		'access arguments' => array('access content'),
		'type' => MENU_CALLBACK,
  );
  $items['js/user-alert/close-message'] = array(
		'page callback' => 'user_alert_close_message',
		'delivery callback' => 'ajax_deliver',
		'access arguments' => array('access content'),
		'type' => MENU_CALLBACK,
  );

  return $items;
}

/**
 * Implements hook_permission()
 */
function user_alert_permission() {
  return array(
    'administer user alert' => array(
      'title' => t('Administer user alert'), 
      'description' => t('Perform administration tasks for User Alert.'),
    ),      
  );
}

/**
 * Implements hook_access().
 */
function user_alert_node_access($op, $node, $account) {
  switch ($op) {
    case 'create':
      if (user_access('create user alert', $account)) {
        return TRUE;
      }
      break;

    case 'update':
      if (user_access('edit any user alert', $account) || ($account->uid == $node->uid && user_access('edit own user alert', $account))) {
        return TRUE;
      }
      break;

    case 'delete':
      if (user_access('delete any user alert', $account) || ($account->uid == $node->uid && user_access('delete own user alert', $account))) {
        return TRUE;
      }
      break;
  }
}

/**
 * Implements hook_block_info()
 */
function user_alert_block_info() {
  $blocks['user_alert'] = array(
    'info'   => t('User Alert'),
    'region' => 'content',
    'status' => 1,
    'cache'  => DRUPAL_NO_CACHE,
  );

	return $blocks;
}

/**
 * Implements hook_block_view()
 */
 function user_alert_block_view($delta) {
  if ($delta == 'user_alert') {
    $block['subject'] = '<none>';
    $block['content'] = ' ';
    return $block;
  }
}

/**
 * Implements hook_node_info().
 */
function user_alert_node_info() {
  return array(
    'user_alert' => array(
      'name' => t('User Alert'),
      'base' => 'user_alert',
      'description' => t('A User Alert is a short Twitter like message displayed at the top of the site, alerting users to critical information like an online sale, new blog post, or breaking news. After viewing it, they can click and close the message.'),
      'has_title' => TRUE,
      'title_label' => t('Title'),
      'disabled' => FALSE,
    )
  );
}

/**
 * Implements hook_form().
 */
function user_alert_form($node, &$form_state) {
  return node_content_form($node, $form_state);
}

/**
 * Gather alerts for the current user and return them. Exclude ones already closed.
 *
 * @return string
 *   Returns themed output if there is a message to display.
 */
function user_alert_display_alert() {
  if (module_exists('translation')) {
    global $language;
    $language = $language->language;
  } else {
    $language = LANGUAGE_NONE;
  }

	$output = '';
	$result = db_query("SELECT n.nid FROM {node} n WHERE type = :type AND status = :status AND language = :language AND n.nid NOT IN (SELECT ua.nid FROM {user_alert} ua WHERE ua.nid = n.nid AND ua.uuid = :cookie) ORDER BY nid DESC", array(':type' => 'user_alert', ':status' => NODE_PUBLISHED,  ':language' => $language, ':cookie' => $_COOKIE['UUID']));

	foreach ($result as $record) {
		$alert = node_load($record->nid);
		if (node_access('view', $alert) && isset($_COOKIE['UUID'])) {
			$output .= theme('user_alert', array('node' => $alert));
		}
	}
	
	return $output;
}
 
/**
 * Respond to a user clicking to close an alert.
 */
function user_alert_close_message() {
	$nid = $_GET['message'];

	if (!node_load($nid)) {
	  return;
	}
	
	$fields = array('nid' => $nid, 'uuid' => $_COOKIE['UUID']);
	db_insert('user_alert')->fields($fields)->execute();
}

/**
 * Implements hook_theme()
 */
function user_alert_theme() {
  return array(
    'user_alert' => array(
      'template' => 'user-alert',
      'variables' => array('node' => NULL),
    ),
  );
}

/**
 * Implements hook_preprocess()
 */
function user_alert_preprocess_user_alert(&$vars) {
  $node = $vars['node'];
  $vars['alert_label'] = variable_get('user_alert_label', 'User Alert');
  $vars['nid'] = $vars['node']->nid;
  $vars['body'] = $vars['node']->body[$vars['node']->language][0]['value'];
  $vars['is_closeable'] = user_alert_cookie_is_valid();
}

/**
 * Implements hook_cron()
 */
 function user_alert_cron() {
  if (variable_get('user_alert_cron_delete', 0)) {
    $result = db_query('SELECT nid FROM {node} WHERE type = :type AND status = :status', array(':type' => 'user_alert', ':status' => NODE_NOT_PUBLISHED));

    foreach ($result as $record) {
      node_delete($record->nid);
    }
  }
}

/**
 * Check that a string appears to be in the format of a UUID.
 *
 * @param $uuid
 *  The string to test.
 *
 * @return bool
 *   TRUE if the string is well formed.
 */
function _user_alert_uuid_is_valid($uuid) {
  return preg_match("/^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$/", $uuid);
}

/**
 * Generates a UUID v4 using PHP code.
 * @see http://php.net/uniqid#65879
 */
function _user_alert_uuid_generate_php() {
  // The field names refer to RFC 4122 section 4.1.2.
  return sprintf('%04x%04x-%04x-%03x4-%04x-%04x%04x%04x',
    // 32 bits for "time_low".
    mt_rand(0, 65535), mt_rand(0, 65535),
    // 16 bits for "time_mid".
    mt_rand(0, 65535),
    // 12 bits before the 0100 of (version) 4 for "time_hi_and_version".
    mt_rand(0, 4095),
    bindec(substr_replace(sprintf('%016b', mt_rand(0, 65535)), '01', 6, 2)),
    // 8 bits, the last two of which (positions 6 and 7) are 01, for "clk_seq_hi_res"
    // (hence, the 2nd hex digit after the 3rd hyphen can only be 1, 5, 9 or d)
    // 8 bits for "clk_seq_low" 48 bits for "node".
    mt_rand(0, 65535), mt_rand(0, 65535), mt_rand(0, 65535)
  );
}

/**
 * Check to see that a cookie exists and has a format of at least .example.com
 * @return bool
 */
function user_alert_cookie_is_valid() {
  global $cookie_domain;

  if (!drupal_strlen($cookie_domain) || substr_count($cookie_domain, '.') < 2) {
    return FALSE;
  }

  return TRUE;
}
