<?php /*

 Composr
 Copyright (c) ocProducts, 2004-2016

 See text/EN/licence.txt for full licencing information.


 NOTE TO PROGRAMMERS:
   Do not edit this file. If you need to make changes, save your changed file to the appropriate *_custom folder
   **** If you ignore this advice, then your website upgrades (e.g. for bug fixes) will likely kill your changes ****

*/

/**
 * @license    http://opensource.org/licenses/cpal_1.0 Common Public Attribution License
 * @copyright  ocProducts Ltd
 * @package    points
 */

/**
 * See if a leader-board has been calculated since a particular cut-off time.
 *
 * @param  TIME $cutoff Cut-off time
 * @return boolean Whether it has
 */
function has_leader_board_since($cutoff)
{
    $test = $GLOBALS['SITE_DB']->query_value_if_there('SELECT COUNT(*) FROM ' . get_table_prefix() . 'leader_board WHERE date_and_time>=' . strval($cutoff));
    return ($test > 0);
}

/**
 * Calculate the leader-board.
 *
 * @param  boolean $retrieve Whether to retrieve results too (no retrieve -> faster call)
 * @return ?array A map of member-IDs to points, sorted by leader-board status (null: not retrieving)
 */
function calculate_latest_leader_board($retrieve = true)
{
    // Already has?
    $cutoff = time() - 60 * 60 * 24 * 7;
    if (has_leader_board_since($cutoff)) {
        if (!$retrieve) {
            return null;
        }

        $rows = $GLOBALS['SITE_DB']->query('SELECT lb_member,lb_points FROM ' . get_table_prefix() . 'leader_board WHERE date_and_time>=' . strval($cutoff));
        $rows = collapse_2d_complexity('lb_member', 'lb_points', $rows);
        arsort($rows);
        return $rows;
    }

    // Calculate

    $limit = intval(get_option('leader_board_size')); // The number to show on the leader-board
    $show_staff = (get_option('leader_board_show_staff') == '1'); // Whether to include staff

    $limit_hack = max(300, $limit); // We'll query more top posters than we'll display, so that we workaround the issue that our initial efficient querying by top post count is not the same as querying by top point count (we'll hope that they align close enough for nobody to notice!)
    $all_members = $GLOBALS['FORUM_DRIVER']->get_top_posters($limit_hack);
    $points = array();

    foreach ($all_members as $member) {
        $id = $GLOBALS['FORUM_DRIVER']->mrow_id($member);

        if (is_guest($id)) {
            continue; // Should not happen, but some forum drivers might suck ;)
        }
        if ((!$show_staff) && ($GLOBALS['FORUM_DRIVER']->is_staff($id))) {
            continue;
        }

        $points[$id] = total_points($id);
    }

    arsort($points);

    $rows = array();

    $i = 0;
    $time = time();
    foreach ($points as $id => $num_points) {
        $username = $GLOBALS['FORUM_DRIVER']->get_username($id);
        if ($username === null) {
            continue;
        }

        if ($i == 0) {
            set_value('site_bestmember', $username);
        }

        if ($i >= $limit) {
            break;
        }

        $row = array('lb_member' => $id, 'lb_points' => $num_points, 'date_and_time' => $time);
        $GLOBALS['SITE_DB']->query_insert('leader_board', $row, false, true); // Allow failure due to race conditions

        $i++;
    }

    if (!$retrieve) {
        return null;
    }

    return $rows;
}
