<?php

/**
 * @file
 * Push Notifications functionality.
 */

/**
 * Constants Definition.
 */

//
// GCM Variables
//
// GCM Credentials.
define('GCM_CLIENT_LOGIN_ACTION_URL', variable_get('gcm_client_login_action_url', 'https://www.google.com/accounts/ClientLogin'));
// GCM Server Post URL
define('GCM_SERVER_POST_URL', variable_get('gcm_server_post_url', 'https://android.googleapis.com/gcm/send'));

/**
 * Implements hook_permission().
 */
function gcm_permission() {
  return array(
    'administer gcm settings' => array(
      'title' => t('Administer GCM settings'),
    ),
  );
}

/**
 * Implementation of hook_rules_action_info().
 */
function gcm_rules_action_info() {
  return array(
    'gcm_action_send_message' => array(
      'label' => t('Send GCM message'),
      'group' => t('Google Cloud Messaging'),
      'parameter' => array(
        'tokens' => array(
          'type' => 'text',
          'label' => t('Tokens'),
          'description' => t('Registration IDs, comma-separated'),
//          'restriction' => 'input',
        ),
        'keyValue' => array(
          'type' => 'text',
          'label' => t('Key-Value'),
          'restriction' => 'input',
        ),
        'delay_while_idle' => array(
          'type' => 'boolean',
          'label' => t('Delay while idle'),
          'description' => t("If included, indicates that the message should not be sent immediately if the device is idle."),
          'default value' => true,  
        ),
        'time_to_live' => array(
          'type' => 'integer',
          'label' => t('Time to live'),
          'description' =>t("How long (in seconds) the message should be kept on GCM storage if the device is offline. Requires collapse key to be regarded."),
          'default value' => NULL,  
          'optional' => TRUE,
        ),
        'collapse_key' => array(
          'type' => 'text',
          'label' => t('Collapse key'),
          'description' => t('An arbitrary string (such as "Updates Available") that is used to collapse a group of like messages when the device is offline, so that only the last message gets sent to the client.'),
          'restriction' => 'input',
          'default value' => NULL,
          'optional' => TRUE,
        ),
      ),
    ),
  );
}

/**
 * Implementation of hook_rules_event_info().
 */
function gcm_rules_event_info() {
  return array(
    'gcm_event_registration_id_error' => array(
      'label' => t('Got registration ID with an error'),
      'group' => t('Google Cloud Messaging'),
      'variables' => array(
        'registration_id' => array(
          'label' => t('Registration id'),
          'type' => 'text',
        ),
        'error' => array(
          'label' => t('Error type'),
          'type' => 'text',
        ),
      ),
    ),
  );
}

function gcm_action_send_message($tokens, $keyValues, $delay_while_idle, $time_to_live, $collapse_key) {

    $gcm_message = array();
    foreach (explode(",", $keyValues) as $keyValue) {
      $temp = explode("=", $keyValue);
      $key = $temp[0];
      $value = $temp[1];
      if (isset($key) && isset($value)) {
        $gcm_message[$key] = $value;
      }
    }
    gcm_send_message(array_unique(explode(',', $tokens)), $gcm_message, $delay_while_idle, $time_to_live, $collapse_key);
}

/**
 * Implementation of hook_menu().
 */
function gcm_menu() {

  $items = array();

  $items['admin/config/workflow/gcm/settings'] = array(
    'title' => 'Google Cloud Messaging Settings',
    'description' => 'Settings for GCM',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('gcm_admin'),
    'access arguments' => array('administer gcm settings'),
    'type' => MENU_NORMAL_ITEM,
   );

  return $items;
}

function gcm_admin() {
  $form = array();

  $form['gcm_project_id'] = array(
    '#type' => 'textfield',
    '#title' => t('GCM Project ID'),
    '#default_value' => variable_get('gcm_project_id', '3243425345'),
    '#required' => TRUE,
  );

  $form['gcm_api_key'] = array(
    '#type' => 'textfield',
    '#title' => t('GCM API Key'),
    '#default_value' => variable_get('gcm_api_key', 'gfhfgdhfhfhf'),
    '#required' => TRUE,
  );

  $form['gcm_debug'] = array(
    '#type' => 'checkbox',
    '#title' => t('GCM Debug'),
    '#default_value' => variable_get('gcm_debug', false),
    '#description' => t('Check if you want detailed debug messages into watchdog'),
  );

  return system_settings_form($form);
}

/**
 * Send out push notifications through GCM.
 *
 * @param $tokens
 *   Array of android tokens
 * @param $payload
 *   Payload to send.
 *
 * @return
 *   Array with the following keys:
 *   - count_attempted (# of attempted messages sent)
 *   - count_success   (# of successful sends)
 *   - success         (# boolean)
 *   - message         (Prepared result message)
 */
function gcm_send_message($tokens, $payload, $delay_while_idle = false, $time_to_live = null, $collapse_key = null) {

  gcm_debug("time_to_live", $time_to_live);
  gcm_debug("collapse_key", $collapse_key);
  gcm_debug("tokens", $tokens);
  gcm_debug("payload", $payload);
  if (!is_array($tokens) || empty($payload) || (is_array($tokens) && empty($tokens))) {
    return FALSE;
  }

  // Define an array of result values.
  $result = array(
    'count_attempted' => 0,
    'count_success' => 0,
    'success' => 0,
    'message' => '',
  );

  // Define the header.
  $headers = array();
  $headers[] = 'Content-Type:application/json';
  $headers[] = 'Authorization: key=' .  variable_get('gcm_api_key', 'AIzaSyArZfzkiFtRjH5IyUBAGGhPmCOE_5qYyJI');

  // Send a push notification to every recipient.
  $data = array();
  $registration_ids = array_unique($tokens);
  $filtered_ids = array();

  $data['registration_ids'] = array();
  $index = 0;
  foreach ($registration_ids as $registration_id) {
    $registration_id = preg_replace('/\s+/', '', $registration_id);
    if (!empty($registration_id)) {
      $data['registration_ids'][] = $registration_id;
      $filtered_ids[$index++] = $registration_id;
    }
  }

  $data['data'] = $payload;
  $data['delay_while_idle'] = ($delay_while_idle == 1 ? true : false);

  // collapse_key is optional
  if ($collapse_key != null && strlen($collapse_key) > 0) {
    $data['collapse_key'] = $collapse_key;

    // time_to_live is optional, and relevant only if collapse_key is defined
    if ($time_to_live != null && intval($time_to_live) > 0) {
      $data['time_to_live'] = intval($time_to_live);
    }
  }

  $json_data = drupal_json_encode($data);
  gcm_debug("data", $data);
  gcm_debug("filtered_ids", $filtered_ids);
  gcm_debug("json data", $json_data);

  $curl = curl_init();
  curl_setopt($curl, CURLOPT_URL, GCM_SERVER_POST_URL);
  curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
  curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
  curl_setopt($curl, CURLOPT_POST, TRUE);
  curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
  curl_setopt($curl, CURLOPT_POSTFIELDS, $json_data);
  $response = curl_exec($curl);
  $info = curl_getinfo($curl);
  curl_close($curl);
  $json_response = json_decode($response);

  if ($info['http_code'] == 200) {
    $multicast_id = $json_response->multicast_id;
    $success = $json_response->success;
    $failure = $json_response->failure;
    $canonical_ids = $json_response->canonical_ids;
    $results = $json_response->results;

    watchdog('gcm', t('GCM request @multicast_id was successful: @success successful messages, @failure failed messages, @canonical_ids canonical ids', array('@multicast_id' => $multicast_id, '@success' => $success, '@failure' => $failure, '@canonical_ids' => $canonical_ids)));

    // TODO: handle results, including canonical ids
    gcm_debug('results', $results);

    gcm_handle_results($filtered_ids, $results);
  } elseif ($info['http_code'] == 400) {
      watchdog('gcm', 'GCM JSON error', NULL, WATCHDOG_ERROR);
  } else { // 500 or 503
      watchdog('gcm', t('GCM error code @code', array('@code' => $info['http_code'])), NULL, WATCHDOG_ERROR);
  }
}

function gcm_purge_token($token) {
  // TODO
}

function gcm_debug($category, $message) {
  if (variable_get('gcm_debug', false)) {
    watchdog('gcm debug', $category . "=" . var_export($message, true));
  }
}

function gcm_handle_results($registration_ids, $results) {
  foreach ($results as $key => $result) {
    gcm_debug("result", $result);
    if (isset($result->error) && !empty($result->error)) {
      $error = $result->error;
      $registration_id = $registration_ids[$key];
      // Remove trailing space
      $registration_id = trim($registration_id);
      gcm_debug("Key $key Registration ID $registration_id ", $result);
      rules_invoke_event('gcm_event_registration_id_error', $registration_id, $error);
    }
  }
}
