<?php
// ; $Id$

/**
 * @file
 * Enables BOINC team functionality.
 *
 * Integrates team data and features of the existing
 * BOINC platorm with the Drupal concept of a team.
 */


/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *
 * Includes that provide supporting functions
 *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */

require_once('includes/boincteam.forms.inc');
require_once('includes/boincteam.helpers.inc');
require_once('includes/boincteam.rules.inc');

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *
 * Hooks into core modules
 *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */

/**
 * Implementation of hook_menu()
 */
function boincteam_menu() {
  $items = array();
  $items['community/teams/%/assume-foundership'] = array(
    'page callback' => 'boincteam_assume_foundership',
    'page arguments' => array(2),
    'access callback' => 'boincteam_is_member',
    'access arguments' => array(2),
    'type' => MENU_CALLBACK
  );
  $items['community/teams/%/join'] = array(
    'page callback' => 'boincteam_join',
    'page arguments' => array(2),
    'access arguments' => array('join boincteam'),
    'type' => MENU_CALLBACK
  );
  $items['community/teams/%/leave'] = array(
    'page callback' => 'boincteam_leave',
    'page arguments' => array(2),
    'access arguments' => array('join boincteam'),
    'type' => MENU_CALLBACK
  );
  $items['community/teams/%/delete'] = array(
    'page callback' => 'boincteam_delete',
    'page arguments' => array(2),
    'access callback' => 'boincteam_is_founder',
    'access arguments' => array(2),
    'type' => MENU_CALLBACK
  );
  $items['community/teams/%/deny-foundership-request'] = array(
    'page callback' => 'boincteam_deny_foundership_request',
    'page arguments' => array(2),
    'access callback' => 'boincteam_is_founder',
    'access arguments' => array(2),
    'type' => MENU_CALLBACK
  );
  $items['community/teams/%/edit/admins/remove/%'] = array(
    'page callback' => 'boincteam_remove_admin',
    'page arguments' => array(2,6),
    'access callback' => 'boincteam_is_founder',
    'access arguments' => array(2),
    'type' => MENU_CALLBACK
  );
  $items['community/teams/%/edit/founder/set/%'] = array(
    'page callback' => 'boincteam_set_founder',
    'page arguments' => array(2,6),
    'access callback' => 'boincteam_is_founder',
    'access arguments' => array(2),
    'type' => MENU_CALLBACK
  );
  $items['community/teams/%/edit/members/remove/%'] = array(
    'page callback' => 'boincteam_remove_member',
    'page arguments' => array(2,6),
    'access callback' => 'boincteam_is_founder',
    'access arguments' => array(2),
    'type' => MENU_CALLBACK
  );
  $items['community/teams/%/history/xml'] = array(
    'page callback' => 'boincteam_history_xml',
    'page arguments' => array(2),
    'access callback' => 'boincteam_is_admin',
    'access arguments' => array(2),
    'type' => MENU_CALLBACK
  );
  $items['community/teams/%/request-foundership'] = array(
    'page callback' => 'boincteam_request_foundership',
    'page arguments' => array(2),
    'access callback' => 'boincteam_is_member',
    'access arguments' => array(2),
    'type' => MENU_CALLBACK
  );
  $items['community/teams/%/user-name-autocomplete'] = array(
    'page callback' => '_boincuser_user_name_autocomplete',
    'access callback' => 'boincteam_is_founder',
    'access arguments' => array(2),
    'type' => MENU_CALLBACK,
  );
  $items['community/teams/%/message-all-members'] = array(
    'title' => bts('Send Message to Team', array(), NULL, 'boinc:team-manage'),
    'description' => bts('Send Message to Team', array(), NULL, 'boinc:team-manage'),
    'page callback' => 'drupal_get_form',
    'page arguments' => array('boincteam_sendmessagetoteam', 2),
    'access callback' => 'boincteam_is_admin',
    'access arguments' => array(2),
    'type' => MENU_CALLBACK,
  );
  $items['admin/boinc/utility-team-delete'] = array(
    'title' => 'Utility: Delete SPAM Teams',
    'description' => 'Utililities to help delete BOINC teams created by SPAMMERs.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('boincteam_utility_delete'),
    'access arguments' => array('administer site configuration'),
    'type' => MENU_NORMAL_ITEM,
    'file' => 'boincteam.admin.inc',
  );

  return $items;
}

/**
* Implementation of hook_theme().
*/

function boincteam_theme() {
/*
  This hook is here to theme the table in the admin interface for
  displaying teams to delete, boincteam_utility_team_table. It is a
  Drupal 6 solution that is NOT forward compatible to drupal 7. In
  drupal 7+ the table is simply designed from the ground-up as a
  checkbox table/form.

  See https://www.drupal.org/node/945102
*/
  return array(
    'boincteam_utility_team_table' => array(
      'arguments' => array('form' => NULL),
      'file' => 'boincteam.admin.inc',
    ),
  );
}

/**
* Implementation of hook_views_api().
*/
function boincteam_views_api() {
  return array(
    'api' => 2.0,
    'path' => drupal_get_path('module', 'boincteam')
  );
}

/**
 * Implementation of hook_perm()
 */
function boincteam_perm() {
  return array('join boincteam', 'create boincteam', 'manage boincteam');
}

/**
 * Implementation of hook_cron()
 */
function boincteam_cron() {
  // Sync teams from BOINC DB every day to catch BOINC-wide team updates
  $last_sync = variable_get('boincteam_last_sync', 0);
  if ($last_sync < time() - 24*60*60) {
    boincteam_sync();
    variable_set('boincteam_last_sync', time());
  }
}

/**
 * Callback ...
 */
function boincteam_top_teams() {

}

/**
* Implementation of hook_views_pre_execute().
*/
function boincteam_views_pre_execute(&$view) {
  /* Specific boinc_teams sub-views use the boinc readonly replica
   * DB. These sub-views defined below by their title. If additional
   * sub-views need to be added, add their title to the list of cases
   * below. If a sub-view needs to be reverted to use the master DB,
   * then remove it from the list of cases.
   */
  if ($view->name == 'boinc_teams') {
    switch ($view->display[$view->current_display]->display_title) {
    case 'Top teams overview pane':
    case 'Top teams pane':
    case 'Page':
      $view->base_database = 'boinc_ro';
    }
  }
}

/**
 * Implementation of hook_cron_queue_info()
 */
function boincteam_cron_queue_info() {
  $queues = array();
  $queues['queue_teamdelete'] = array(
    'worker callback' => 'boincteam_delete',
    'time' => 60,
  );
}

/**
 * Implementation of hook_mail_alter()
 */
function boincteam_mail_alter(&$message) {
  if (isset($message['params']['boincteam_headers'])) {
    $message['headers']['Bcc'] = $message['params']['boincteam_headers']['Bcc'];
    $message['to'] = '';
  }
}

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *
 * BOINC team functions
 *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */

/**
 * If there has been no response to a transfer request, the requestor can
 * assume the role of founder
 */
function boincteam_assume_foundership($team_id) {
  global $user;
  $account = user_load($user->uid);
  $team = node_load($team_id);
  $boincteam_id = boincteam_lookup_id($team_id);
  $boincteam = boincteam_load($boincteam_id);
  $boincuser_id = $account->boincuser_id;

  if (boincteam_foundership_transfer_ok($boincteam)) {
    if ($boincuser_id == $boincteam->ping_user) {
      db_set_active('boinc_rw');
      db_query("
        UPDATE {team}
        SET userid = '%d', ping_user = '0', ping_time = '0'
        WHERE id = '%d'",
        $boincuser_id, $boincteam_id
      );
      db_set_active('default');
      drupal_set_message(t('You are now the founder of @team', array(
        '@team' => $team->title
      )));
      watchdog('boincteam', 'User @user assumed foundership of team @nid',
        array(
          '@current_user' => $account->uid,
          '@nid' => $team_id
        ), WATCHDOG_NOTICE
      );
    }
  }
  else {
    drupal_set_message(t('You are not allowed to assume foundership of this
      team.'
    ));
  }
  drupal_goto("community/teams/{$team_id}");
}

/**
 * Delete the team, if empty
 */
function boincteam_delete($team_id) {
  $team = node_load($team_id);
  $boincteam = boincteam_load(boincteam_lookup_id($team_id), TRUE);
  if ($boincteam->nusers == 1) {
    require_boinc('team');
    $boincuser = boincuser_load();
    user_quit_team($boincuser);
    $boincteam->delete();
    node_unpublish_action($team);
    $team->uid = 0;
    node_save($team);
    drupal_set_message(t('@team has been removed.',
      array('@team' => $boincteam->name)));
    drupal_goto('community/teams');
  }
  else {
    drupal_set_message(t('All members must be removed from @team before the
      team can be deleted.', array('@team' => $boincteam->name)), 'error');
    drupal_goto(strstr($_GET['q'], '/delete', TRUE));
  }
}

/**
 * Deny a foundership transfer request
 */
function boincteam_deny_foundership_request($team_id) {
  $boincteam_id = boincteam_lookup_id($team_id);
  // Remove the request from the BOINC database
  db_set_active('boinc_rw');
  db_query("
    UPDATE {team}
    SET ping_user=0
    WHERE id = '%d'",
    $boincteam_id
  );
  db_set_active('default');

  drupal_set_message(t('The transfer request has been denied. No additional
    requests will be allowed until 90 days have passed since this request was
    made.'));
  drupal_goto("community/teams/{$team_id}/edit/founder");
}


/**
 * Get the join date of a user
 */
function boincteam_get_member_join_date($boincteam_id, $boincuser_id = NULL) {
  if (!$boincuser_id) {
    global $user;
    $account = user_load($user->uid);
    $boincuser_id = $account->boincuser_id;
  }
  db_set_active('boinc_rw');
  $timestamp = db_result(db_query("
    SELECT timestamp FROM {team_delta} WHERE
    userid = %d AND teamid = %d AND joining = 1
    ORDER BY timestamp DESC LIMIT 1",
    $boincuser_id, $boincteam_id
  ));
  db_set_active('default');
  return $timestamp;
}

/**
 * Get the team type for display
 */
function boincteam_get_type($team_id) {
  //$vid = boincteam_get_vocabulary_by_name('Teams'); $team->vid = $vid;
  $team = node_load($team_id);
  $terms = taxonomy_node_get_terms($team);
  if ($terms) {
    $term = reset($terms);
    return $term->name;
  } else {
    return null;
  }
}

/**
 * Access a vocabulary of terms by name
 */
function boincteam_get_vocabulary_by_name($name) {
  $vocabs = taxonomy_get_vocabularies('team');
  foreach ($vocabs as $vocab) {
    if ($vocab->name == $name) return $vocab->vid;
  }
  return null;
}

/**
 * Output the XML of the team history
 */
function boincteam_history_xml($team_id) {
  $team = node_load($team_id);
  $boincteam_id = boincteam_lookup_id($team_id);
  $team_history = array(
    'actions' => array(
      'action' => array(),
    ),
  );

  db_set_active('boinc_rw');
  $result = db_query("
    SELECT
      td.userid AS id,
      u.name,
      IF (td.joining, 'joined', 'left') AS action,
      td.total_credit,
      FROM_UNIXTIME(td.timestamp, '%%e %%b %%Y | %%T UTC') AS `when`
    FROM {team_delta} td
    JOIN {user} u ON u.id = td.userid
    WHERE td.teamid = %d
    ORDER BY timestamp ASC",
    $boincteam_id
  );
  db_set_active('default');

  while ($record = db_fetch_array($result)) {
    $team_history['actions']['action'][] = $record;
  }

  header('Content-type: text/xml');
  echo xml_to_text(array_to_xml($team_history));
}

/**
 * Convert a BOINC team ID to a Drupal team ID
 */
function boincteam_lookup_nid($boinc_id) {
  $drupal_id = db_result(db_query("SELECT nid FROM {boincteam} WHERE team_id='%d'", $boinc_id));
  return $drupal_id;
}

/**
 * Convert a Drupal team ID to a BOINC team ID
 */
function boincteam_lookup_id($nid) {
  $boinc_id = db_result(db_query("SELECT team_id FROM {boincteam} WHERE nid = '%d'", $nid));
  return $boinc_id;
}

/**
 * Get a BOINC team object
 */
function boincteam_load($boincteam_id, $full_object = FALSE) {
  require_boinc(array('team'));
  $team = BoincTeam::lookup_id($boincteam_id);
  if ($team AND $full_object) {
    $team->nusers = BoincUser::count("teamid={$team->id}");
    $team->nusers_worked = BoincUser::count("teamid={$team->id} and total_credit>0");
    $team->nusers_active = BoincUser::count("teamid={$team->id} and expavg_credit>0.1");
    $team->forum = BoincForum::lookup("parent_type=1 and category={$team->id}");
    $team->new_members = new_member_list($boincteam_id);
    $team->admins = admin_list($boincteam_id);
    $team->founder = BoincUser::lookup_id($team->userid);
  }
  return $team;
}

/**
 * Check if a user is the team founder
 */
function boincteam_is_founder($nid, $uid = NULL) {
  if (!$uid) {
    global $user;
    $uid = $user->uid;
  }
  if (!boincteam_is_member($nid, $uid)) {
    return FALSE;
  }
  $team_id = boincteam_lookup_id($nid);
  require_boinc('team');
  return is_team_founder(boincuser_load($uid, TRUE), boincteam_load($team_id));
}

/**
 * Check if a user is a team admin
 */
function boincteam_is_admin($nid, $uid = NULL) {
  if (!$uid) {
    global $user;
    $uid = $user->uid;
  }
  if (!boincteam_is_member($nid, $uid)) {
    return FALSE;
  }
  $team_id = boincteam_lookup_id($nid);
  require_boinc('team');
  return is_team_admin(boincuser_load($uid, TRUE), boincteam_load($team_id));
}

/**
 * Check if a user is a team member
 */
function boincteam_is_member($nid, $uid = NULL) {
  if (!$uid) {
    global $user;
    $uid = $user->uid;
  }
  $account = user_load($uid);
  return ($account->team == $nid);
}

/**
 * Display any persistent team messages
 */
function boincteam_show_messages() {
  global $user;
  $uid = $user->uid;
  $account = user_load($uid);
  if ($account->team) {
    if (boincteam_is_founder($account->team, $account->uid)) {
      // Set a notice of any pending foundership requests
      $boincteam_id = boincteam_lookup_id($account->team);
      $boincteam = boincteam_load($boincteam_id);
      if ($boincteam->ping_user > 0) {
        $foundership_url = "community/teams/{$account->team}/edit/founder";
        if (substr($_GET['q'], 0, strlen($foundership_url)) != $foundership_url) {
          drupal_set_message(
            bts(
              'A foundership transfer request has been made for your team. Please !respond.',
              array('!respond' => l(bts('respond to the request', array(), NULL, 'boinc:team-founder-change'), $foundership_url)),
              NULL, 'boinc:team-founder-change'),
            'warning', FALSE
          );
        }
      }
    }
  }
}

/**
 * Add a user to a team
 */
function boincteam_join($team_id) {
  global $user;
  $account = user_load($user->uid);

  $boincteam_id = boincteam_lookup_id($team_id);
  $boincteam = boincteam_load($boincteam_id);
  if ($boincteam->joinable AND $account->team != $team_id) {
    require_boinc('team');
    $boincuser = boincuser_load();
    if (user_join_team($boincteam, $boincuser)) {
      drupal_set_message(t('You are now a member of @team!',
        array('@team' => $boincteam->name)));
      watchdog('boincteam', 'added user @uid to team @nid',
        array('@uid' => $user->uid, '@nid' => $team_id), WATCHDOG_NOTICE);
    }
    else {
      // @todo - consider another rule/error event here
      drupal_set_message(t('There was a problem joining @team, please try again
        later', array('@team' => $boincteam->name)));
      watchdog('boincteam', 'error adding user @uid to team @nid',
        array('@uid' => $user->uid, '@nid' => $team_id), WATCHDOG_ERROR);
    }
  }
  drupal_goto("community/teams/{$team_id}");
}

/**
 * Leave a team
 */
function boincteam_leave($team_id) {
  global $user;
  $account = user_load($user->uid);

  $boincteam_id = boincteam_lookup_id($team_id);
  $boincteam = boincteam_load($boincteam_id);
  if ($account->team == $team_id) {
    require_boinc('team');
    $boincuser = boincuser_load();
    user_quit_team($boincuser);
    drupal_set_message(t('You are no longer a member of @team.',
      array('@team' => $boincteam->name)));
    watchdog('boincteam', 'removed user @uid from team @nid',
      array('@uid' => $user->uid, '@nid' => $team_id), WATCHDOG_NOTICE);
  }
  else {
      drupal_set_message(t('You are not a member of @team, so you cannot revoke
        your membership to it.', array('@team' => $boincteam->name)));
  }
  drupal_goto("community/teams/{$team_id}");
}

/**
 * Remove team admin status from a user
 */
function boincteam_remove_admin($team_id, $user_id) {
  global $user;
  $account = user_load($user_id);
  $team = node_load($team_id);
  $boincteam_id = boincteam_lookup_id($team_id);
  $boincuser_id = $account->boincuser_id;

  if (boincteam_is_admin($team_id, $account->uid)) {
    // Update the team in the BOINC db
    db_set_active('boinc_rw');
    db_query("
      DELETE FROM {team_admin} WHERE
        teamid = '%d' AND userid = '%d'",
      $boincteam_id,
      $boincuser_id
    );
    db_set_active('default');
    drupal_set_message(t('@user is no longer an admin of @team.',
      array(
        '@user' => $account->boincuser_name,
        '@team' => $team->title
      )
    ));
    watchdog('boincteam', 'User @current_user removed admin status for user
      @uid from team @nid',
      array(
        '@current_user' => $user->uid,
        '@uid' => $account->uid,
        '@nid' => $team_id
      ), WATCHDOG_NOTICE);
  }
  drupal_goto("community/teams/{$team_id}/edit/admins");
}

/**
 * Remove a user from a team
 */
function boincteam_remove_member($team_id, $user_id) {
  global $user;
  $account = user_load($user_id);

  $boincteam_id = boincteam_lookup_id($team_id);
  $boincteam = boincteam_load($boincteam_id);
  if ($account->team == $team_id) {
    require_boinc('team');
    $boincuser = boincuser_load($user_id, TRUE);
    user_quit_team($boincuser);
    drupal_set_message(t('@user has been removed from @team.',
      array(
        '@user' => $account->boincuser_name,
        '@team' => $boincteam->name
      )
    ));
    watchdog('boincteam', 'User @current_user removed user @uid from team @nid',
      array(
        '@current_user' => $user->uid,
        '@uid' => $account->uid,
        '@nid' => $team_id
      ), WATCHDOG_NOTICE);
  }
  else {
      drupal_set_message(t('@user is not a member of @team, so you cannot
        revoke the membership.', array(
          '@user' => $account->boincuser_name,
          '@team' => $boincteam->name
        )
      ));
  }
  drupal_goto("community/teams/{$team_id}/edit/members");
}

/**
 * Request a foundership transfer
 */
function boincteam_request_foundership($team_id) {
  global $user;
  $account = user_load($user->uid);
  $team = node_load($team_id);
  $boincteam_id = boincteam_lookup_id($team_id);
  $boincteam = boincteam_load($boincteam_id);
  $boincuser_id = $account->boincuser_id;

  if (boincteam_is_founder($team_id, $account->uid)) {
    // Shouldn't even be here...
    drupal_set_message(t('@user is already the team founder.',
      array(
        '@user' => $account->boincuser_name
      )
    ), 'warning');
  }
  elseif (!boincteam_new_foundership_transfer_request_ok($team_id)) {
    // It hasn't been long enough since the last transfer request
    drupal_set_message(t('A foundership change was requested during the last 90
      days, so new requests are not allowed. Please try again later.'
    ), 'warning');
  }
  elseif (boincteam_is_member($team_id, $account->uid)) {
    // Log the transfer request
    db_set_active('boinc_rw');
    db_query("
      UPDATE {team}
      SET ping_user = '%d', ping_time='%d'
      WHERE id = '%d'",
      $boincuser_id, time(), $boincteam_id
    );
    db_set_active('default');
    drupal_set_message(t('You have requested foundership of @team. The current
      founder has 60 days to respond to this request.',
      array(
        '@team' => $team->title
      )
    ));
    watchdog('boincteam', 'User @user requested foundership of team @nid',
      array(
        '@current_user' => $account->uid,
        '@nid' => $team_id
      ), WATCHDOG_NOTICE);
  }
  drupal_goto("community/teams/{$team_id}");
}

/**
 * Transfer foundership to another team member
 */
function boincteam_set_founder($team_id, $user_id) {
  global $user;
  $account = user_load($user_id);
  $team = node_load($team_id);
  $boincteam_id = boincteam_lookup_id($team_id);
  $boincuser_id = $account->boincuser_id;

  if (boincteam_is_member($team_id, $account->uid)) {
    // Update the team in the BOINC db
    db_set_active('boinc_rw');
    db_query("
      UPDATE {team}
      SET userid = '%d', ping_user=0
      WHERE id = '%d'",
      $boincuser_id, $boincteam_id
    );
    db_set_active('default');
    drupal_set_message(t('Foundership of @team has been transfered to @user.',
      array(
        '@user' => $account->boincuser_name,
        '@team' => $team->title
      )
    ));
    watchdog('boincteam', 'User @current_user transferred foundership of team
      @nid to user @uid',
      array(
        '@current_user' => $user->uid,
        '@uid' => $account->uid,
        '@nid' => $team_id
      ), WATCHDOG_NOTICE);
  }
  drupal_goto("community/teams/{$team_id}");
}

/**
 * See if a new foundership transfer request is allowed
 */
function boincteam_new_foundership_transfer_request_ok($team_id) {
  $boincteam_id = boincteam_lookup_id($team_id);
  $boincteam = boincteam_load($boincteam_id);
  $now = time();
  if ($boincteam->ping_user <= 0) {
    if ($boincteam->ping_time < $now - 60 * (24*60*60)) {
      return TRUE;
    }
    return FALSE;
  }
  if ($boincteam->ping_time < $now - 90 * (24*60*60)) {
    return TRUE;
  }
  return FALSE;
}

/**
 * The time at which foundership can be transferred if the founder has not
 * responded to the request
 */
function boincteam_foundership_transfer_ok_time($boincteam) {
    return $boincteam->ping_time + 60 * (24*60*60);
}

/**
 * Check if foundership can now be transferred
 */
function boincteam_foundership_transfer_ok($boincteam) {
    return (time() > boincteam_foundership_transfer_ok_time($boincteam));
}

/**
 * Check if a user has an active foundership request with a team
 */
function boincteam_user_requested_foundership($team_id, $user_id = NULL) {
  if (!$user_id) {
    global $user;
    $user_id = $user->uid;
  }
  $account = user_load($user_id);
  $boincteam_id = boincteam_lookup_id($team_id);
  $boincteam = boincteam_load($boincteam_id);

  if ($boincteam->ping_user == $account->boincuser_id) {
    // Be sure the request is still active
    return !boincteam_new_foundership_transfer_request_ok($team_id);
  }
}


/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *
 * Pane content for panels
 *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  */

/**
 * General info about team admins
 */
function boincteam_about_admins_panel() {
  $output = '';
  $output .= '<h2 class="pane-title">' . bts('About team admins', array(), NULL, 'boinc:team-admins-panel') . '</h2>';
  $output .= '<div>';
  $output .= '<p>' . bts('Team admins can:', array(), NULL, 'boinc:team-admins-panel') . '</p>';
  $output .= '<ul>';
  $output .= '  <li>' . bts('Edit team information', array(), NULL, 'boinc:team-admins-panel') . '</li>';
  $output .= '  <li>' . bts("View the team's join / quit history", array(), NULL, 'boinc:team-admins-panel') . '</li>';
  $output .= '  <li>' . bts('Moderate the team forum', array(), NULL, 'boinc:team-admins-panel') . '</li>';
  $output .= '  <li>' . bts('Remove members from the team', array(), NULL, 'boinc:team-admins-panel') . '</li>';
  $output .= '  <li>' . bts('Disband a team if it has no members', array(), NULL, 'boinc:team-admins-panel') . '</li>';
  $output .= '</ul>';
  $output .= '</div>';
  $output .= '<div>';
  $output .= '<p>' . bts('Team admins cannot:', array(), NULL, 'boinc:team-admins-panel') . '</p>';
  $output .= '<ul>';
  $output .= '  <li>' . bts('Change the team founder', array(), NULL, 'boinc:team-admins-panel') . '</li>';
  $output .= '  <li>' . bts('Remove members', array(), NULL, 'boinc:team-admins-panel') . '</li>';
  $output .= '  <li>' . bts('Add / Remove team admins', array(), NULL, 'boinc:team-admins-panel') . '</li>';
  $output .= '</ul>';
  $output .= '</div>';
  $output .= '<p>' . bts('If a team admin quits the team, they cease to be a'
    . ' team admin. We recommend only selecting people you know and trust', array(), NULL, 'boinc:team-admins-panel')
    . '</p>';
  return $output;
}

/**
 * General info about changing the team founder
 */
function boincteam_about_founder_panel() {
  $output = '';
  $output .= '<h2 class="pane-title">' . bts('Changing the team founder', array(), NULL, 'boinc:team-founder-panel')
    . '</h2>';
  $output .= '<div>';
  $output .= '<p>' . bts('Notes about changes in foundership:', array(), NULL, 'boinc:team-founder-panel') . '</p>';
  $output .= '<ul>';
  $output .= '  <li>' . bts('Any member of the team is eligible', array(), NULL, 'boinc:team-founder-panel') . '</li>';
  $output .= '  <li>' . bts('Current founder becomes a normal user', array(), NULL, 'boinc:team-founder-panel') . '</li>';
  $output .= '</ul>';
  $output .= '</div>';
  $output .= '<div>';
  $output .= '<p>' . bts('Foundership can be requested by team members:', array(), NULL, 'boinc:team-founder-panel')
    . '</p>';
  $output .= '<ul>';
  $output .= '  <li>' . bts('One request is allowed at a time', array(), NULL, 'boinc:team-founder-panel') . '</li>';
  $output .= '  <li>' . bts('It must be 60 days since any previous request', array(), NULL, 'boinc:team-founder-panel')
    . '</li>';
  $output .= '  <li>' . bts('Any active request must be older than 90 days', array(), NULL, 'boinc:team-founder-panel')
    . '</li>';
  $output .= '  <li>' . bts('Current founder has 60 days to respond to a'
    . ' request', array(), NULL, 'boinc:team-founder-panel') . '</li>';
  $output .= '</ul>';
  $output .= '</div>';
  return $output;
}

/**
 * Link to create a new team
 */
function boincteam_create_team_link_panel() {
  global $user;
  $account = user_load($user->uid);
  $unrestricted_role = array_search('verified contributor', user_roles(true));
  $output = '';
  $output .= '<h2 class="pane-title">' . bts('Create a new team', array(), NULL, 'boinc:create-team-panel') . '</h2>';
  $output .= '<p>' . bts('If you cannot find a team that is right for you, you'
    . ' can create a team.', array(), NULL, 'boinc:create-team-panel') . '</p>';
  $output .= '<ul class="tab-list">';
  $output .= '  <li class="first last tab">';
  if (isset($account->roles[$unrestricted_role])) {
    $output .= l(bts('Create new team', array(), NULL, 'boinc:create-team-panel'), 'community/teams/add');
  } elseif ($account->uid <= 0) {
    $output .= l(
      bts('Login to create a new team', array(), NULL, 'boinc:create-team-panel'),
      'user/login',
      array('query' => drupal_get_destination())
    );
  } else {
    $min_credit_needed = variable_get('boinc_comment_min_credit', 0);
    $credit_needed = $min_credit_needed - $account->boincuser_total_credit;
    $output .= '[';
    if ($credit_needed == 1) {
      $output .= bts('You must earn 1 more credit!', array(), NULL, 'boinc:create-team-panel');
    }
    else {
      $output .= bts('You must earn @count more credits!',
        array('@count' => $credit_needed),
	NULL, 'boinc:create-team-panel'
      );
    }
    $output .= ']';
  }
  $output .= '  </li>';
  $output .= '</ul>';
  return $output;
}

/**
 * Create team form
 */
function boincteam_create_team_panel() {
  $output = '';
  $output .= '<h2 class="pane-title">' . bts('Create a team', array(), NULL, 'boinc:create-team-panel') . '</h2>';
  $output .= drupal_get_form('boincteam_create_form');

  return $output;
}

/**
 * Link to user's team
 */
function boincteam_dashboard_panel($uid = NULL) {
  global $user;
  if (!$uid) {
    $uid = $user->uid;
  }
  $output = '';
  $account = user_load($uid);
  if ($account->team) {
    $team = boincteam_load(boincteam_lookup_id($account->team));
    $output .= '<h2 class="pane-title">' . bts('Team', array(), NULL, 'boinc:team-dashboard') . '</h2>';
    $output .= '<div class="stats">';
    $output .= '  <label>' . bts('Name', array(), NULL, 'boinc:user-or-team-name') . ': </label>';
    $output .= '  <span>' . l($team->name, "community/teams/{$account->team}") . '</span>';
    $output .= '</div>' . "\n";
    $output .= '<div class="stats">';
    $output .= '  <label>' . bts('Member since', array(), NULL, 'boinc:user-info') . ': </label>';
    $output .= '  <span>' . date('j F Y', boincteam_get_member_join_date($team->id, $account->boincuser_id)) . '</span>';
    $output .= '</div>' . "\n";
    $output .= '<div class="stats">';
    $output .= '  <label>' . bts('Country', array(), NULL, 'boinc:country-of-origin') . ': </label>';
    $output .= '  <span>' . $team->country . '</span>';
    $output .= '</div>' . "\n";
    $output .= '<div class="stats">';
    $output .= '  <label>' . bts('Total credit', array(), NULL, 'boinc:user-or-team-total-credits') . ': </label>';
    $output .= '  <span>' . number_format($team->total_credit, 0) . '</span>';
    $output .= '</div>' . "\n";
  }
  else if ($user->uid == $account->uid) {
    $output .= '<h2 class="pane-title">' . bts('Team (None)', array(), NULL, 'boinc:team-dashboard') . '</h2>';
    $output .= '<ul class="tab-list action-list">';
    $output .= '<li class="tab primary">';
    $output .= l(bts('Join a Team', array(), NULL, 'boinc:team-dashboard'), 'community/teams');
    $output .= '</li>';
    $output .= '</ul>';
  }
  return $output;
}

/**
 * Edit team form
 */
function boincteam_edit_team_panel($team_id) {
  $team = node_load($team_id);
  $output = '';
  $output .= '<h2 class="pane-title">' . $team->title . '</h2>';
  $output .= drupal_get_form('boincteam_edit_form', $team_id);

  return $output;
}

/**
 * Link to join a team
 */
function boincteam_join_team_panel($team_id) {
  $team = node_load($team_id);
  $output = '';
  $output .= '<h2 class="pane-title">' . bts('Join team', array(), NULL, 'boinc:join-team-panel') . '</h2>';
  $output .= '<p>' . bts('Click here to become a member of @this_team',
    array('@this_team' =>$team->title), NULL, 'boinc:join-team-panel') . '</p>';
  $output .= '<ul class="tab-list">';
  $output .= '  <li class="first last tab">' .
    l(bts('Join this team', array(), NULL, 'boinc:join-team-panel'), "community/teams/{$team_id}/join") . '</li>';
  $output .= '</ul>';
  return $output;
}

/**
 * Link to leave a team
 */
function boincteam_leave_team_panel($team_id) {
  $team = node_load($team_id);
  $output = '';
  $output .= '<h2 class="pane-title">' . bts('Leave team', array(), NULL, 'boinc:leave-team-panel') . '</h2>';
  $output .= '<p>' . bts('Click here to revoke your membership with'
    . ' @this_team', array('@this_team' =>$team->title), NULL, 'boinc:leave-team-panel') . '</p>';
  $output .= '<ul class="tab-list">';
  $output .= '  <li class="first last tab">' .
    l(bts('Leave this team', array(), NULL, 'boinc:leave-team-panel'), "community/teams/{$team_id}/leave") . '</li>';
  $output .= '</ul>';
  return $output;
}

/**
 * General info about team admins
 */
function boincteam_manage_admins_panel_header($team_id) {
  $output = '';
  $output .= '<h4>' . bts('Add team admin', array(), NULL, 'boinc:team-manage-admins') . '</h4>';
  $output .= drupal_get_form('boincteam_add_admin_form', $team_id);
  $output .= '<div class="clearfix"></div>';
  $output .= '<h4>' . bts('Current team admins', array(), NULL, 'boinc:team-manage-admins') . '</h4>';

  return $output;
}

/**
 * Team management tools
 */
function boincteam_management_panel($team_id) {
  $is_founder = boincteam_is_founder($team_id);
  $team = node_load($team_id);

  $output = '';
  $output .= '<h2 class="pane-title">' . bts('Manage team', array(), NULL, 'boinc:team-manage') . '</h2>';

  // PM all members
  if (module_exists('privatemsg')) {
    $output .= '<div class="form-item">';
    $output .= '  <ul class="tab-list action-list">';
    $output .= '    <li class="first tab primary">' .
      l('Send message to team', "community/teams/{$team_id}/message-all-members") . '</li>';
    $output .= '  </ul>';
    $output .= '  <div class="description">';
    $output .=   bts('Contact all team members using e-mail.', array(), NULL, 'boinc:team-manage');
    $output .= '  </div>';
    $output .= '</div>';
  }

  // Team forum
  if (module_exists('boincteam_forum')) {
    if ($is_founder) {
      // Determine whether to create a forum or edit the existing forum
      // (multiple forums per team could be supported in the future)
      $team_forum_link_path = 'add';
      $team_forums = boincteam_forum_list();
      if ($team_forums) {
        $team_forum = reset($team_forums);
        $team_forum_link_path = "{$team_forum->tfid}/edit";
      }
      $output .= '<div class="form-item">';
      $output .= '  <ul class="tab-list action-list">';
      $output .= '    <li class="first tab primary">' .
        l(bts('Manage team message board', array(), NULL, 'boinc:team-manage'),
          "community/teams/{$team_id}/forum/{$team_forum_link_path}"
        );
      $output .= '    </li>';
      $output .= '  <div class="description">';
      $output .=   bts('Create or manage message board', array(), NULL, 'boinc:team-manage');
      $output .= '  </div>';
      $output .= '</div>';
    }
  }

  // Team history
  $output .= '<div class="form-item">';
  $output .= '  <label>' . bts('View change history', array(), NULL, 'boinc:team-manage') . '</label>';
  $output .= '  <ul class="tab-list">';
  $output .= '    <li class="first tab primary">' .
    l('HTML', "community/teams/{$team_id}/history") . '</li>';
  $output .= '    <li class="last tab primary">' .
    l('XML', "community/teams/{$team_id}/history/xml") . '</li>';
  $output .= '  </ul>';
  $output .= '  <div class="description">';
  $output .=   bts('See member activity', array(), NULL, 'boinc:team-manage');
  $output .= '  </div>';
  $output .= '</div>';

  $output .= '<div class="form-item">';
  $output .= '  <ul class="tab-list action-list">';

  // Edit team information
  $output .= '    <li class="first tab primary">' .
    l(bts('Edit team info', array(), NULL, 'boinc:team-manage'), "community/teams/{$team_id}/edit/info") . '</li>';

  // Member list
  $output .= '    <li class="tab primary">' .
    l(bts('View member list', array(), NULL, 'boinc:team-manage'), "community/teams/{$team_id}/members") . '</li>';

  // Remove members
  $output .= '    <li class="tab primary">' .
    l(bts('Remove members', array(), NULL, 'boinc:team-admins-panel'), "community/teams/{$team_id}/edit/members") . '</li>';

  if ($is_founder) {

    // Change founder
    $output .= '    <li class="tab primary">' .
      l(bts('Change founder', array(), NULL, 'boinc:team-manage'), "community/teams/{$team_id}/edit/founder") . '</li>';

      // Manage admins
    $output .= '    <li class="tab primary">' .
      l(bts('Manage team admins', array(), NULL, 'boinc:team-manage'), "community/teams/{$team_id}/edit/admins") . '</li>';

    // Delete the team
    $output .= '    <li class="last tab primary">' .
      l(bts('Remove team', array(), NULL, 'boinc:team-manage'), "community/teams/{$team_id}/delete") . '</li>';
  }

  $output .= '  </ul>';
  $output .= '</div>';

  return $output;
}

/**
 * Link to user's team
 */
function boincteam_member_link_panel() {
  global $user;
  $account = user_load($user->uid);
  $team = node_load($account->team);
  $output = '';
  $output .= '<h2 class="pane-title">' . bts('My team', array(), NULL, 'boinc:account-team-panel') . '</h2>';
  $output .= '<p>' . bts('You are a member of @team.',
    array('@team' => $team->title), NULL, 'boinc:account-team-panel') . '</p>';
  $output .= '<ul class="tab-list">';
  $output .= '  <li class="first last tab">' .
    l(bts('View my team', array(), NULL, 'boinc:account-team-panel'), "community/teams/{$account->team}") . '</li>';
  $output .= '</ul>';
  return $output;
}

/**
 * Link to request foundership transfer of a team
 */
function boincteam_request_foundership_panel($team_id) {
  global $user;
  $account = user_load($user->uid);
  $team = node_load($team_id);
  $boincteam_id = boincteam_lookup_id($team_id);
  $boincteam = boincteam_load($boincteam_id);
  $boincuser_id = $account->boincuser_id;
  $output = '';
  $output .= '<h2 class="pane-title">' . bts('Request foundership', array(), NULL, 'boinc:team-request-foundership') . '</h2>';

  if (boincteam_user_requested_foundership($team_id)) {
    $deadline = boincteam_foundership_transfer_ok_time($boincteam);
    $days_to_deadline = ceil(($deadline - time()) / (24*60*60));
    $request_age = 60 - $days_to_deadline;
    $days_to_respond = 30 + $days_to_deadline;
    if (time() > $deadline) {
      $output .= '<p>';
      if ($request_age == 1) {
        $output .= bts('1 day has elapsed since your request and'
          . ' the founder has not responded.', array(), NULL, 'boinc:team-request-foundership');
      }
      else {
        $output .= bts('@count days have elapsed since your request and'
          . ' the founder has not responded.',
          array('@count' => $request_age),
          NULL, 'boinc:team-request-foundership');
      }
      $output .= ' ';
      if ($days_to_respond == 1) {
        $output .= bts('You now have 1 day to assume foundership before'
          . ' another team member may submit a request.', array(), NULL, 'boinc:team-request-foundership');
      }
      else {
        $output .= bts('You now have @count days to assume foundership before'
          . ' another team member may submit a request.',
          array('@count' => $days_to_respond),
          NULL, 'boinc:team-request-foundership');
      }
      $output .= '</p>';
      $output .= '<ul class="tab-list">';
      $output .= '  <li class="first last tab">' .
        l(bts('Assume foundership', array(), NULL, 'boinc:team-request-foundership'), "community/teams/{$team_id}/assume-foundership") . '</li>';
      $output .= '</ul>';
    }
    else {
      $output .= '<p>';
      if ($days_to_deadline == 1) {
        $output .= bts('The team founder has 1 day to respond to your'
          . ' transfer request.',
          NULL, 'boinc:team-request-foundership');
      }
      else {
        $output .= bts('The team founder has @count days to respond to your'
          . ' transfer request.', array('@count' => $days_to_deadline),
          NULL, 'boinc:team-request-foundership');
      }
      $output .= '</p>';
    }
  }
  elseif (!boincteam_new_foundership_transfer_request_ok($team_id)) {
    // If this user does not have a transfer request pending, but new requests
    // are not allowed, set the deadline to 90 days instead of 60 (as the user
    // who made the request has 30 additional days to assume foundership if
    // there is no response to the request)
    $deadline = boincteam_foundership_transfer_ok_time($boincteam);
    $days_to_deadline = ceil(($deadline - time()) / (24*60*60)) + 30;
    $output .= '<p>';
    $output .= bts('A team foundership change was already requested recently.'
      . ' Only one request is allowed within a period of 90 days.',
      NULL, 'boinc:team-request-foundership');
    if ($days_to_deadline == 1) {
      $output .= ' (' . bts('1 day remaining', array(), NULL, 'boinc:team-request-foundership') . ')';
    }
    else {
      $output .= ' (' . bts('@count days remaining',
        array('@count' => $days_to_deadline),
        NULL, 'boinc:team-request-foundership') . ')';
    }
    $output .= '</p>';
  }
  else {
    $output .= '<p>' . bts('If the team founder is not active and you want to'
      . ' assume the role of founder, click below to request foundership of'
      . ' @this_team.',
      array('@this_team' =>$team->title), NULL, 'boinc:team-request-foundership') . '</p>';
    $output .= '<ul class="tab-list">';
    $output .= '  <li class="first last tab">' .
      l(bts('Initiate request', array(), NULL, 'boinc:team-request-foundership'), "community/teams/{$team_id}/request-foundership") . '</li>';
    $output .= '</ul>';
  }
  return $output;
}

/**
 * Respond to foundership transfer requests for a team
 */
function boincteam_request_foundership_response_panel($team_id) {
  global $user;
  $account = user_load($user->uid);
  $team = node_load($team_id);
  $boincteam_id = boincteam_lookup_id($team_id);
  $boincteam = boincteam_load($boincteam_id);
  $boincuser_id = $account->boincuser_id;
  $output = '';

  if ($boincteam->ping_user) {
    if ($boincteam->ping_user < 0) {
      $member = user_load(boincuser_lookup_uid(-$boincteam->ping_user));
      $output .= '<h2 class="pane-title">' . bts('Obsolete transfer request', array(), NULL, 'boinc:team-request-foundership-response')
        . '</h2>';
      $output .= '<p>' . bts('Team member @name requested team foundership on'
        . ' @date, but then left the team. This request is now canceled.',
        array(
          '@name' => $member->boincuser_name,
          '@date' => date('j M Y', $boincteam->ping_time),
        ),
        NULL, 'boinc:team-request-foundership-response') . '</p>';
      // Automatically cancel the request
      db_set_active('boinc_rw');
      db_query("
        UPDATE {team}
        SET ping_user=0
        WHERE id = '%d'",
        $boincteam_id
      );
      db_set_active('default');
    }
    else {
      $member = user_load(boincuser_lookup_uid($boincteam->ping_user));
      $output .= '<h2 class="pane-title">' . bts('Respond to transfer request', array(), NULL, 'boinc:team-request-foundership-response')
        . '</h2>';
      $output .= '<p>' . bts('Team member @name has requested team foundership.'
        . ' This may be because you left the team or have not had contact with'
        . ' the team for a long time.', array(
          '@name' => $member->boincuser_name,
        )
      , array(), NULL, 'boinc:team-request-foundership-response') . '</p>';
      $output .= '<p>' . bts("If you don't decline the request by @date, @name"
        . ' will have the option of assuming team foundership. (note: To'
        . ' accept the request, assign foundership to @name using the form'
        . ' below)',
        array(
          '@name' => $member->boincuser_name,
          '@date' => date('j M Y', boincteam_foundership_transfer_ok_time($boincteam)),
        ),
        NULL, 'boinc:team-request-foundership-response') . '</p>';
      $output .= '<ul class="tab-list">';
      $output .= '  <li class="first last tab">' .
        l(bts('Deny request', array(), NULL, 'boinc:team-request-foundership-response'), "community/teams/{$team_id}/deny-foundership-request") . '</li>';
      $output .= '</ul>';
    }
  }
  return $output;
}

function boincteam_search_panel() {
  $output = '';
  if (module_exists('global_search_teams_solr')) {
    $output .= '<h2 class="pane-title">' . bts('Search teams', array(), NULL, 'boinc:search-team') . '</h2>';
    //$output .= '<p>' . bts('Render a search form here.', array(), NULL, 'boinc:search-team') . '</p>';
    $output .= '<p>' . boincteam_search_view() . '</p>';
  }
  return $output;
}

function boincteam_search_view($type = 'team') {
  // Get the team search form
  $search_page = apachesolr_search_page_load('team_search');
  module_load_include('inc', 'apachesolr_search', 'apachesolr_search.pages');
  return drupal_get_form('apachesolr_search_custom_page_search_form', $search_page);
}

/**
 * General info about the concept of teams
 */
function boincteam_topic_overview_panel() {
  $site_name =  variable_get('site_name', 'Drupal-BOINC');
  $output = '';
  $output .= '<h2 class="pane-title">' . bts('Teams', array(), NULL, 'boinc:team-general-info') . '</h2>';
  $output .= '<div class="">';
  $output .= '<p>' . bts('@project participants may form teams. You may belong'
    . ' to only one team. You can join or quit a team at any time. To join a'
    . ' team, visit its team page and click "Join this team". Each team has a'
    . ' founder who may:', array('@project' => $site_name), NULL, 'boinc:team-general-info') . '</p>';
  $output .= '<ul>';
  $output .= '  <li>' . bts('Private Message all team members', array(), NULL, 'boinc:team-general-info') . '</li>';
  $output .= '  <li>' . bts("edit the team's name and description", array(), NULL, 'boinc:team-general-info') . '</li>';
  $output .= '  <li>' . bts('add or remove team admins', array(), NULL, 'boinc:team-general-info') . '</li>';
  $output .= '  <li>' . bts('remove members from the team', array(), NULL, 'boinc:team-general-info') . '</li>';
  $output .= '  <li>' . bts('disband a team if it has no members', array(), NULL, 'boinc:team-general-info') . '</li>';
  $output .= '</ul>';
  $output .= '</div>';
  return $output;
}

/**
 * Link to view the member list for a team
 *//*
function boincteam_view_member_list_panel($team_id) {
  $team = boincteam_load(boincteam_lookup_id($team_id), TRUE);
  $founder = user_load(get_drupal_id($team->userid));
  $new_members = array();
  if ($team->new_members) {
    foreach ($team->new_members as $member) {
      $account = user_load(get_drupal_id($member->id));
      $new_members[] = l($account->boincuser_name, "account/{$account->uid}");
    }
  }
  $output = '';
  $output .= '<h2 class="pane-title">' . $team->name . '</h2>';
  $output .= '<div>' . l($team->name, "community/teams/{$team_id}") . '</div>';
  $output .= '<div>';
  $output .= '</div>';
  return $output;
}*/

/**
 * Link to view a team
 */
function boincteam_view_team_panel($team_id) {
  $team = node_load($team_id);
  if ($team->type != "team") {
    return;
  }
  $boincteam = boincteam_load(boincteam_lookup_id($team_id), TRUE);
  $founder = user_load(get_drupal_id($boincteam->userid));
  $new_members = array();
  if ($boincteam->new_members) {
    foreach ($boincteam->new_members as $member) {
      $account = user_load(get_drupal_id($member->id));
      $new_members[] = l($account->boincuser_name, "account/{$account->uid}");
    }
  }
  $output = '';
  $output .= '<h2 class="pane-title">' . $boincteam->name . '</h2>';
  $output .= '<div>';
  $output .= '<div class="left-column">';
  $output .= '<ul class="stats">';
  $output .= '  <li>' . bts('Total credit', array(), NULL, 'boinc:user-or-team-total-credits') . ': ' . number_format($boincteam->total_credit, 0) . '</li>';
  $output .= '  <li>' . bts('Recent average credit', array(), NULL, 'boinc:user-or-team-RAC') . ': ' . number_format($boincteam->expavg_credit, 2) . '</li>';
  $output .= '  <li>' . bts('Country', array(), NULL, 'boinc:country-of-origin') . ': ' . $boincteam->country . '</li>';
  $output .= '  <li>' . bts('Type', array(), NULL, 'boinc:view-team-info') . ': ' . boincteam_get_type($team_id) . '</li>';
  $output .= '</ul>';
  $output .= '</div>';
  $output .= '<div class="right-column">';
  $output .= '<ul class="stats">';
  $output .= '  <li>' . bts('Founder', array(), NULL, 'boinc:view-team-info') . ': ' . l($founder->boincuser_name, "account/{$founder->uid}") . '</li>';
  $output .= '  <li>' . bts('New members in last day', array(), NULL, 'boinc:view-team-info') . ': ' . implode('&middot;', $new_members) . '</li>';
  $output .= '  <li>' . bts('Total members', array(), NULL, 'boinc:view-team-info') . ': ' . l($boincteam->nusers, "community/teams/{$team_id}/members") . '</li>';
  $output .= '  <li>' . bts('Active members', array(), NULL, 'boinc:view-team-info') . ': ' . $boincteam->nusers_active . '</li>';
  $output .= '  <li>' . bts('Members with credit', array(), NULL, 'boinc:view-team-info') . ': ' . $boincteam->nusers_worked . '</li>';
  $output .= '</ul>';
  $output .= '</div>';
  $output .= '</div>';
  $output .= '<div class="clearfix"></div>';
  if ($boincteam->url) {
    $output .= '<div class="stats">';
    $output .= bts('Website', array(), NULL, 'boinc:website-of-user-or-team') . ': ' . l("http://{$boincteam->url}", "http://{$boincteam->url}");
    $output .= '</div>';
  }
  if ($team->body) {
    $output .= '<h3>' . bts('Description', array(), NULL, 'boinc:team-description') . '</h3>';
    $output .= check_markup($team->body, $team->format);
    $output .= '</div>';
  }
  return $output;
}
