<?php /*

 Composr
 Copyright (c) Christopher Graham, 2004-2024

 See docs/LICENSE.md for full licensing 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  Christopher Graham
 * @package    leader_board
 */

/**
 * Block class.
 */
class Block_main_leader_board
{
    /**
     * Find details of the block.
     *
     * @return ?array Map of block info (null: block is disabled)
     */
    public function info() : ?array
    {
        $info = [];
        $info['author'] = 'Chris Graham';
        $info['organisation'] = 'Composr';
        $info['hacked_by'] = null;
        $info['hack_version'] = null;
        $info['version'] = 4;
        $info['locked'] = false;
        $info['min_cms_version'] = 11.0;
        $info['addon'] = 'leader_board';
        $info['parameters'] = ['zone', 'param', 'timestamp'];
        $info['update_require_upgrade'] = true;
        return $info;
    }

    /**
     * Uninstall the module.
     */
    public function uninstall()
    {
        $tables = [
            'leader_board',
            'leader_boards',
            'leader_boards_groups',
        ];
        $GLOBALS['SITE_DB']->drop_table_if_exists($tables);
    }

    /**
     * Install the module.
     *
     * @param  ?integer $upgrade_from What version we're upgrading from (null: new install)
     * @param  ?integer $upgrade_from_hack What hack version we're upgrading from (null: new-install/not-upgrading-from-a-hacked-version)
     */
    public function install(?int $upgrade_from = null, ?int $upgrade_from_hack = null)
    {
        if ($upgrade_from === null) {
            $GLOBALS['SITE_DB']->create_table('leader_board', [
                'lb_leader_board_id' => '*AUTO_LINK',
                'lb_member' => '*MEMBER',
                'lb_date_and_time' => '*TIME',
                'lb_points' => 'INTEGER',
                'lb_rank' => 'INTEGER',
                'lb_voting_power' => '?REAL',
                'lb_voting_control' => '?REAL',
            ]);
        }

        if (($upgrade_from === null) || $upgrade_from < 4) {
            $GLOBALS['SITE_DB']->create_table('leader_boards', [
                'id' => '*AUTO',
                'lb_title' => 'SHORT_TEXT',
                'lb_creation_date_and_time' => 'TIME',
                'lb_type' => 'SHORT_TEXT',
                'lb_member_count' => 'INTEGER',
                'lb_timeframe' => 'SHORT_TEXT',
                'lb_rolling' => 'BINARY',
                'lb_include_staff' => 'BINARY',
                'lb_calculate_voting_power' => 'BINARY',
            ]);

            $GLOBALS['SITE_DB']->create_table('leader_boards_groups', [
                'lb_leader_board_id' => '*AUTO_LINK',
                'lb_group' => '*GROUP',
            ]);
        }
        if (($upgrade_from !== null) && $upgrade_from < 4) { // LEGACY
            $GLOBALS['SITE_DB']->add_table_field('leader_board', 'lb_rank', 'INTEGER');

            // Create legacy leader-board and a new field will reference it
            require_lang('leader_board');
            require_code('leader_board2');
            $new_leader_board = add_leader_board(do_lang('POINT_LEADER_BOARD'), 'holders', 10, 'week', 1, 0, null, 0);
            $GLOBALS['SITE_DB']->add_table_field('leader_board', 'lb_leader_board_id', '*AUTO_LINK', $new_leader_board);

            // Calculate rankings for legacy result sets
            $dates = $GLOBALS['SITE_DB']->query('SELECT DISTINCT date_and_time FROM ' . get_table_prefix() . 'leader_board');
            foreach ($dates as $date) {
                $rows = $GLOBALS['SITE_DB']->query_select('leader_board', ['*'], ['date_and_time' => $date['date_and_time']]);

                sort_maps_by($rows, '!lb_points');

                $i = 0;
                foreach ($rows as $row) {
                    $i++;
                    $GLOBALS['SITE_DB']->query_update('leader_board', ['lb_rank' => $i], ['lb_member' => $row['lb_member'], 'date_and_time' => $date['date_and_time']], '', 1);
                }
            }

            // Consistency re-naming
            $GLOBALS['SITE_DB']->alter_table_field('leader_board', 'date_and_time', '*TIME', 'lb_date_and_time');
            $GLOBALS['SITE_DB']->change_primary_key('leader_board', ['lb_leader_board_id', 'lb_member', 'lb_date_and_time']);

            // Voting power support
            $GLOBALS['SITE_DB']->add_table_field('leader_board', 'lb_voting_power', '?REAL');
            $GLOBALS['SITE_DB']->add_table_field('leader_board', 'lb_voting_control', '?REAL');
        }

        if (($upgrade_from === null) || $upgrade_from < 4) {
            // Add indexes
            $GLOBALS['SITE_DB']->create_index('leader_board', 'lb_leader_board_id', ['lb_leader_board_id']);
            $GLOBALS['SITE_DB']->create_index('leader_board', 'lb_date_and_time', ['lb_date_and_time']);
            $GLOBALS['SITE_DB']->create_index('leader_board', 'lb_rank', ['lb_leader_board_id', 'lb_date_and_time', 'lb_rank']);
        }
    }

    /**
     * Find caching details for the block.
     *
     * @return ?array Map of cache details (cache_on and ttl) (null: block is disabled)
     */
    public function caching_environment() : ?array
    {
        $info = [];
        $info['cache_on'] = <<<'PHP'
        [
            array_key_exists('zone', $map) ? $map['zone'] : get_module_zone('leader_board'),
            array_key_exists('param', $map) ? $map['param'] : null,
            array_key_exists('timestamp', $map) ? $map['timestamp'] : null,
        ]
PHP;
        $info['ttl'] = 60 * 15; // 15 minutes
        return $info;
    }

    /**
     * Execute the block.
     *
     * @param  array $map A map of parameters
     * @return Tempcode The result of execution
     */
    public function run(array $map) : object
    {
        $error_msg = new Tempcode();
        if (!addon_installed__messaged('leader_board', $error_msg)) {
            return $error_msg;
        }
        if (!addon_installed__messaged('points', $error_msg)) {
            return $error_msg;
        }

        if (!cron_installed()) {
            return do_template('RED_ALERT', ['_GUID' => 'a2a0d9ca06605ebcbf98d8597a73d053', 'TEXT' => do_lang_tempcode('CRON_NEEDED_TO_WORK', escape_html(get_tutorial_url('tut_configuration')))]);
        }

        require_lang('leader_board');
        require_code('leader_board');
        require_css('leader_board');
        require_code('points');

        if (!array_key_exists('param', $map)) { // Get the first leader-board if none defined
            $boards = $GLOBALS['SITE_DB']->query_select('leader_boards', ['*'], [], 'ORDER BY id', 1);
        } else {
            $boards = $GLOBALS['SITE_DB']->query_select('leader_boards', ['*'], ['id' => intval($map['param'])], '', 1);
        }

        if (empty($boards)) {
            // Only error on a leader-board not existing if we explicitly requested one; otherwise just return blank
            if (array_key_exists('param', $map)) {
                return do_template('RED_ALERT', ['_GUID' => '4c1a7f62c19ac80998fa1634454317bc', 'TEXT' => do_lang_tempcode('MISSING_RESOURCE', 'leader_board')]);
            }
            return new Tempcode();
        }

        $board = $boards[0];
        $leader_board_id = $board['id'];

        $zone = array_key_exists('zone', $map) ? $map['zone'] : get_module_zone('leader_board');

        $rows = get_leader_board($leader_board_id, array_key_exists('timestamp', $map) ? intval($map['timestamp']) : null);
        if (empty($rows)) {
            return do_template('RED_ALERT', ['_GUID' => '21e220f0b11a3a1fd278d3ff8452b2d6', 'TEXT' => do_lang_tempcode('LEADER_BOARD_NOT_GENERATED', escape_html($board['lb_title']))]);
        }

        $date = $rows[0]['lb_date_and_time'];
        $nice_date = get_timezoned_date($date, false);
        $start_date = strtotime('-1 ' . $board['lb_timeframe'], $date);
        $nice_start_date = get_timezoned_date($start_date, false);

        $out = new Tempcode();
        $i = 0;

        // Are there any rank images going to display?
        $or_list = '1=1';
        $admin_groups = $GLOBALS['FORUM_DRIVER']->get_super_admin_groups();
        $moderator_groups = $GLOBALS['FORUM_DRIVER']->get_moderator_groups();
        foreach (array_merge($admin_groups, $moderator_groups) as $group_id) {
            $or_list .= ' AND id<>' . strval($group_id);
        }
        $has_rank_images = (get_forum_type() == 'cns') && ($GLOBALS['FORUM_DB']->query_value_if_there('SELECT COUNT(*) FROM ' . $GLOBALS['FORUM_DB']->get_table_prefix() . 'f_groups WHERE (' . $or_list . ') AND ' . db_string_not_equal_to('g_rank_image', '')) != 0);

        foreach ($rows as $row) {
            $points_url = points_url($row['lb_member']);

            $profile_url = $GLOBALS['FORUM_DRIVER']->member_profile_url($row['lb_member'], true);

            $username = $GLOBALS['FORUM_DRIVER']->get_username($row['lb_member'], false, USERNAME_DEFAULT_DELETED);

            if (addon_installed('cns_forum')) {
                require_lang('cns_polls');
                $voting_power = $row['lb_voting_power'];
                $voting_control = $row['lb_voting_control'];
            } else {
                $voting_power = null;
                $voting_control = null;
            }

            $out->attach(do_template('POINTS_LEADER_BOARD_ROW', [
                '_GUID' => '8e37bbbf7df05544997ac27767bb7b79',
                'ID' => strval($row['lb_member']),
                'POINTS_URL' => $points_url,
                'PROFILE_URL' => $profile_url,
                '_POINTS' => strval($row['lb_points']),
                'POINTS' => integer_format($row['lb_points']),
                '_VOTING_POWER' => (($voting_power !== null) ? float_to_raw_string($voting_power, 10) : ''),
                'VOTING_POWER' => (($voting_power !== null) ? float_format($voting_power, 3) : ''),
                '_VOTING_CONTROL' => (($voting_control !== null) ? float_to_raw_string($voting_control, 10) : ''),
                'VOTING_CONTROL' => (($voting_control !== null) ? float_format($voting_control, 3) : ''),
                'USERNAME' => $username,
                'HAS_RANK_IMAGES' => $has_rank_images,
            ]));

            $i++;
        }

        $about = ($board['lb_type'] == 'earners') ? do_lang_tempcode('LEADER_BOARD_ABOUT_earners', integer_format(count($rows)), escape_html($nice_start_date), escape_html($nice_date)) : do_lang_tempcode('LEADER_BOARD_ABOUT_holders', integer_format(count($rows)), escape_html($nice_date));

        $url = build_url(['page' => 'leader_board', 'id' => $leader_board_id], $zone);

        return do_template('POINTS_LEADER_BOARD_SET', [
            '_GUID' => '6ad2990c8440500681a402fe4fdf3916',
            '_SET_NUMBER' => strval(count($rows)),
            '_TYPE' => $board['lb_type'],
            '_COUNT' => strval(count($rows)),
            '_DATE' => $date,
            '_START_DATE' => $start_date,
            'URL' => $url,
            'TITLE' => $board['lb_title'],
            'ABOUT' => $about,
            'ROWS' => $out,
            'IS_BLOCK' => true
        ]);
    }
}
