<?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    core_adminzone_dashboard
 */

/**
 * Block class.
 */
class Block_main_staff_checklist
{
    /**
     * 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'] = 5;
        $info['locked'] = false;
        $info['min_cms_version'] = 11.0;
        $info['addon'] = 'core_adminzone_dashboard';
        $info['update_require_upgrade'] = true;
        $info['parameters'] = [];

        return $info;
    }

    /**
     * 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 = [];
        // No cache on POST as this is when we save text data
        $info['cache_on'] = <<<'PHP'
        (count($_POST) > 0)
        ?
        null
        :
        [
        ]
PHP;
        $info['ttl'] = 10; // Needs to be short given due times
        return $info;
    }

    /**
     * Uninstall the block.
     */
    public function uninstall()
    {
        $GLOBALS['SITE_DB']->drop_table_if_exists('staff_checklist_cus_tasks');
    }

    /**
     * Install the block.
     *
     * @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) || ($upgrade_from < 4)) {
            $GLOBALS['SITE_DB']->create_table('staff_checklist_cus_tasks', [
                'id' => '*AUTO',
                'task_title' => 'LONG_TEXT',
                'add_date' => 'TIME',
                'recur_interval' => 'INTEGER',
                'recur_every' => 'ID_TEXT',
                'done_time' => '?TIME',
            ]);

            require_lang('staff_checklist');
            $tasks = [
                do_lang('CHECKLIST_INITIAL_TASK_CONTENT'),
                '[url="' . do_lang('CHECKLIST_INITIAL_TASK_UPTIME_MONITOR') . '"]https://uptimerobot.com/[/url]',
                (brand_name() == 'Composr') ? '[page="adminzone:admin_version"]Consider contributing to the Composr project[/page]' : '',
            ];
            foreach ($tasks as $task) {
                $GLOBALS['SITE_DB']->query_insert('staff_checklist_cus_tasks', [
                    'task_title' => $task,
                    'add_date' => time(),
                    'recur_interval' => 0,
                    'recur_every' => '',
                    'done_time' => null,
                ]);
            }
        }

        if (($upgrade_from !== null) && ($upgrade_from < 5)) { // LEGACY: 11.beta1
            // Database consistency fixes
            $GLOBALS['SITE_DB']->alter_table_field('staff_checklist_cus_tasks', 'task_is_done', '?TIME', 'done_time');
        }
    }

    /**
     * Execute the block.
     *
     * @param  array $map A map of parameters
     * @return Tempcode The result of execution
     */
    public function run(array $map) : object
    {
        require_lang('dates');
        require_lang('staff_checklist');
        require_css('adminzone_dashboard');

        $block_id = get_block_id($map);

        // Handle custom tasks
        $new_task = post_param_string('new_task', null);
        $recur_interval = post_param_integer('recur_interval', 0);
        $recur_every = post_param_string('recur_every', null);
        if (($new_task !== null) && ($recur_interval !== null) && ($recur_every !== null)) {
            $GLOBALS['SITE_DB']->query_insert('staff_checklist_cus_tasks', ['task_title' => $new_task, 'add_date' => time(), 'recur_interval' => $recur_interval, 'recur_every' => $recur_every, 'done_time' => null]);
            delete_cache_entry('main_staff_checklist');
        }
        $custom_tasks = new Tempcode();
        $rows = $GLOBALS['SITE_DB']->query_select('staff_checklist_cus_tasks', ['*']);
        foreach ($rows as $r) {
            $recur_every = '';
            switch ($r['recur_every']) {
                case 'mins':
                    $recur_every = do_lang('DPLU_MINUTES');
                    break;
                case 'hours':
                    $recur_every = do_lang('DPLU_HOURS');
                    break;
                case 'days':
                    $recur_every = do_lang('DPLU_DAYS');
                    break;
                case 'months':
                    $recur_every = do_lang('DPLU_MONTHS');
                    break;
            }
            $custom_tasks->attach(do_template('BLOCK_MAIN_STAFF_CHECKLIST_CUSTOM_TASK', [
                '_GUID' => 'fa747347ad7b9eb1a7f3f54867154db4',
                'TASK_TITLE' => comcode_to_tempcode($r['task_title']),
                'ADD_DATE' => display_time_period($r['add_date']),
                'ADD_TIME' => do_lang_tempcode('_AGO', do_lang_tempcode('DAYS', escape_html(integer_format(intval(round(floatval(time() - $r['add_date']) / 60.0 / 60.0 / 24.0)))))),
                'RECUR_INTERVAL' => ($r['recur_interval'] == 0) ? '' : integer_format($r['recur_interval']),
                'RECUR_EVERY' => $recur_every,
                'TASK_DONE' => (($r['done_time'] !== null) && (($r['recur_interval'] == 0) || (($r['recur_every'] != 'mins') || (time() < $r['done_time'] + 60 * $r['recur_interval'])) && (($r['recur_every'] != 'hours') || (time() < $r['done_time'] + 60 * 60 * $r['recur_interval'])) && (($r['recur_every'] != 'days') || (time() < $r['done_time'] + 24 * 60 * 60 * $r['recur_interval'])) && (($r['recur_every'] != 'months') || (time() < $r['done_time'] + 31 * 24 * 60 * 60 * $r['recur_interval'])))) ? 'checklist_done' : 'checklist_todo',
                'ID' => strval($r['id']),
            ]));
        }

        // Handle built-in items

        $rets_no_times = [];
        $rets_todo_counts = [];
        $rets_dates = [];

        $_hooks = find_all_hook_obs('blocks', 'main_staff_checklist', 'Hook_checklist_');
        ksort($_hooks);
        foreach ($_hooks as $object) {
            $ret = $object->run();
            if (($ret !== null) && (!empty($ret))) {
                foreach ($ret as $r) {
                    if (($r[1] === null) && ($r[2] === null)) {
                        $rets_no_times[] = $r;
                    } elseif ($r[2] !== null) {
                        $rets_todo_counts[] = $r;
                    } else {
                        $rets_dates[] = $r;
                    }
                }
            }
        }

        sort_maps_by($rets_todo_counts, '!2');
        sort_maps_by($rets_dates, '1');

        $out_no_times = new Tempcode();
        foreach ($rets_no_times as $item) {
            $out_no_times->attach($item[0]);
        }
        $out_todo_counts = new Tempcode();
        foreach ($rets_todo_counts as $item) {
            $out_todo_counts->attach($item[0]);
        }
        $out_dates = new Tempcode();
        foreach ($rets_dates as $item) {
            $out_dates->attach($item[0]);
        }

        return do_template('BLOCK_MAIN_STAFF_CHECKLIST', [
            '_GUID' => 'aefbca8252dc1d6edc44fc6d1e78b3ec',
            'BLOCK_ID' => $block_id,
            'URL' => get_self_url(),
            'DATES' => $out_dates,
            'NO_TIMES' => $out_no_times,
            'TODO_COUNTS' => $out_todo_counts,
            'CUSTOM_TASKS' => $custom_tasks,
        ]);
    }
}

/**
 * Work out when an action should happen, and last happened.
 *
 * @param  ?integer $seconds_ago The number of seconds ago since it last happened (null: never happened) OR If $recur_hours is null then the number of seconds until it happens (null: won't happen)
 * @param  ?integer $recur_hours It should be done every this many hours (null: never happened)
 * @return array A pair: Tempcode to display, and the number of seconds to go until the action should happen
 */
function staff_checklist_time_ago_and_due(?int $seconds_ago, ?int $recur_hours = null) : array
{
    if ($recur_hours === null) { // None recurring
        $seconds_to_go = $seconds_ago; // Actually, if only one parameter given, meaning is different
        $seconds_ago = null;
        if ($seconds_to_go === null) {
            return [do_lang_tempcode('DUE_NOT'), 1000000];
        }
    } else { // Recurring
        if ($seconds_ago === null) {
            return [do_lang_tempcode('DUE_NOW'), 0]; // Due for first time now
        } else {
            $seconds_to_go = $recur_hours * 60 * 60 - $seconds_ago;
        }
    }

    if ($seconds_to_go == 0) {
        return [do_lang_tempcode('DUE_NOW'), 0]; // Due for first time now (this is a special encoding for non-recurring tasks that still need doing on some form of schedule and need doing for first time now)
    }
    if ($seconds_to_go > 0) {
        return [do_lang_tempcode('DUE_TIME', ($seconds_ago === null) ? do_lang_tempcode('NA_EM') : make_string_tempcode(escape_html(display_time_period($seconds_ago))), make_string_tempcode(escape_html(display_time_period($seconds_to_go)))), $seconds_to_go];
    }
    return [do_lang_tempcode('DUE_TIME_AGO', ($seconds_ago === null) ? do_lang_tempcode('NA_EM') : make_string_tempcode(escape_html(display_time_period($seconds_ago))), make_string_tempcode(escape_html(display_time_period(-$seconds_to_go)))), $seconds_to_go];
}
