<?php
/**
 * @file
 * Integration with Chamilo for SSO and information blocks
 */
// Base URL
define('CHAMILO_BASE_URL', '/main/webservices');
// Base API KEY URL
define('CHAMILO_API_KEY_URL', '/main/auth/profile.php');
// Default amount of items(photos) per page.
define('CHAMILO_DEFAULT_IPP', 10);
// signature types
define('CHAMILO_GLOBAL_SIGNATURE', 1);
define('CHAMILO_PERUSER_SIGNATURE', 2);
define('CHAMILO_SECRET_KEY', 3);

/**
 * Implementation of hook_boot()
 * This hook is run at the beginning of the page request (even for cached page)
 */
function chamilo_boot() {
  global $user;
  // Implementation of Master SSO server
  if ($user->uid && isset($_GET['sso_referer'])) {
    chamilo_sso_auth($user);
  }
}

/**
 * Returns the protocol used to connect to Chamilo
 * @return string 'http://' or 'https://', depending on variable stored in Chamilo module's config
 */
function chamilo_sso_protocol() {
  $protocols = array('http://', 'https://');
  return $protocols[variable_get('chamilo_sso_protocol', 0)];
}

/**
 * Given a drupal account, redirect to Vanity server including login info.
 * @param object User account object
 */
function chamilo_sso_auth($account) {
  global $base_path;
  // Makes sure the filter module is loaded
  // (this can happen when function is called early in the bootstrap (from hook_boot)
  if (!function_exists('filter_xss')) {
    include_once('includes/common.inc');
  }
  
  $master_auth_uri = $base_path .'?q=user';

  // Master Cookie
  $sso = array(
    'username' => $account->name,
    'secret' => sha1($account->name.filter_xss($_GET['sso_challenge']).variable_get('chamilo_appkey', '')),
    'master_domain' => filter_xss($_SERVER['HTTP_HOST']),
    'master_auth_uri' => $master_auth_uri,
    'lifetime' => time() + 3600,
    'target' => filter_xss($_GET['sso_target']),
  );
  $cookie = base64_encode(serialize($sso));

  // Redirect to Vanity Server
  $url = chamilo_sso_protocol() . filter_xss($_SERVER['HTTP_HOST']) . $master_auth_uri;
  $params = 'sso_referer='. urlencode($url) .'&sso_cookie='. urlencode($cookie);
  header('Location: '. filter_xss($_GET['sso_referer']) .'?'. $params);
  exit;
}

/**
 * Builds a SOAP call to Chamilo web services with the given parameters
 * @param string Name of web service script to call
 * @param string Service to call inside given web service script
 * @return mixed Array of results (or false on error)
 */
function chamilo_soap_call() {
  // Prepare params
  $params = func_get_args();
  $service = array_shift($params);
  $action = array_shift($params);
  ini_set('soap.wsdl_cache_enabled', 0);
  // Init SOAP client
  $service_path = chamilo_get_service_path($service);
  
  if ($service_path) {
    $client = new SoapClient($service_path);    
    // Make call and its return result
    return $client->__soapCall($action, $params);
  } else {
    return FALSE;
  }
}

/**
 * Implementation of hook_user_categories(). 
 * Makes a tab appear in user profile to edit Chamilo settings.
 * @return array Array containing name, title and weight of the profile tab
 */
function chamilo_user_categories() {
  return array(array(
    'name' => 'chamilo',
    'title' => t('Chamilo settings'),
    'weight' => 2,
/* TODO
    'access arguments' => 'connect with own Chamilo account',
*/
  ));
}

/**
 * Implementation of hook_menu_alter() to pair with hook_user_categories - see http://api.drupal.org/api/drupal/modules!user!user.api.php/function/hook_user_categories/7
 */
/*
function chamilo_menu_alter(&$items){
 
  // Need to add user category tabs here like this
  // first in hook_user_categories, then here to expand
  $items['user/%user_category/edit/chamilo']['page callback'] = 'chamilo_customer_profile_form_wrapper';
  $items['user/%user_category/edit/chamilo']['page arguments'] = array(1);
  $items['user/%user_category/edit/chamilo']['module'] = 'chamilo';
  $items['user/%user_category/edit/chamilo']['file'] = 'chamilo.module';
}
*/

/**
 * Implementation of hook_form_FORM_ID_alter()
 * Shows all user settings in the Chamilo settings tab in user profile
 * @param object The form object
 * @param object The form_state object (not really necssary)
 * @param string The form ID (not really necessary here)
 * @return void Alters objects passed by reference
 */
function chamilo_form_user_profile_form_alter(&$form, &$form_state, $form_id) {
  if (is_object($form['#user']) && !empty($form['#user']->uid)) {
    $entity = $form['#user'];
    chamilo_load_user_data($entity);
    $admin_access = user_access('administer chamilo');
    $connect_access = user_access('connect with own Chamilo account');
    $sync_access = user_access('sync users with Chamilo accounts');
    if ($form['#user_category'] == 'chamilo' && ($connect_access || $sync_access || $admin_access)) {
      $form['chamilo_settings'] = array(
        '#type' => 'fieldset',
        '#title' => t('Chamilo settings'),
        '#collapsible' => TRUE,
        '#weight' => 1,
        '#tree' => TRUE,
      );
/* This section is only for admins
      if ($sync_access || $admin_access) {
        $form['chamilo_settings']['sync_account'] = array(
          '#type' => 'checkbox',
          '#title' => t('Sync with a chamilo account.'),
          '#default_value' => in_array($entity->uid, variable_get('chamilo_accounts', array())),
          '#description' => t('If enabled, system will create or override a chamilo account with same username, email and password.')
        );
      }
*/
      if ($connect_access || $admin_access) {
        $form['chamilo_settings']['duser'] = array(
          '#type' => 'textfield',
          '#title' => t('Chamilo username'),
          '#default_value' => $entity->chamilo_settings['user'],
          '#description' => t('Chamilo username.'),
        );

        $api_key_url = chamilo_sso_protocol() . variable_get('chamilo_server', '') . CHAMILO_API_KEY_URL;

        $form['chamilo_settings']['apikey'] = array(
          '#type' => 'textfield',
          '#title' => t('Chamilo API key'),
          '#default_value' => $entity->chamilo_settings['apikey'],
          '#description' => t('Chamilo API key. Find your API key in your Chamilo Profile by clicking <a href="@url">here</a>.',array('@url' => $api_key_url)),
        );
/* This section is only for admins, and it has been moved to chamilo.admin.inc, to the module config form
        if ($admin_access) {
          $form['chamilo_settings']['course_visibility'] = array(
            '#type' => 'checkboxes',
            '#title' => t('Trainings Visibilities'),
            '#description' => t('If this site displays a block with a list of your courses, will be filtered by criterias above.'),
            '#default_value' => !empty($entity->chamilo_settings['course_visibility'])? $entity->chamilo_settings['course_visibility']: array(),
            '#options' => chamilo_course_visibility(),
          );
        }
*/
        $form['chamilo_settings']['agenda_time_frame'] = array(
          '#type' => 'radios',
          '#title' => t('Agenda time frame'),
          '#default_value' => $entity->chamilo_settings['agenda_time_frame'],
          '#options' => chamilo_agenda_time_frame(TRUE),
        );
      }
    }else {
        $form['chamilo_settings']['duser'] = array(
          '#type' => 'textfield',
          '#title' => t('Chamilo username'),
          '#default_value' => $entity->chamilo_settings['user'],
          '#description' => t('You do not have the right permissions to update these account details. If you think this is a mistake, please contact your administrator and ask to be allowed to connect to your own Chamilo account.'),
          '#disabled' => true,
        );
    }
  }
}

/**
 * Implements hook_field_extra_fields().
 */
/* TODO: Expose account fields to Field UI
function chamilo_field_extra_fields() {
  $return['user']['user'] = array(
    'form' => array(
      'chamilo' => array(
        'label' => 'Chamilo fields',
        'description' => t('Chamilo module account form elements'),
        'weight' => -10,
      ),
    ),
  );

  return $return;
}
*/

/**
 * Implementation of hook_user_login().
 * Called when the user just logged in
 */
function chamilo_user_login(&$edit, &$account) {
  if ($account->uid && isset($_GET['sso_referer'])) {
    chamilo_sso_auth($account);
  }
}

/**
 * Implementation of hook_user_load();
 */
/* TODO
function chamilo_user_load($users) {
  static $chamilo_accounts;

  if (!isset($chamilo_accounts)) {
    $chamilo_accounts = variable_get('chamilo_accounts', array());
  }
  if (!isset($account->chamilo_user)) {
    $account->chamilo_user = in_array($account->uid, $chamilo_accounts);
  }
  chamilo_load_user_data($account);

  break;
}
*/


/**
 * Implementation of hook_user_insert().
 */
function chamilo_user_insert(&$edit, &$account, $category = NULL) {
  $admin_access = user_access('administer chamilo');
  $connect_access = user_access('connect with own Chamilo account');
  $sync_access = user_access('sync users with Chamilo accounts');
  $users = array();
    if (!isset($edit['chamilo_settings']['sync_account']) && ($sync_access || $admin_access)) {
        $users = variable_get('chamilo_accounts', array());
        if (!is_array($users)) { $users = array(); }
        $params = array(
                'username' => $edit['name'],
                'secret_key' => chamilo_get_signature(CHAMILO_SECRET_KEY),
        );
        // Check as chamilo account
        $chamilo_account = chamilo_soap_call('registration', 'WSGetUserFromUsername', $params);
        // Deterimine wether to Create or Override account at Chamilo
        if (empty($chamilo_account->user_id)) {
            $params = array(
                'loginname' => $edit['name'],
                'password' => ($edit['pass'] ? $edit['pass'] : $account->pass),
                'password_crypted' => 1,
                'email' => $edit['mail'],
                'firstname' => '',
                'lastname' => '',
                'language' => '',
                'phone' => '',
                'expiration_date' => '',
                'original_user_id_name' => 'drupal_user_id',
                'original_user_id_value' => $account->uid,
                'extra' => '',
                'active' => '1',
                'status' => '1',
                'secret_key' => chamilo_get_signature(CHAMILO_SECRET_KEY),
            );
            // Make call
            $user = chamilo_soap_call('registration', 'WSCreateUser', $params);

            // Save
            if (!isset($users[$account->uid])) {
              $users[$account->uid] = $account->uid;
              variable_set('chamilo_accounts', $users);
            }
            drupal_set_message('User succesfully syncronized with Chamilo.');
        }        
      } else { // Unlink account
        // Save
        if (isset($users[$account->uid])) {
          unset($users[$account->uid]);
          variable_set('chamilo_accounts', $users);
        }
      }
    if ($connect_access || $admin_access) {
      chamilo_save_user_data($edit, $account, $category);
    }
  
}

/**
 * Implementation of hook_user_update().
 */
function chamilo_user_update(&$edit, &$account, $category = NULL) {
  $admin_access = user_access('administer chamilo');
  $connect_access = user_access('connect with own Chamilo account');
  $sync_access = user_access('sync users with Chamilo accounts');
  if ($category == 'chamilo') {
    if (!isset($edit['chamilo_settings']['sync_account']) && ($sync_access || $admin_access)) {
      $users = variable_get('chamilo_accounts', array());
      if (!is_array($users)) { $users = array(); }
      // Sync account
      if ($edit['chamilo_settings']['sync_account']) {
        // Check as chamilo account
        $chamilo_account = chamilo_soap_call('user_manager', 'WSGetUserFromUsername', array('username' => $edit['name']));
        // Deterimine wether to Create or Override account at Chamilo
        if (isset($chamilo_account->firstName) ? $chamilo_account->username == '' : FALSE) {
          $action = 'WSCreateUser';
        }
        else {
          $action = 'WSEditUser';
        }
        // Make call
        $user = chamilo_soap_call('user_manager', $action, array(
          'loginname' => $edit['name'], 'password' => ($edit['pass'] ? $edit['pass'] : $account->pass),
          'password_crypted' => 1, 'email' => $edit['mail'],
        ));
        // Save
        if (!isset($users[$account->uid])) {
          $users[$account->uid] = $account->uid;
          variable_set('chamilo_accounts', $users);
        }
        drupal_set_message('User succesfully syncronized with Chamilo.');
      }
      // Unlink account
      else {
        // Save
        if (isset($users[$account->uid])) {
          unset($users[$account->uid]);
          variable_set('chamilo_accounts', $users);
        }
      }
    }
    if ($connect_access || $admin_access) {
      chamilo_save_user_data($edit, $account, $category);
    }
  }
}

/**
 * Loads user's Chamilo settings from DB
 * @param object Account object
 * @return void Alters the account object
 */
function chamilo_load_user_data(&$account) {
  $result = db_query('SELECT duser, apikey, course_visibility, agenda_time_frame FROM {chamilo_user} WHERE user_id = (:uid)', array(':uid' => $account->uid));

  foreach($result as $record) {
    $account->chamilo_settings = array(
      'user' => $record->duser,
      'apikey' => $record->apikey,
      'course_visibility' => unserialize($record->course_visibility),
      'agenda_time_frame' => $record->agenda_time_frame,
    );
    return;
  }

  $account->chamilo_settings = array(
    'user' => '',
    'apikey' => '',
    'course_visibility' => '',
    'agenda_time_frame' => '',
  );
}


function chamilo_save_user_data(&$edit, &$account, $category, $register = FALSE) {
  $data = &$edit['chamilo_settings'];
  // Pre-process courses visibility
  if (!is_array($data['course_visibility'])) {
    $data['course_visibility'] = array($data['course_visibility']);
  }
  $data['course_visibility'] = preg_grep('/^0$/', $data['course_visibility'], PREG_GREP_INVERT);
  $data['course_visibility'] = count($data['course_visibility']) ? serialize($data['course_visibility']) : NULL;
  
  // Pre-process agenta time frame
  if (!empty($data['agenda_time_frame']) && $data['agenda_time_frame'] == '0') {
    $data['agenda_time_frame'] = '';
  }
  // Look for data
  $save_data = FALSE;
  $fields = array(NULL, 'duser', 'apikey', 'course_visibility', 'agenda_time_frame');
  while($field = next($fields)) {
    if (!empty($data[$field]) && $data[$field]) {
      $save_data = TRUE;
      break;
    }
  }

  // Delete old user data
  db_delete('chamilo_user')
    ->condition('user_id', $account->uid)
    ->execute();

  if ($save_data) {
    $edit = (object)array(
      'user_id' => $account->uid,
      'duser' => $data['duser'],
      'apikey' => $data['apikey'],
      'course_visibility' => $data['course_visibility'],
      'agenda_time_frame' => $data['agenda_time_frame'],
    );
    drupal_write_record('chamilo_user', $edit);
  }
}

/**
 * Implementation of hook_menu().
 */
function chamilo_menu() {
  //var_dump("LINE: " . __LINE__, __FUNCTION__);exit;
  $items['admin/config/system/chamilo'] = array(
    'title' => 'Chamilo',
    'description' => 'Configure integration settings with Chamilo.',
    'page callback' => 'chamilo_admin_settings',
    'access arguments' => array('administer chamilo'),
    'file' => 'chamilo.admin.inc',
  );
  return $items;
}

/**
 * Gets the Chamilo signature (personal or global) to call the web services
 * @param int Type of signature (flag)
 * @return string The signature to join to any web service call
 */
function chamilo_get_signature($type = CHAMILO_GLOBAL_SIGNATURE) {
  global $user;

  switch ($type) {
    case CHAMILO_PERUSER_SIGNATURE:
      chamilo_load_user_data($user);
      if (isset($user->chamilo_settings)) {
        return sha1($user->chamilo_settings['user'] . $user->chamilo_settings['apikey']);
      }
      break;
     case CHAMILO_SECRET_KEY:
         $chamilo_apikey = sha1($_SERVER['SERVER_ADDR'] . variable_get('chamilo_appkey', ''));
         return $chamilo_apikey;
     break;
    default:
    case CHAMILO_GLOBAL_SIGNATURE:
      $chamilo_user = variable_get('chamilo_user', '');
      $chamilo_apikey = variable_get('chamilo_appkey', '');
      return sha1($chamilo_user . $chamilo_apikey);
  }
}

/**
 * Implementation of hook_block_info().
 */
function chamilo_block_info() {
  $blocks['trainings'] = array(
    'info' => t('Chamilo courses'),
    'weight' => 0,
  );
  $blocks['user_agenda'] = array(
    'info' => t('My Chamilo agenda'),
    'weight' => 0,
  );
  $blocks['user_trainings'] = array(
    'info' => t('My Chamilo courses'),
    'weight' => 0,
  );
  return $blocks;
}

/**
 * Implementation of hook_block_view().
 *
 * Generates the administrator-defined blocks for display.
 */
function chamilo_block_view($delta = '') {
  global $user;
  chamilo_load_user_data($user);

  if (variable_get('chamilo_server', '') == '') {
    drupal_set_message(t("Chamilo module yet not configured, can't display blocks."));
    return;
  }

  $block = array();

  switch ($delta) {
    case 'trainings':
      $signature = chamilo_get_signature();
      $chamilo_user = variable_get('chamilo_user', '');
      $service = chamilo_get_service_path('courses_list');
      $client = new SoapClient($service);
      $chamilo_courses_block_items = variable_get('chamilo_courses_block_items', array('public'));
      foreach ($chamilo_courses_block_items as $key => $item) {
        if ($item === 0) {
          unset($chamilo_courses_block_items[$key]);
        }
      }
      $visibilities = implode(',', $chamilo_courses_block_items);
      //$visibilities = 'public-registered';
      $courses = $client->WSCourseList($chamilo_user, $signature, $visibilities);
      $block = array(
        'subject' => t('Chamilo trainings'),
        'content' => theme('chamilo_course_list', $courses, $limit = 10), // change the limit here to show more
      );
      break;

    case 'user_agenda':
      if (isset($user->chamilo_settings)) {
        $signature = chamilo_get_signature(CHAMILO_PERUSER_SIGNATURE);
        $service = chamilo_get_service_path('user_info');
        $agenda_time_frame = !empty($user->chamilo_settings['agenda_time_frame']) ? $user->chamilo_settings['agenda_time_frame'] : 30;
        $datestart = (int) date('Ymd');
        $dateend = (int) date('Ymd', strtotime("+$agenda_time_frame days"));
        $client = new SoapClient($service);
        $agenda = $client->WSEventsList($user->chamilo_settings['user'], $signature, $datestart, $dateend);
        $block = array(
          'subject' => t('My Chamilo agenda'),
          'content' => theme('chamilo_user_agenda_list', $agenda),
        );
      }
      break;

    case 'user_trainings':
      if (isset($user->chamilo_settings)) {
        $signature = chamilo_get_signature(CHAMILO_PERUSER_SIGNATURE);
        $service = chamilo_get_service_path('user_info');
        $client = new SoapClient($service);
        $agenda = $client->WSCourseListOfUser($user->chamilo_settings['user'], $signature);
        $data['content'] = theme_chamilo_course_list($agenda);
        $block = array(
          'subject' => t('My Chamilo Courses'),
          'content' => theme('chamilo_course_list', $agenda),
        );
      }
      break;
  }
  return $block;
}

/**
 * Implementation of hook_block_configure().
 */
function chamilo_block_configure($delta = '') {
  //var_dump("LINE: " . __LINE__, __FUNCTION__);exit;
  if ($delta == 'trainings') {
    $form['items'] = array(
      '#type' => 'checkboxes',
      '#title' => t('Trainings Visibilities'),
      '#default_value' => variable_get('chamilo_courses_block_items', array()),
      '#options' => chamilo_course_visibility(),
    );
    return $form;
  }
}

/**
 * Implementation of hook_block_save().
 */
function chamilo_block_save($delta = '', $edit = array()) {
  //var_dump("LINE: " . __LINE__, __FUNCTION__);exit;
  if ($delta == 'trainings') {
    variable_set('chamilo_courses_block_items', $edit['items']);
  }
}

/**
 * Implementation of hook_theme().
 */
function chamilo_theme($existing, $type, $theme, $path) {
  //var_dump("LINE: " . __LINE__, __FUNCTION__);exit;
  return array(
    'chamilo_course_list' => array(
      'arguments' => array('courses' => NULL),
    ),
    'chamilo_user_agenda_list' => array(
      'arguments' => array('agenda_items' => NULL),
    ),
    'chamilo_course_list' => array(
      'arguments' => array('courses' => NULL),
    ),
  );
}

/**
 * Prepare courses list
 * @param   Array
 *    A list of course details as returned by chamilo_curl_exec()
 * @param int
 *    Limit for the number of courses to be shown
 */
function theme_chamilo_course_list($courses, $limit = 10) {
  if (!is_array($courses)) return;
  if (count($courses)) {
    drupal_add_css(drupal_get_path('module', 'chamilo') .'/chamilo.css', 'module', 'all', FALSE);
    ob_start();
    $i = 0;
    ?><ul><?php
    // Limit the list to 10 (or any other limit) courses, otherwise it starts to get very messy
    foreach ($courses as $course) {
        if ($i >= $limit) { break; }
?><li class="chamilo-course">
<span class="chamilo-course-title"><a href="<?php print $course->url ?>"><?php print utf8_decode($course->title) ?></a></span>
<span class="chamilo-course-info"><?php print utf8_decode($course->language).(empty($course->teacher)?'':' - '.utf8_decode($course->teacher)) ?></span>
</li><?php
        $i++;
    }
    ?></ul><?php
    $output = ob_get_contents();
    ob_end_clean();
    return $output;
  }
}

function theme_chamilo_user_agenda_list($agenda_items) {
  if (!is_array($agenda_items)) return;
  $path = drupal_get_path('module', 'chamilo');
  drupal_add_css($path .'/chamilo.css', 'module', 'all', FALSE);
  $output = '';
  $agenda = array('items' => array());
  foreach ($agenda_items as $item) {
    $html = '<span class="chamilo-event-title">'. l(utf8_decode($item->title), $item->link) .'</span>';
    $html .= '<span class="chamilo-event-info">'. utf8_decode($item->coursetitle) .'</span>';
    $html .= '<span class="chamilo-event-info">'. date('M j, Y, g:i a', strtotime($item->datestart)) .'</span>';
    $html .= '<span class="chamilo-event-info">'. date('M j, Y, g:i a', strtotime($item->dateend)) .'</span>';
    $agenda['items'][] = $html;
  }
  $output .= theme('item_list', $agenda);
  return $output;
}

/**
 * Implementation of hook_permission().
 */
function chamilo_permission() {
  return array(
    'administer chamilo' => array(
      'title' => t('Administer chamilo'),
      'description' => t('Let configure Chamilo integration settings.'),
    ),
    'connect with own Chamilo account' => array(
      'title' => t('connect with own Chamilo account'),
      'description' => t('Access to SSO and user blocks.'),
    ),
  );
}

/**
 * Return supported course visibility options
 */
function chamilo_course_visibility() {
  return array(
    'public' => t('public'),
    'private' => t('private'),
    'public-registered' => t('public registered'),
    'closed' => t('closed')
  );
}

function chamilo_agenda_time_frame($optional = FALSE) {
  static $time_frames;

  if (!is_array($time_frames)) {
    $time_keys = array(30 => '', 15 => '', 7 => '');
    // Describe time frames
    $time_frames = $optional ? array('0' => t('Disabled')) : array();
    foreach ($time_keys as $f => $d) {
      $time_frames[$f] = t('between now and within next !n days', array('!n' => $f));
    }
  }

  return $time_frames;
}

/**
 * Given a $service name, return corresponding location and uri into an array.
 */
function chamilo_get_service_path($service) {
  static $services;
  $chamilo_server = variable_get('chamilo_server', '');
  if (!isset($services)) {
    $services = array('courses_list', 'user_info', 'registration');
  }

  if (in_array($service, $services)) {
    return chamilo_sso_protocol(). $chamilo_server . CHAMILO_BASE_URL .'/'. $service .'.soap.php?wsdl';
  }
}
