<?php
/**
 * @file
 * Contains core functions for the GoToWebinar module.
 */

/**
 * GoToWebinar contstants.
 */
define('GOTOWEBINAR_OAUTH_URL', 'https://api.citrixonline.com/oauth/');
define('GOTOWEBINAR_API_URL', 'https://api.citrixonline.com/G2W/rest/organizers/');

/**
 * Include additional files.
 */
foreach (module_list() as $module) {
  if (file_exists($file = dirname(__FILE__) . "/includes/{$module}.inc")) {
    require_once $file;
  }
}

/**
 * Implements hook_permission().
 */
function gotowebinar_permission() {
  return array(
    'administer gotowebinar' => array(
      'title' => t('Administer GoToWebinar'),
      'description' => t('Perform administration tasks for GoToWebinar.'),
    ),
    'administer gotowebinar settings' => array(
      'title' => t('Administer GoToWebinar settings'),
      'description' => t('Set the GoToWebinar API Key and Authenticate.'),
    ),
  );
}

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

  $items['admin/config/services/gotowebinar'] = array(
    'title' => 'GoToWebinar',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('gotowebinar_registrants_create_form'),
    'access arguments' => array('administer gotowebinar'),
  );

  $items['admin/config/services/gotowebinar/registrants/create'] = array(
    'title' => 'Create registrants',
    'type' => MENU_DEFAULT_LOCAL_TASK,
  );

  $items['admin/config/services/gotowebinar/settings'] = array(
    'title' => 'Settings',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('gotowebinar_settings_form'),
    'access arguments' => array('administer gotowebinar settings'),
    'type' => MENU_LOCAL_TASK,
    'weight' => 100,
  );

  $items['gotowebinar/oauth'] = array(
    'page callback' => 'gotowebinar_oauth_callback',
    'access arguments' => array('administer gotowebinar'),
  );

  return $items;
}

/**
 * GoToWebinar Create registrants form.
 */
function gotowebinar_registrants_create_form($form, &$form_state) {
  $settings = variable_get('gotowebinar_settings', array());
  if (!isset($settings['access_token'])) {
    drupal_set_message(t('GoToWebinar must be authenticated before use.'));
    drupal_goto('admin/config/services/gotowebinar/settings');
  }

  $webinars = _gotowebinar_method('get_upcoming_webinars');
  if ($webinars && count($webinars) > 0) {
    $form['webinar'] = array(
      '#title' => t('Webinar'),
      '#type' => 'select',
      '#options' => array(),
      '#ajax' => array(
        'callback' => 'gotowebinar_registrants_create_form_ajax',
        'wrapper' => 'edit-fields',
      ),
    );
    foreach ($webinars as $webinar)  {
      $form['webinar']['#options'][$webinar->webinarKey] = $webinar->subject;
    }

    $form['roles'] = array(
      '#title' => 'Roles',
      '#type' => 'checkboxes',
      '#options' => array(),
      '#required' => TRUE,
    );
    foreach (user_roles() as $rid => $role) {
      if ($rid > 1) {
        $form['roles']['#options'][$rid] = $role;
      }
    }

    // Field Mapping.
    $field_map = variable_get('gotowebinar_field_map', array());

    $form['fields'] = array(
      '#title' => t('Field mapping'),
      '#type' => 'fieldset',
      '#collapsible' => TRUE,
      '#collapsed' => TRUE,
      '#tree' => TRUE,
    );

    $user_fields = array();
    foreach (field_info_instances('user', 'user') as $field_name => $field) {
      $user_fields[$field_name] = $field['label'];
    }

    $fields = _gotowebinar_method('registrant_fields', array(
      'params' => array(
        'webinar_key' => isset($form_state['values']['webinar']) ? $form_state['values']['webinar'] : key($form['webinar']['#options']),
      ),
    ));

    foreach ($fields->fields as $field) {
      if ($field->field == 'email') {
        continue;
      }

      $form['fields'][$field->field] = array(
        '#title' => $field->field,
        '#type' => 'select',
        '#options' => $user_fields,
        '#empty_option' => $field->required ? t('- Select -') : t('- None -'),
        '#default_value' => isset($field_map[$field->field]) ? $field_map[$field->field] : NULL,
        '#required' => $field->required,
      );

      if ($field->required && !isset($field_map[$field->field])) {
        $form['fields']['#collapsed'] = FALSE;
      }
    }

    $form['actions'] = array(
      '#type' => 'container',
    );
    $form['actions']['submit'] = array(
      '#type' => 'submit',
      '#value' => t('Submit'),
    );
  }

  // No webinars setup.
  else {
    $form['no_webinars'] = array(
      '#markup' => t('There are currently no future scheduled webinars setup.')
    );
  }

  return $form;
}

/**
 *
 */
function gotowebinar_registrants_create_form_ajax(&$form, &$form_state) {
  return $form['fields'];
}

/**
 * Submit callback for GoToWebinar Create registrants form.
 */
function gotowebinar_registrants_create_form_submit(&$form, &$form_state) {
  $roles = array_filter($form_state['values']['roles']);
  $webinar = _gotowebinar_method('get_webinar', array(
    'params' => array(
      'webinar_key' => $form_state['values']['webinar'],
    ),
  ));

  // Cache field mapping settings.
  $field_map = variable_get('gotowebinar_field_map', array());
  variable_set('gotowebinar_field_map', array_merge($field_map, $form_state['values']['fields']));

  // Build fields object.
  $fields = array_unique(array_filter(array_values($form_state['values']['fields'])));
  $fields['#map'] = array_filter($form_state['values']['fields']);
  $fields['#instances'] = array();
  foreach (element_children($fields) as $delta) {
    $fields['#instances'][$fields[$delta]] = field_info_instance('user', $fields[$delta], 'user');
    unset($fields[$delta]);
  }

  // Load all Authenticated users.
  if (in_array(2, $roles)) {
    $uids = db_select('users', 'u')
      ->fields('u', array('uid'))
      ->condition('status', 1)
      ->execute()
      ->fetchAll();
  }

  // Load users by role.
  else {
    $query = db_select('users_roles', 'r');
    $query->join('users', 'u', 'r.uid = u.uid');
    $query->distinct();
    $uids = $query->fields('r', array('uid'))
      ->condition('r.rid', $roles)
      ->condition('u.status', 1)
      ->execute()
      ->fetchAll();
  }

  // Create Batch.
  $batch = array(
    'title' => t('Creating registrants for Webinar: !name', array('!name' => $webinar->subject)),
    'operations' => array(
      array('_gotowebinar_registrants_create_batch_process', array($webinar, $uids, $fields)),
    ),
  );
  batch_set($batch);
  batch_process();
}

/**
 * Batch process callback for GoToWebinar Create registrants form submission.
 */
function _gotowebinar_registrants_create_batch_process($webinar, $uids, $fields, &$context) {
  if (empty($context['sandbox'])) {
    $context['sandbox'] = array();
    $context['sandbox']['progress'] = 0;

    // Store arguments in $context.
    $context['sandbox']['webinar'] = $webinar;
    $context['sandbox']['uids'] = $uids;
    $context['sandbox']['fields'] = $fields;

    // Save uid count for the termination message.
    $context['sandbox']['max'] = count($uids);
  }

  // Load user.
  $uid = $context['sandbox']['uids'][$context['sandbox']['progress']]->uid;
  $user = user_load($uid);

  $data = array('email' => $user->mail);
  foreach ($context['sandbox']['fields']['#map'] as $key => $field_name) {
    // @TODO - Make field handling better.
    if (isset($user->{$field_name}[LANGUAGE_NONE][0]['safe_value'])) {
      $data[$key] = $user->{$field_name}[LANGUAGE_NONE][0]['safe_value'];
    }
  }

  $response = _gotowebinar_method('create_registrant', array(
    'params' => array(
      'webinar_key' => $context['sandbox']['webinar']->webinarKey,
    ),
    'data' => json_encode($data),
  ));

  // Logging.
  switch (TRUE) {
    case isset($response->joinUrl):
      watchdog('GoToWebinar', 'User %user successfully registered to %webinar', array(
        '%user' => "{$user->name} (UID:{$user->uid})",
        '%webinar' => "{$webinar->subject} ({$webinar->webinarKey})",
      ));
      break;

    case isset($response->description):
      watchdog('GoToWebinar', 'An error occured while attempting to register user %user to %webinar:<br /><br />%description', array(
        '%user' => "{$user->name} (UID:{$user->uid})",
        '%webinar' => "{$webinar->subject} ({$webinar->webinarKey})",
        '%description' => $response->description,
      ));
      break;
  }

  // Update our progress information.
  $context['sandbox']['progress']++;

  // Inform the batch engine that we are not finished, and provide an estimation
  // of the completion level we reached.
  if ($context['sandbox']['progress'] != $context['sandbox']['max']) {
    $context['finished'] = ($context['sandbox']['progress'] >= $context['sandbox']['max']);
  }
}

/**
 * GoToWebinar settings form.
 */
function gotowebinar_settings_form($form, &$form_state) {
  $settings = variable_get('gotowebinar_settings', array());

  $form['gotowebinar_settings'] = array(
    '#type' => 'container',
    '#tree' => TRUE,
  );
  $form['gotowebinar_settings']['api_key'] = array(
    '#title' => t('API Key'),
    '#type' => 'textfield',
    '#default_value' => isset($settings['api_key']) ? $settings['api_key'] : '',
  );

  $form['actions'] = array(
    '#type' => 'container',
  );
  $form['actions']['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Save settings'),
  );

  return $form;
}

/**
 * Validation callback for GoToWebinar settings form.
 */
function gotowebinar_settings_form_validate(&$form, &$form_state) {
  // @TODO - Test to see if API Key is valid before attempting authentication.
}

/**
 * Submit callback for GoToWebinar settings form.
 */
function gotowebinar_settings_form_submit(&$form, &$form_state) {
  // Save settings.
  variable_set('gotowebinar_settings', $form_state['values']['gotowebinar_settings']);

  // Authenticate.
  $auth_url = url(GOTOWEBINAR_OAUTH_URL . 'authorize', array(
    'query' => array(
      'client_id' => $form_state['values']['gotowebinar_settings']['api_key'],
      'redirect_uri' => url('gotowebinar/oauth', array('absolute' => TRUE)),
    ),
  ));
  drupal_goto($auth_url);
}

/**
 * GoToWebinar OAuth callback.
 */
function gotowebinar_oauth_callback() {
  if (!isset($_GET['code'])) {
    drupal_not_found();
  }

  $response = _gotowebinar_method('get_access_token');
  if ($response) {
    variable_set('gotowebinar_settings', array_merge(variable_get('gotowebinar_settings', array()), (array) $response));
    drupal_set_message(t('Settings saved and GoToWebinar successfully authenticated.'));
  }
  else {
    // drupal_set_message(t('There was an issue while authenticating GoToWebinar.'));
  }

  // Redirect back to GoToWebinar settings form.
  drupal_goto('admin/config/services/gotowebinar/settings');
}

/**
 *
 */
function _gotowebinar_method($method, $options = array()) {
  $settings = variable_get('gotowebinar_settings', array());

  // Include method file.
  if (file_exists($file = dirname(__FILE__) . "/methods/{$method}.inc")) {
    require $file;
  }

  if (is_array($method)) {
    $ch = curl_init();

    curl_setopt($ch, CURLOPT_URL, $method['url']);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

    if ($method['method'] == 'post' && isset($options['data'])) {
      curl_setopt($ch, CURLOPT_POST, TRUE);
      curl_setopt($ch, CURLOPT_POSTFIELDS, $options['data']);
    }

    $response = curl_exec($ch);
    $error = curl_error($ch);

    curl_close($ch);

    switch ($method['response_type']) {
      case 'json':
      default:
        // Decode JSON response.
        $response = json_decode($response);
        break;
    }

    return $error || empty($response) ? FALSE : $response;
  }

  return FALSE;
}
