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

/**
 * Module page class.
 */
class Module_topicview
{
    public $title;
    public $breadcrumbs;
    public $id;
    public $forum_id;
    public $type;
    public $topic_info;
    public $posts;
    public $serialized_options;
    public $hash;
    public $may_reply;
    public $start;
    public $default_max;
    public $max;
    public $threaded_topic_ob;

    /**
     * Find details of the module.
     *
     * @return ?array Map of module info (null: module is disabled).
     */
    public function info()
    {
        $info = array();
        $info['author'] = 'Chris Graham';
        $info['organisation'] = 'ocProducts';
        $info['hacked_by'] = null;
        $info['hack_version'] = null;
        $info['version'] = 2;
        $info['locked'] = false;
        return $info;
    }

    /**
     * Find entry-points available within this module.
     *
     * @param  boolean $check_perms Whether to check permissions.
     * @param  ?MEMBER $member_id The member to check permissions as (null: current user).
     * @param  boolean $support_crosslinks Whether to allow cross links to other modules (identifiable via a full-page-link rather than a screen-name).
     * @param  boolean $be_deferential Whether to avoid any entry-point (or even return null to disable the page in the Sitemap) if we know another module, or page_group, is going to link to that entry-point. Note that "!" and "browse" entry points are automatically merged with container page nodes (likely called by page-groupings) as appropriate.
     * @return ?array A map of entry points (screen-name=>language-code/string or screen-name=>[language-code/string, icon-theme-image]) (null: disabled).
     */
    public function get_entry_points($check_perms = true, $member_id = null, $support_crosslinks = true, $be_deferential = false)
    {
        if (get_forum_type() != 'cns') {
            return null;
        }
        if ($be_deferential) {
            return array();
        }
        if ($check_perms && is_guest($member_id)) {
            return array();
        }

        return array('!' => array('INLINE_PERSONAL_POSTS', 'menu/social/forum/inline_personal_posts'));
    }

    /**
     * Module pre-run function. Allows us to know metadata for <head> before we start streaming output.
     *
     * @return ?Tempcode Tempcode indicating some kind of exceptional output (null: none).
     */
    public function pre_run()
    {
        if (get_forum_type() != 'cns') {
            warn_exit(do_lang_tempcode('NO_CNS'));
        } else {
            cns_require_all_forum_stuff();
        }
        require_code('cns_topicview');

        $type = get_param_string('type', 'browse');

        require_lang('cns');

        $id = get_param_integer('id', null);
        if ((is_guest()) && (is_null($id))) {
            access_denied('NOT_AS_GUEST');
        }

        if (!is_null($id)) {
            $notification_where_map = array('d_notification_code' => 'cns_topic', 'd_code_category' => strval($id), 'd_to_member_id' => get_member(), 'd_read' => 0);
            $notification_ids = $GLOBALS['SITE_DB']->query_select('digestives_tin', array('id'), $notification_where_map);
            if ($notification_ids !== array()) {
                foreach ($notification_ids as $notification_id) {
                    $GLOBALS['SITE_DB']->query_update('digestives_tin', array('d_read' => 1), array('id' => $notification_id['id']));
                }
                decache('_get_notifications', null, get_member());
            }
        }

        if ($type == 'findpost') {
            $post_id = get_param_integer('id');
            $redirect = find_post_id_url($post_id);
            return redirect_screen(get_screen_title('VIEW_TOPIC'), $redirect);
        } elseif ($type == 'first_unread') {
            $redirect = find_first_unread_url($id);
            return redirect_screen(get_screen_title('VIEW_TOPIC'), $redirect);
        }

        $start = get_param_integer('topic_start', 0);
        $default_max = intval(get_option('forum_posts_per_page'));
        $max = get_param_integer('topic_max', $default_max);
        if ($max == 0) {
            $max = $default_max;
        }
        if ($max == 0) {
            $max = 1;
        }
        if (($max > 30) && (!has_privilege(get_member(), 'remove_page_split'))) {
            $max = $default_max;
        }

        $view_poll_results = get_param_integer('view_poll_results', 0);

        $topic_info = cns_read_in_topic($id, $start, $max, $view_poll_results == 1);

        $may_reply = array_key_exists('may_reply', $topic_info);

        inform_non_canonical_parameter('threaded');
        inform_non_canonical_parameter('post_id');
        inform_non_canonical_parameter('#^kfs.*$#');

        if (!is_null($id)) {
            set_extra_request_metadata($topic_info['metadata'], $topic_info['row'], 'topic', strval($id));
        }

        global $SEO_TITLE;
        $SEO_TITLE = do_lang('_VIEW_TOPIC', $topic_info['title']);

        if (!is_null($id)) {
            set_feed_url('?mode=cns_topicview&select=' . strval($id));
        }

        if (is_null($id)) { // Just inline personal posts
            $title = get_screen_title('INLINE_PERSONAL_POSTS');
        } else {
            if (is_null($topic_info['forum_id'])) {
                $title = get_screen_title(do_lang_tempcode('NAMED_PRIVATE_TOPIC', escape_html($topic_info['title'])), false, null, do_lang_tempcode('READING_PRIVATE_TOPIC'));
            } else {
                if ((get_value('no_awards_in_titles') !== '1') && (addon_installed('awards'))) {
                    require_code('awards');
                    $awards = find_awards_for('topic', strval($id));
                } else {
                    $awards = array();
                }

                $title = get_screen_title(do_lang_tempcode('NAMED_TOPIC', make_fractionable_editable('topic', $id, $topic_info['title'])), false, null, null, $awards);
            }
        }

        // Forum breadcrumbs
        if (!is_null($topic_info['forum_id'])) {
            $breadcrumbs = cns_forum_breadcrumbs($topic_info['forum_id'], null, null, false);
        } else {
            $breadcrumbs = array();
            $breadcrumbs[] = array(build_page_link(array('page' => 'members'), get_module_zone('members')), do_lang_tempcode('MEMBERS'));
            if (has_privilege(get_member(), 'view_other_pt')) {
                $of_member = ($topic_info['pt_from'] == get_member()) ? $topic_info['pt_from'] : $topic_info['pt_to'];
            } else {
                $of_member = get_member();
            }
            $of_username = $GLOBALS['FORUM_DRIVER']->get_username($of_member, true);
            if (is_null($of_username)) {
                $of_username = do_lang('UNKNOWN');
            }
            $private_topic_page_link = build_page_link(array('page' => 'members', 'type' => 'view', 'id' => $of_member), get_module_zone('members'), null, 'tab__pts');
            $breadcrumbs[] = array($private_topic_page_link, do_lang_tempcode('MEMBER_ACCOUNT', escape_html($of_username)));
        }

        if (!is_null($id)) {
            $breadcrumbs[] = array('', do_lang_tempcode(is_null($topic_info['forum_id']) ? 'VIEW_PRIVATE_TOPIC' : 'VIEW_TOPIC'));
            breadcrumb_set_parents($breadcrumbs);
        }

        if (is_null($id)) { // Just inline personal posts
            $root_forum_name = $GLOBALS['FORUM_DB']->query_select_value('f_forums', 'f_name', array('id' => db_get_first_id()));
            $breadcrumbs = array();
            $breadcrumbs[] = array(build_page_link(array('page' => 'forumview', 'id' => db_get_first_id()), get_module_zone('forumview')), $root_forum_name);
            $breadcrumbs[] = array('', do_lang_tempcode('INLINE_PERSONAL_POSTS'));
            breadcrumb_set_parents($breadcrumbs);
        }

        $threaded = ($topic_info['is_threaded'] == 1);
        if (!$threaded) {
            $jump_post_id = get_param_integer('post_id', null);

            set_extra_request_metadata(array(
                'description' => $topic_info['description'],
            ));
            foreach ($topic_info['posts'] as $array_id => $_postdetails) {
                if (($GLOBALS['METADATA']['description'] == '') && (($_postdetails['id'] === $jump_post_id) || (($array_id == 0) && ($jump_post_id === null)))) {
                    // NB: A side-effect of this is that the Tempcode is evaluated, causing the 'image' metadata for an attachment (in MEDIA_WEBSAFE.tpl) to fill. We want this.
                    $truncated = symbol_truncator(array($_postdetails['post'], '200', '0', '1', '0.2'), 'left'); // FUDGE: Should we hard-code this?
                    set_extra_request_metadata(array(
                        'description' => strip_html($truncated),
                    ));

                    // Also scan for <img> tag, in case it was put in manually
                    if ((!isset($GLOBALS['METADATA']['image'])) || ($GLOBALS['METADATA']['image'] == find_theme_image('icons/48x48/menu/social/forum/forums'))) {
                        $matches = array();
                        if (preg_match('#<img\s[^<>]*src="([^"]*)"#', is_object($_postdetails['post']) ? $_postdetails['post']->evaluate() : $_postdetails['post'], $matches) != 0) {
                            set_extra_request_metadata(array(
                                'image' => html_entity_decode($matches[1], ENT_QUOTES, get_charset()),
                            ));
                        }
                    }
                }
            }
        } else {
            require_code('topics');
            $threaded_topic_ob = new CMS_Topic();

            // Load some settings into the renderer
            $threaded_topic_ob->first_post_id = $topic_info['first_post_id'];
            $threaded_topic_ob->topic_description = $topic_info['description'];
            $threaded_topic_ob->topic_description_link = $topic_info['description_link'];
            $threaded_topic_ob->topic_title = $topic_info['title'];
            $threaded_topic_ob->topic_info = $topic_info;

            // Other settings we need
            $max_thread_depth = intval(get_option('max_thread_depth'));
            $num_to_show_limit = get_param_integer('max_comments', intval(get_option('comments_to_show_in_thread')));

            // Load posts
            $threaded_topic_ob->load_from_topic($id, $num_to_show_limit, $start, false, null, true);
            $threaded_topic_ob->is_threaded = true;

            // Render posts
            list($posts, $serialized_options, $hash) = $threaded_topic_ob->render_posts($num_to_show_limit, $max_thread_depth, $may_reply, $topic_info['first_poster'], array(), $topic_info['forum_id'], $topic_info['row'], null, false);

            set_extra_request_metadata(array(
                'description' => $threaded_topic_ob->topic_description,
            ));

            $this->posts = $posts;
            $this->serialized_options = $serialized_options;
            $this->hash = $hash;
            $this->threaded_topic_ob = $threaded_topic_ob;
        }

        $this->title = $title;
        $this->breadcrumbs = $breadcrumbs;
        $this->type = $type;
        $this->id = $id;
        $this->topic_info = $topic_info;
        $this->forum_id = $topic_info['forum_id'];
        $this->may_reply = $may_reply;
        $this->start = $start;
        $this->default_max = $default_max;
        $this->max = $max;

        return null;
    }

    /**
     * Execute the module.
     *
     * @return Tempcode The result of execution.
     */
    public function run()
    {
        $title = $this->title;
        $breadcrumbs = $this->breadcrumbs;
        $type = $this->type;
        $id = $this->id;
        $topic_info = $this->topic_info;
        $may_reply = $this->may_reply;
        $start = $this->start;
        $default_max = $this->default_max;
        $max = $this->max;

        require_css('cns');

        $first_unread_id = -1;

        require_code('users');

        // Mark as read
        if ((!is_null($id)) && ($GLOBALS['FORUM_DRIVER']->get_member_row_field(get_member(), 'm_auto_mark_read') == 1)) {
            if ((is_null($topic_info['forum_id'])) || (get_value('avoid_register_shutdown_function') === '1') ) {
                $this->_update_read_status(); // Done early because we need to have updated read status set when the pt_notifications show up
            } else {
                register_shutdown_function(array($this, '_update_read_status')); // done at end after output in case of locking (don't make the user wait)
            }
        }

        // Render posts according to whether threaded or not
        $threaded = ($topic_info['is_threaded'] == 1);
        if (!$threaded) {
            // Poster detail hooks
            $hooks = find_all_hooks('modules', 'topicview');
            $hook_objects = array();
            foreach (array_keys($hooks) as $hook) {
                require_code('hooks/modules/topicview/' . filter_naughty_harsh($hook));
                $object = object_factory('Hook_topicview_' . filter_naughty_harsh($hook), true);
                if (is_null($object)) {
                    continue;
                }
                $hook_objects[$hook] = $object;
            }

            $jump_post_id = get_param_integer('post_id', null);
            $jump_post_found = false;

            // Render non-threaded
            $posts = new Tempcode();
            $replied = false;
            if (is_null($topic_info['forum_id'])) {
                // Has now read
                decache('side_cns_private_topics', null, get_member());
                decache('_new_pp', null, get_member());
                decache('_get_pts', null, get_member());
            }
            $second_poster = $topic_info['first_poster'];
            $poster_details_cache = array();
            foreach ($topic_info['posts'] as $array_id => $_postdetails) {
                if ($_postdetails['id'] === $jump_post_id) {
                    $jump_post_found = true;
                }

                if ($array_id == 0) {
                    $description = $topic_info['description'];
                } else {
                    $description = null;
                }

                if ($_postdetails['poster'] == get_member()) {
                    $replied = true;
                }

                if (($array_id == 1 && $start == 0) || ($array_id == 0 && $start != 0)) {
                    $second_poster = $_postdetails['poster'];
                }

                if (array_key_exists('last_edit_time', $_postdetails)) {
                    $last_edited = do_template('CNS_TOPIC_POST_LAST_EDITED', array(
                        '_GUID' => '77a28e8bc3cf2ec2211aafdb5ba192bf',
                        'LAST_EDIT_DATE_RAW' => is_null($_postdetails['last_edit_time']) ? '' : strval($_postdetails['last_edit_time']),
                        'LAST_EDIT_DATE' => $_postdetails['last_edit_time_string'],
                        'LAST_EDIT_PROFILE_URL' => $GLOBALS['FORUM_DRIVER']->member_profile_url($_postdetails['last_edit_by'], false, true),
                        'LAST_EDIT_USERNAME' => $_postdetails['last_edit_by_username'],
                    ));
                } else {
                    $last_edited = new Tempcode();
                }
                $last_edited_raw = (array_key_exists('last_edit_time', $_postdetails)) ? (is_null($_postdetails['last_edit_time']) ? '' : strval($_postdetails['last_edit_time'])) : '0';

                $is_spacer_post = $_postdetails['is_spacer_post'];

                // Post buttons
                $buttons = new Tempcode();
                if (!$is_spacer_post) {
                    $buttons = cns_render_post_buttons($topic_info, $_postdetails, $may_reply);
                }

                if (isset($poster_details_cache[$_postdetails['poster']][$_postdetails['poster_username']])) { // The cache avoids a lot of potentially duplicated Tempcode structure
                    list($poster_online, $post_avatar, $rank_images, $poster_details, $poster, $signature) = $poster_details_cache[$_postdetails['poster']][$_postdetails['poster_username']];
                } else {
                    // User online status
                    $poster_online = mixed();
                    if ((get_option('is_on_show_online') == '1') && (!is_guest($_postdetails['poster']))) {
                        require_code('users2');
                        $poster_online = member_is_online($_postdetails['poster']);
                    }

                    // Avatar
                    if ((array_key_exists('poster_avatar', $_postdetails)) && ($_postdetails['poster_avatar'] != '')) {
                        $post_avatar = do_template('CNS_TOPIC_POST_AVATAR', array('_GUID' => 'd647ada9c11d56eedc0ff7894d33e83c', 'AVATAR' => $_postdetails['poster_avatar']));
                    } else {
                        $post_avatar = new Tempcode();
                    }

                    // Rank images
                    $rank_images = new Tempcode();
                    if (!$is_spacer_post) {
                        $posters_groups = $GLOBALS['FORUM_DRIVER']->get_members_groups($_postdetails['poster'], true);
                        foreach ($posters_groups as $group) {
                            $rank_image = cns_get_group_property($group, 'rank_image');
                            $group_leader = cns_get_group_property($group, 'group_leader');
                            $group_name = cns_get_group_name($group);
                            $rank_image_pri_only = cns_get_group_property($group, 'rank_image_pri_only');
                            if (($rank_image != '') && (($rank_image_pri_only == 0) || ($group == $GLOBALS['FORUM_DRIVER']->get_member_row_field($_postdetails['poster'], 'm_primary_group')))) {
                                $rank_username = $GLOBALS['FORUM_DRIVER']->get_username($_postdetails['poster']);
                                if ($rank_username === null) {
                                    $rank_username = do_lang('UNKNOWN');
                                }
                                $rank_images->attach(do_template('CNS_RANK_IMAGE', array('_GUID' => '0ff7855482b901be95591964d4212c44', 'GROUP_NAME' => $group_name, 'USERNAME' => $rank_username, 'IMG' => $rank_image, 'IS_LEADER' => $group_leader == $_postdetails['poster'])));
                            }
                        }
                    }

                    // Poster details
                    if (!$is_spacer_post) {
                        if (!is_guest($_postdetails['poster'])) {
                            require_code('cns_members2');
                            $poster_details = render_member_box($_postdetails, false, $hooks, $hook_objects, false, null, false);
                        } else {
                            $custom_fields = new Tempcode();
                            if (array_key_exists('ip_address', $_postdetails)) {
                                $custom_fields->attach(do_template('CNS_MEMBER_BOX_CUSTOM_FIELD', array('_GUID' => 'd85be094dff0d039a64120d6f8f381bb', 'NAME' => do_lang_tempcode('IP_ADDRESS'), 'VALUE' => ($_postdetails['ip_address']))));
                                $poster_details = do_template('CNS_GUEST_DETAILS', array('_GUID' => 'e43534acaf598008602e8da8f9725f38', 'CUSTOM_FIELDS' => $custom_fields));
                            } else {
                                $poster_details = new Tempcode();
                            }
                        }
                    } else {
                        $poster_details = new Tempcode();
                    }

                    if (!is_guest($_postdetails['poster'])) {
                        require_code('users2');
                        $poster = do_template('CNS_POSTER_MEMBER', array(
                            '_GUID' => 'dbbed1850b6c01a6c9601d85c6aee43f',
                            'ONLINE' => member_is_online($_postdetails['poster']),
                            'ID' => strval($_postdetails['poster']),
                            'POSTER_DETAILS' => $poster_details,
                            'PROFILE_URL' => $GLOBALS['FORUM_DRIVER']->member_profile_url($_postdetails['poster'], false, true),
                            'POSTER_USERNAME' => $_postdetails['poster_username'],
                            'HIGHLIGHT_NAME' => array_key_exists('poster_highlighted_name', $_postdetails) ? strval($_postdetails['poster_highlighted_name']) : null,
                        ));
                    } else {
                        $lookup_ip_url = ((addon_installed('securitylogging')) && (array_key_exists('ip_address', $_postdetails)) && (has_actual_page_access(get_member(), 'admin_lookup'))) ? build_url(array('page' => 'admin_lookup', 'param' => $_postdetails['ip_address']), get_module_zone('admin_lookup')) : new Tempcode();
                        $poster = do_template('CNS_POSTER_GUEST', array('_GUID' => '36a8e550222cdac5165ef8f722be3def', 'LOOKUP_IP_URL' => $lookup_ip_url, 'POSTER_DETAILS' => $poster_details, 'POSTER_USERNAME' => $_postdetails['poster_username']));
                    }

                    // Signature
                    $signature = new Tempcode();
                    if ((array_key_exists('signature', $_postdetails)) && (!$_postdetails['signature']->is_empty())) {
                        $signature = $_postdetails['signature'];
                    }

                    $poster_details_cache[$_postdetails['poster']][$_postdetails['poster_username']] = array($poster_online, $post_avatar, $rank_images, $poster_details, $poster, $signature);
                }

                $post_title = $_postdetails['title'];

                $first_unread = (($_postdetails['id'] == $first_unread_id) || (($first_unread_id < 0) && ($array_id == count($topic_info['posts']) - 1))) ? do_template('CNS_TOPIC_FIRST_UNREAD') : new Tempcode();

                $unvalidated = (($_postdetails['validated'] == 0) && (addon_installed('unvalidated'))) ? do_lang_tempcode('UNVALIDATED') : new Tempcode();

                $post_url = $GLOBALS['FORUM_DRIVER']->post_url($_postdetails['id'], is_null($topic_info['forum_id']) ? '' : strval($topic_info['forum_id']), true);

                if ((array_key_exists('intended_solely_for', $_postdetails)) && ($_postdetails['intended_solely_for'] == get_member())) {
                    // Has now read
                    decache('side_cns_private_topics', null, get_member());
                    decache('_new_pp', null, get_member());
                    decache('_get_pts', null, get_member());
                }

                $emphasis = cns_get_post_emphasis($_postdetails);

                require_code('feedback');
                if (!array_key_exists('intended_solely_for', $_postdetails) && get_value('no_post_rating', '0', true) !== '1') {
                    actualise_rating(true, 'post', strval($_postdetails['id']), get_self_url(), $_postdetails['title']);
                    $rating = display_rating(get_self_url(), $_postdetails['title'], 'post', strval($_postdetails['id']), 'RATING_INLINE_DYNAMIC', $_postdetails['poster']);
                } else {
                    $rating = new Tempcode();
                }

                if ((isset($GLOBALS['METADATA']['description'])) && ($GLOBALS['METADATA']['description'] == '') && (($_postdetails['id'] === $jump_post_id) || (($array_id == 0) && ($jump_post_id === null)))) {
                    set_extra_request_metadata(array(
                        'description' => strip_html(symbol_truncator(array($_postdetails['post'], '200', '0', '1', '0.2'), 'left')),
                    ));
                }

                $rendered_post = do_template('CNS_TOPIC_POST', array(
                    '_GUID' => 'sacd09wekfofpw2f',
                    'GIVE_CONTEXT' => false,
                    'ID' => $is_spacer_post ? '' : strval($_postdetails['id']),
                    'TOPIC_FIRST_POST_ID' => is_null($topic_info['first_post_id']) ? '' : strval($topic_info['first_post_id']),
                    'TOPIC_FIRST_POSTER' => is_null($topic_info['first_poster']) ? '' : strval($topic_info['first_poster']),
                    'POST_ID' => $is_spacer_post ? '' : ((get_option('seq_post_ids') == '1') ? strval($start + $array_id + 1) : strval($_postdetails['id'])),
                    'URL' => $post_url,
                    'CLASS' => $_postdetails['is_emphasised'] ? 'cns_post_emphasis' : (array_key_exists('intended_solely_for', $_postdetails) ? 'cns_post_personal' : ''),
                    'EMPHASIS' => $emphasis,
                    'FIRST_UNREAD' => $first_unread,
                    'POSTER_TITLE' => $is_spacer_post ? '' : $_postdetails['poster_title'],
                    'POST_TITLE' => $post_title,
                    'POST_DATE_RAW' => strval($_postdetails['time']),
                    'POST_DATE' => $_postdetails['time_string'],
                    'POST' => $_postdetails['post'],
                    'TOPIC_ID' => is_null($id) ? '' : strval($id),
                    'LAST_EDITED_RAW' => $last_edited_raw,
                    'LAST_EDITED' => $last_edited,
                    'POSTER_ID' => strval($_postdetails['poster']),
                    'POSTER' => $is_spacer_post ? '' : $poster,
                    'POSTER_DETAILS' => $poster_details,
                    'POST_AVATAR' => $post_avatar,
                    'RANK_IMAGES' => $rank_images,
                    'BUTTONS' => $buttons,
                    'SIGNATURE' => $signature,
                    'UNVALIDATED' => $unvalidated,
                    'DESCRIPTION' => $description,
                    'RATING' => $rating,
                    'POSTER_ONLINE' => $poster_online,
                    'FORUM_ID' => is_null($topic_info['forum_id']) ? '' : strval($topic_info['forum_id']),
                ));
                $posts->attach($rendered_post);
            }

            $serialized_options = mixed();
            $hash = mixed();

            if (($jump_post_id !== null) && (!$jump_post_found)) {
                attach_message(do_lang_tempcode('_MISSING_RESOURCE', strval($jump_post_id), 'post'), 'warn');
            }
        } else { // Threaded
            $posts = $this->posts;
            $serialized_options = $this->serialized_options;
            $hash = $this->hash;
            $threaded_topic_ob = $this->threaded_topic_ob;

            // Get other gathered details
            $replied = $threaded_topic_ob->replied;
            if (!is_null($threaded_topic_ob->topic_title)) {// Updated topic title
                $topic_info['title'] = $threaded_topic_ob->topic_title;
            }
            $topic_info['max_rows'] = $threaded_topic_ob->total_posts;

            $second_poster = $GLOBALS['FORUM_DRIVER']->get_guest_id(); // No definitive post orders
        }

        // Buttons for topic as whole
        $button_array = array();
        if (!is_null($id)) {
            if (get_option('threaded_buttons') == '1') {
                if ($threaded) {
                    $view_as_linear_url = get_self_url(false, false, array('threaded' => 0));
                    $button_array[] = array('immediate' => true, 'title' => do_lang_tempcode('_VIEW_AS_LINEAR'), 'url' => $view_as_linear_url, 'img' => 'buttons__linear');
                } else {
                    $view_as_threaded_url = get_self_url(false, false, array('threaded' => 1));
                    $button_array[] = array('immediate' => true, 'title' => do_lang_tempcode('_VIEW_AS_THREADED'), 'url' => $view_as_threaded_url, 'img' => 'buttons__threaded');
                }
            }

            if (!is_guest()) {
                $too_old = $topic_info['last_time'] < time() - 60 * 60 * 24 * intval(get_option('post_read_history_days'));

                require_code('users');

                if (($GLOBALS['FORUM_DRIVER']->get_member_row_field(get_member(), 'm_auto_mark_read') != 1) && (get_option('enable_mark_topic_unread') === '1') && !cns_has_read_topic($id)) {
                    $redirect_map = array('page' => 'topicview', 'id' => $id);
                    $test_threaded = get_param_integer('threaded', null);
                    if ($test_threaded !== null) {
                        $redirect_map['threaded'] = $test_threaded;
                    }
                    $redirect = build_url($redirect_map, get_module_zone('topicview'));
                    $map = array('page' => 'topics', 'type' => 'mark_read_topic', 'id' => $id, 'redirect' => $redirect->evaluate());
                    if ($test_threaded !== null) {
                        $map['threaded'] = $test_threaded;
                    }
                    $mark_read_url = build_url($map, get_module_zone('topics'));
                    $button_array[] = array('immediate' => true, 'title' => do_lang_tempcode('MARK_READ'), 'url' => $mark_read_url, 'img' => 'buttons__mark_read_topic');
                } else {
                    if ((get_option('enable_mark_topic_unread') === '1') && !$too_old) {
                        $map = array('page' => 'topics', 'type' => 'mark_unread_topic', 'id' => $id);
                        $test = get_param_string('kfs' . (is_null($topic_info['forum_id']) ? '' : strval($topic_info['forum_id'])), null, true);
                        if (($test !== null) && ($test !== '0')) {
                            $map['kfs' . (is_null($topic_info['forum_id']) ? '' : strval($topic_info['forum_id']))] = $test;
                        }
                        $test_threaded = get_param_integer('threaded', null);
                        if ($test_threaded !== null) {
                            $map['threaded'] = $test_threaded;
                        }
                        $mark_unread_url = build_url($map, get_module_zone('topics'));
                        $button_array[] = array('immediate' => true, 'title' => do_lang_tempcode('MARK_UNREAD'), 'url' => $mark_unread_url, 'img' => 'buttons__mark_unread_topic');
                    }
                }
            }

            if (($may_reply) && (is_null(get_bot_type()))) {
                $reply_prevented = false;

                // "Staff-only" reply for support tickets
                if (($GLOBALS['FORUM_DRIVER']->is_staff(get_member())) && (addon_installed('tickets'))) {
                    require_code('tickets');
                    if (is_ticket_forum($topic_info['forum_id'])) {
                        if (is_guest($second_poster)) {
                            $reply_prevented = true;
                        }

                        require_lang('tickets');
                        require_css('tickets');
                        $map = array('page' => 'topics', 'type' => 'new_post', 'id' => $id, 'intended_solely_for' => $GLOBALS['FORUM_DRIVER']->get_guest_id());
                        $test = get_param_string('kfs' . (is_null($topic_info['forum_id']) ? '' : strval($topic_info['forum_id'])), null, true);
                        if (($test !== null) && ($test !== '0')) {
                            $map['kfs' . (is_null($topic_info['forum_id']) ? '' : strval($topic_info['forum_id']))] = $test;
                        }
                        $test_threaded = get_param_integer('threaded', null);
                        if ($test_threaded !== null) {
                            $map['threaded'] = $test_threaded;
                        }
                        $new_post_url = build_url($map, get_module_zone('topics'));
                        $button_array[] = array('immediate' => false, 'rel' => 'add', 'title' => do_lang_tempcode('TICKET_STAFF_ONLY_REPLY'), 'url' => $new_post_url, 'img' => 'buttons__new_reply_staff_only');
                    }
                }

                if (!$reply_prevented) {
                    if ($topic_info['is_threaded'] == 0) { // For threaded ones (i.e. not this) we want to encourage people to click the reply button by a post
                        $map = array('page' => 'topics', 'type' => 'new_post', 'id' => $id);
                        $test = get_param_string('kfs' . (is_null($topic_info['forum_id']) ? '' : strval($topic_info['forum_id'])), null, true);
                        if (($test !== null) && ($test !== '0')) {
                            $map['kfs' . (is_null($topic_info['forum_id']) ? '' : strval($topic_info['forum_id']))] = $test;
                        }
                        $test_threaded = get_param_integer('threaded', null);
                        if ($test_threaded !== null) {
                            $map['threaded'] = $test_threaded;
                        }
                        $new_post_url = build_url($map, get_module_zone('topics'));
                        $button_array[] = array('immediate' => false, 'rel' => 'add', 'title' => do_lang_tempcode($topic_info['is_open'] ? '_REPLY' : 'CLOSED'), 'url' => $new_post_url, 'img' => $topic_info['is_open'] ? 'buttons__new_reply' : 'buttons__closed');
                    }
                } else {
                    unset($topic_info['may_use_quick_reply']);
                }
            } // Maybe we can let them edit their last post instead?
            elseif (((is_null($topic_info['forum_id'])) || (has_privilege(get_member(), 'submit_lowrange_content', 'topics', array('forums', $topic_info['forum_id'])))) && ($topic_info['last_poster'] == get_member()) && (!is_guest()) && (cns_may_edit_post_by($topic_info['last_post_id'], $topic_info['last_time'], get_member(), $topic_info['forum_id'], null, $topic_info['is_open'] == 0))) {
                $map = array('page' => 'topics', 'type' => 'edit_post', 'id' => $topic_info['last_post_id']);
                $test = get_param_string('kfs' . strval($topic_info['forum_id']), null, true);
                if (($test !== null) && ($test !== '0')) {
                    $map['kfs' . strval($topic_info['forum_id'])] = $test;
                }
                $test_threaded = get_param_integer('threaded', null);
                if ($test_threaded !== null) {
                    $map['threaded'] = $test_threaded;
                }
                $new_post_url = build_url($map, get_module_zone('topics'));
                $button_array[] = array('immediate' => false, 'rel' => 'edit', 'title' => do_lang_tempcode('LAST_POST'), 'url' => $new_post_url, 'img' => 'buttons__edit');
            }

            if (!is_null($topic_info['forum_id'])) {
                if (get_option('enable_add_topic_btn_in_topic') == '1') {
                    if (cns_may_post_topic($topic_info['forum_id'], get_member())) {
                        $new_topic_url = build_url(array('page' => 'topics', 'type' => 'new_topic', 'id' => $topic_info['forum_id']), get_module_zone('topics'));
                        $button_array[] = array('immediate' => false, 'rel' => 'add', 'title' => do_lang_tempcode('ADD_TOPIC'), 'url' => $new_topic_url, 'img' => 'buttons__new_topic');
                    }
                }
            } else {
                $invite_url = build_url(array('page' => 'topics', 'type' => 'invite_member', 'id' => $id), get_module_zone('topics'));
                $button_array[] = array('immediate' => false, 'title' => do_lang_tempcode('_INVITE_MEMBER_TO_PT'), 'url' => $invite_url, 'img' => 'menu___generic_admin__add_to_category');
            }
        }
        $buttons = cns_button_screen_wrap($button_array);

        // Poll
        if (array_key_exists('poll', $topic_info)) {
            $_poll = $topic_info['poll'];
            $voted_already = $_poll['voted_already'];
            $poll_results = (array_key_exists(0, $_poll['answers'])) && (array_key_exists('num_votes', $_poll['answers'][0]));
            $answers = new Tempcode();
            $real_button = false;
            if ($_poll['is_open']) {
                if ($poll_results) {
                    $button = new Tempcode();
                } elseif (($_poll['requires_reply']) && (!$replied)) {
                    $button = do_lang_tempcode('POLL_REQUIRES_REPLY');
                } else {
                    if (!has_privilege(get_member(), 'vote_in_polls')) {
                        $button = do_lang_tempcode(is_guest() ? 'GUESTS_CANT_VOTE_IN_POLLS' : 'VOTE_DENIED');
                    } else {
                        if (!is_null($voted_already)) {
                            $button = do_lang_tempcode('NOVOTE');
                        } else {
                            require_lang('polls');
                            $map = array('page' => 'topicview', 'id' => $id, 'view_poll_results' => 1, 'topic_start' => ($start == 0) ? null : $start, 'topic_max' => ($max == $default_max) ? null : $max);
                            $test = get_param_string('kfs' . (is_null($topic_info['forum_id']) ? '' : strval($topic_info['forum_id'])), null, true);
                            if (($test !== null) && ($test !== '0')) {
                                $map['kfs' . (is_null($topic_info['forum_id']) ? '' : strval($topic_info['forum_id']))] = $test;
                            }
                            $test_threaded = get_param_integer('threaded', null);
                            if ($test_threaded !== null) {
                                $map['threaded'] = $test_threaded;
                            }
                            $results_url = build_url($map, get_module_zone('topics'));
                            $button = do_template('CNS_TOPIC_POLL_BUTTON', array('_GUID' => '94b932fd01028df8f67bb5864d9235f9', 'RESULTS_URL' => $results_url));
                            $real_button = true;
                        }
                    }
                }
            } else {
                $button = do_lang_tempcode('TOPIC_POLL_CLOSED');
            }
            foreach ($_poll['answers'] as $answer) {
                if (($poll_results) && (($_poll['requires_reply'] == 0) || ($replied))) {
                    $num_votes = $answer['num_votes'];
                    $total_votes = $_poll['total_votes'];
                    if ($total_votes != 0) {
                        $width = intval(round(70.0 * floatval($num_votes) / floatval($total_votes)));
                    } else {
                        $width = 0;
                    }
                    $answer_tpl = do_template('CNS_TOPIC_POLL_ANSWER_RESULTS', array('_GUID' => 'b32f4c526e147abf20ca0d668e40d515', 'ID' => strval($_poll['id']), 'NUM_VOTES' => integer_format($num_votes), 'TOTAL_VOTES' => integer_format($total_votes), 'WIDTH' => strval($width), 'ANSWER' => $answer['answer'], 'I' => strval($answer['id'])));
                } else {
                    $answer_tpl = do_template('CNS_TOPIC_POLL_ANSWER' . ($_poll['maximum_selections'] == 1 ? '_RADIO' : ''), array('REAL_BUTTON' => $real_button, 'ID' => strval($_poll['id']), 'ANSWER' => $answer['answer'], 'I' => strval($answer['id'])));
                }
                $answers->attach($answer_tpl);
            }
            $map = array('page' => 'topics', 'type' => 'vote_poll', 'id' => $id, 'topic_start' => ($start == 0) ? null : $start, 'topic_max' => ($max == $default_max) ? null : $max);
            $test = get_param_string('kfs' . (is_null($topic_info['forum_id']) ? '' : strval($topic_info['forum_id'])), null, true);
            if (($test !== null) && ($test !== '0')) {
                $map['kfs' . (is_null($topic_info['forum_id']) ? '' : strval($topic_info['forum_id']))] = $test;
            }
            $test_threaded = get_param_integer('threaded', null);
            if ($test_threaded !== null) {
                $map['threaded'] = $test_threaded;
            }
            $vote_url = build_url($map, get_module_zone('topics'));
            if ($_poll['is_private']) {
                $private = paragraph(do_lang_tempcode('TOPIC_POLL_IS_PRIVATE'), 'dfgsdgdsgs');
            } else {
                $private = new Tempcode();
            }
            if ($_poll['maximum_selections'] > 1) {
                $num_choices = paragraph(($_poll['minimum_selections'] == $_poll['maximum_selections']) ? do_lang_tempcode('POLL_NOT_ENOUGH_ERROR_2', escape_html(integer_format($_poll['minimum_selections']))) : do_lang_tempcode('POLL_NOT_ENOUGH_ERROR', escape_html(integer_format($_poll['minimum_selections'])), escape_html(integer_format($_poll['maximum_selections']))), 'dsfsdfsdfs');
            } else {
                $num_choices = new Tempcode();
            }

            $poll = do_template('CNS_TOPIC_POLL' . ($poll_results ? '_VIEW_RESULTS' : ''), array(
                'ID' => strval($_poll['id']),
                'NUM_CHOICES' => $num_choices,
                'PRIVATE' => $private,
                'QUESTION' => $_poll['question'],
                'ANSWERS' => $answers,
                'REAL_BUTTON' => $real_button,
                'BUTTON' => $button,
                'VOTE_URL' => $vote_url,
                'MINIMUM_SELECTIONS' => integer_format($_poll['minimum_selections']),
                'MAXIMUM_SELECTIONS' => integer_format($_poll['maximum_selections']),
            ));
        } else {
            $poll = new Tempcode();
        }

        // Quick reply
        if ((array_key_exists('may_use_quick_reply', $topic_info)) && ($may_reply) && (!is_null($id))) {
            $map = array('page' => 'topics', 'type' => '_add_reply', 'topic_id' => $id, 'timestamp' => time());
            $test = get_param_string('kfs' . (is_null($topic_info['forum_id']) ? '' : strval($topic_info['forum_id'])), null, true);
            if (($test !== null) && ($test !== '0')) {
                $map['kfs' . (is_null($topic_info['forum_id']) ? '' : strval($topic_info['forum_id']))] = $test;
            }
            $test_threaded = get_param_integer('threaded', null);
            if ($test_threaded !== null) {
                $map['threaded'] = $test_threaded;
            }
            $map['overlay'] = get_param_integer('overlay', null);
            $map['wide_high'] = get_param_integer('wide_high', null);
            $_post_url = build_url($map, get_module_zone('topics'));
            $post_url = $_post_url->evaluate();
            $map = array('page' => 'topics', 'type' => 'new_post', 'id' => $id, 'timestamp' => time());
            if (($test !== null) && ($test !== '0')) {
                $map['kfs' . (is_null($topic_info['forum_id']) ? '' : strval($topic_info['forum_id']))] = $test;
            }
            $more_url = build_url($map, get_module_zone('topics'));
            if (isset($topic_info['first_post'])) {
                $post_row = db_map_restrict($topic_info['row'], array('id', 'p_post'), array('id' => 't_cache_first_post_id'));
                $_postdetails = get_translated_tempcode('f_posts', $post_row, 'p_post', $GLOBALS['FORUM_DB']);
            } else {
                $_postdetails = new Tempcode();
            }
            $first_post = $_postdetails;
            if (strpos($first_post->evaluate(), '<script') !== false) {
                $first_post = new Tempcode(); // Rendering twice could cause issues
            }
            $first_post_url = $GLOBALS['FORUM_DRIVER']->post_url($topic_info['first_post_id'], is_null($topic_info['forum_id']) ? '' : strval($topic_info['forum_id']), true);
            $display = 'block';
            $expand_type = 'contract';
            if ($topic_info['max_rows'] > $start + $max) {
                $display = 'none';
                $expand_type = 'expand';
            }
            $em = $GLOBALS['FORUM_DRIVER']->get_emoticon_chooser();
            require_javascript('editing');
            require_javascript('checking');
            if (addon_installed('captcha')) {
                require_code('captcha');
                $use_captcha = use_captcha();
                if ($use_captcha) {
                    generate_captcha();
                }
            } else {
                $use_captcha = false;
            }

            $post_warning = '';
            if ($topic_info['is_really_threaded'] == 1) {
                $post_warning = do_lang('THREADED_REPLY_NOTICE', $post_warning);
            }

            require_code('form_templates');
            list($attachments, $attach_size_field) = get_attachments('post');

            $quick_reply = do_template('COMMENTS_POSTING_FORM', array(
                '_GUID' => '4c532620f3eb68d9cc820b18265792d7',
                'JOIN_BITS' => '',
                'USE_CAPTCHA' => $use_captcha,
                'ATTACHMENTS' => $attachments,
                'ATTACH_SIZE_FIELD' => $attach_size_field,
                'GET_EMAIL' => false,
                'EMAIL_OPTIONAL' => true,
                'GET_TITLE' => false,
                'POST_WARNING' => $post_warning,
                'COMMENT_TEXT' => '',
                'EM' => $em,
                'EXPAND_TYPE' => $expand_type,
                'DISPLAY' => $display,
                'FIRST_POST_URL' => $first_post_url,
                'FIRST_POST' => $first_post,
                'MORE_URL' => $more_url,
                'COMMENT_URL' => $post_url,
                'TITLE' => do_lang_tempcode('QUICK_REPLY'),
                'SUBMIT_NAME' => do_lang_tempcode('REPLY'),
            ));
        } else {
            $quick_reply = new Tempcode();
        }

        $action_url = build_url(array('page' => 'topics', 'id' => $id), get_module_zone('topics'));
        if (!is_null($id)) {
            // Moderation options
            $moderator_actions = '';
            if (is_null($topic_info['forum_id'])) {
                $moderator_actions .= '<option value="categorise_pts">' . do_lang('_CATEGORISE_PTS') . '</option>';
                $filter_cats = cns_get_filter_cats();
                foreach ($filter_cats as $filter_cat) {
                    if ($filter_cat != '') {
                        $moderator_actions .= '<option value="categorise_pts__' . escape_html($filter_cat) . '">' . do_lang('CATEGORISE_PTS_AS', escape_html($filter_cat)) . '</option>';
                    }
                }
            }
            if ((array_key_exists('may_multi_moderate', $topic_info)) && (array_key_exists('forum_id', $topic_info)) && (addon_installed('cns_multi_moderations'))) {
                $multi_moderations = cns_list_multi_moderations($topic_info['forum_id']);
                if (count($multi_moderations) != 0) {
                    require_lang('cns_multi_moderations');
                    $moderator_actions .= '<optgroup label="' . do_lang('MULTI_MODERATIONS') . '">';
                    foreach ($multi_moderations as $mm_id => $mm_name) {
                        $moderator_actions .= '<option value="mm_' . strval($mm_id) . '">' . escape_html($mm_name) . '</option>';
                    }
                    $moderator_actions .= '</optgroup>';
                }
            }
            if (array_key_exists('may_move_topic', $topic_info)) {
                $moderator_actions .= '<option value="move_topic">' . do_lang('MOVE_TOPIC') . '</option>';
            }
            if (array_key_exists('may_edit_topic', $topic_info)) {
                $moderator_actions .= '<option value="edit_topic">' . do_lang('EDIT_TOPIC') . '</option>';
            }
            if (array_key_exists('may_delete_topic', $topic_info)) {
                $moderator_actions .= '<option value="delete_topic">' . do_lang('DELETE_TOPIC') . '</option>';
            }
            if (array_key_exists('may_pin_topic', $topic_info)) {
                $moderator_actions .= '<option value="pin_topic">' . do_lang('PIN_TOPIC') . '</option>';
            }
            if (array_key_exists('may_unpin_topic', $topic_info)) {
                $moderator_actions .= '<option value="unpin_topic">' . do_lang('UNPIN_TOPIC') . '</option>';
            }
            if (array_key_exists('may_sink_topic', $topic_info)) {
                $moderator_actions .= '<option value="sink_topic">' . do_lang('SINK_TOPIC') . '</option>';
            }
            if (array_key_exists('may_unsink_topic', $topic_info)) {
                $moderator_actions .= '<option value="unsink_topic">' . do_lang('UNSINK_TOPIC') . '</option>';
            }
            if (array_key_exists('may_cascade_topic', $topic_info)) {
                $moderator_actions .= '<option value="cascade_topic">' . do_lang('CASCADE_TOPIC') . '</option>';
            }
            if (array_key_exists('may_uncascade_topic', $topic_info)) {
                $moderator_actions .= '<option value="uncascade_topic">' . do_lang('UNCASCADE_TOPIC') . '</option>';
            }
            if (array_key_exists('may_open_topic', $topic_info)) {
                $moderator_actions .= '<option value="open_topic">' . do_lang('OPEN_TOPIC') . '</option>';
            }
            if (array_key_exists('may_close_topic', $topic_info)) {
                $moderator_actions .= '<option value="close_topic">' . do_lang('CLOSE_TOPIC') . '</option>';
            }
            if (array_key_exists('may_edit_poll', $topic_info)) {
                $moderator_actions .= '<option value="edit_poll">' . do_lang('EDIT_TOPIC_POLL') . '</option>';
            }
            if (array_key_exists('may_delete_poll', $topic_info)) {
                $moderator_actions .= '<option value="delete_poll">' . do_lang('DELETE_TOPIC_POLL') . '</option>';
            }
            if (array_key_exists('may_attach_poll', $topic_info)) {
                $moderator_actions .= '<option value="add_poll">' . do_lang('ADD_TOPIC_POLL') . '</option>';
            }
            if (addon_installed('actionlog')) {
                require_code('revisions_engine_database');
                $revision_engine = new RevisionEngineDatabase(true);
                if ($revision_engine->has_revisions(array('post'), null, strval($id))) {
                    $moderator_actions .= '<option value="topic_history">' . do_lang('actionlog:REVISIONS') . '</option>';
                }
            }
            if ((array_key_exists('may_make_private', $topic_info)) && (!is_null($topic_info['forum_id']))) {
                $moderator_actions .= '<option value="make_private">' . do_lang('MAKE_PERSONAL') . '</option>';
            }

            if ($GLOBALS['XSS_DETECT']) {
                ocp_mark_as_escaped($moderator_actions);
            }

            // Marked post actions
            $map = array('page' => 'topics', 'id' => $id);
            $test = get_param_string('kfs' . (is_null($topic_info['forum_id']) ? '' : strval($topic_info['forum_id'])), null, true);
            if (($test !== null) && ($test !== '0')) {
                $map['kfs' . (is_null($topic_info['forum_id']) ? '' : strval($topic_info['forum_id']))] = $test;
            }
            $test_threaded = get_param_integer('threaded', null);
            if ($test_threaded !== null) {
                $map['threaded'] = $test_threaded;
            }
            $action_url = build_url($map, get_module_zone('topics'), null, false, true);
            $marked_post_actions = '';
            if (array_key_exists('may_move_posts', $topic_info)) {
                $marked_post_actions .= '<option value="move_posts_a">' . do_lang('MERGE_POSTS') . '</option>';
                $marked_post_actions .= '<option value="move_posts_b">' . do_lang('SPLIT_POSTS') . '</option>';
            }
            if (array_key_exists('may_delete_posts', $topic_info)) {
                $marked_post_actions .= '<option value="delete_posts">' . do_lang('DELETE_POSTS') . '</option>';
            }
            if ((array_key_exists('may_validate_posts', $topic_info)) && (addon_installed('unvalidated'))) {
                $marked_post_actions .= '<option value="validate_posts">' . do_lang('VALIDATE_POSTS') . '</option>';
            }
            if (get_option('enable_multi_quote') == '1') {
                if ($may_reply) {
                    $marked_post_actions .= '<option value="new_post">' . do_lang('QUOTE_POSTS') . '</option>';
                }
            }

            if ($GLOBALS['XSS_DETECT']) {
                ocp_mark_as_escaped($marked_post_actions);
            }
        } else {
            $moderator_actions = '';
            $marked_post_actions = '';
        }

        $max_rows = $topic_info['max_rows'];
        if (($max_rows > $max) && (!$threaded)) {
            require_code('templates_pagination');
            $pagination = pagination(do_lang_tempcode('FORUM_POSTS'), $start, 'topic_start', $max, 'topic_max', $max_rows, false, 7, array(10, 20, 30));
        } else {
            $pagination = new Tempcode();
        }

        // Members viewing this topic
        if (!is_null($topic_info['forum_id'])) {
            member_tracking_update('forumview', '', strval($topic_info['forum_id'])); // If we are viewing topic say we are viewing the forum too
        }
        require_code('users2');
        if (is_null($id)) {
            $num_guests = mixed();
            $num_members = mixed();
            $members_viewing = new Tempcode();
        } else {
            list($num_guests, $num_members, $members_viewing) = get_members_viewing_wrap('topicview', '', strval($id), true); // This does a member_tracking_update to the topic internally
        }

        if (($topic_info['validated'] == 0) && (addon_installed('unvalidated'))) {
            $warning_details = do_template('WARNING_BOX', array(
                '_GUID' => '313de370c1aeab9545c4bee4e35e7f84',
                'WARNING' => do_lang_tempcode((get_param_integer('redirected', 0) == 1) ? 'UNVALIDATED_TEXT_NON_DIRECT' : 'UNVALIDATED_TEXT', 'topic'),
            ));
        } else {
            $warning_details = new Tempcode();
        }

        require_code('cns_general');
        cns_set_context_forum($topic_info['forum_id']);

        if (addon_installed('tickets')) {
            require_code('tickets');
            $is_ticket_forum = is_ticket_forum($topic_info['forum_id']);
        } else {
            $is_ticket_forum = false;
        }

        $topic_tpl = do_template('CNS_TOPIC_SCREEN', array(
            '_GUID' => 'bb201d5d59559e5e2bd60e7cf2e6f7e9',
            'TITLE' => $this->title,
            'SERIALIZED_OPTIONS' => $serialized_options,
            'HASH' => $hash,
            'ID' => is_null($id) ? '' : strval($id),
            '_TITLE' => $topic_info['title'],
            'MAY_DOUBLE_POST' => has_privilege(get_member(), 'double_post'),
            'LAST_POSTER' => array_key_exists('last_poster', $topic_info) ? (is_null($topic_info['last_poster']) ? '' : strval($topic_info['last_poster'])) : '',
            'WARNING_DETAILS' => $warning_details,
            'MAX' => strval($max),
            'MAY_CHANGE_MAX' => array_key_exists('may_change_max', $topic_info),
            'ACTION_URL' => $action_url,
            'NUM_GUESTS' => is_null($num_guests) ? '' : integer_format($num_guests),
            'NUM_MEMBERS' => is_null($num_members) ? '' : integer_format($num_members),
            'MEMBERS_VIEWING' => $members_viewing,
            'PAGINATION' => $pagination,
            'MODERATOR_ACTIONS' => $moderator_actions,
            'MARKED_POST_ACTIONS' => $marked_post_actions,
            'QUICK_REPLY' => $quick_reply,
            'BREADCRUMBS' => breadcrumbs_get_default_stub(),
            'POLL' => $poll,
            'BUTTON_SCREENS' => $buttons,
            'POSTS' => $posts,
            'THREADED' => $threaded,
            'FORUM_ID' => is_null($topic_info['forum_id']) ? '' : strval($topic_info['forum_id']),
            'IS_ALREADY_READ' => cns_has_read_topic($id),
            'TICKET_FORUM' => $is_ticket_forum,
        ));

        require_code('templates_internalise_screen');
        return internalise_own_screen($topic_tpl);
    }

    /**
     * Update the read status for a topic.
     */
    public function _update_read_status()
    {
        if (!is_guest()) {
            if ((get_option('post_read_history_days') != '0') && ((get_value('avoid_normal_topic_read_history') !== '1') || (is_null($this->forum_id)))) {
                cns_ping_topic_read($this->id);
                if ($GLOBALS['IS_ACTUALLY'] !== null) { // If posting with SU, mark the SUing user as read too, otherwise it is annoying
                    cns_ping_topic_read($this->id, $GLOBALS['IS_ACTUALLY']);
                }
            }
        }
        if ((get_db_type() != 'xml') && (is_null(get_bot_type()))) {
            if (!$GLOBALS['FORUM_DB']->table_is_locked('f_topics')) {
                $GLOBALS['FORUM_DB']->query('UPDATE ' . $GLOBALS['FORUM_DB']->get_table_prefix() . 'f_topics SET t_num_views=(t_num_views+1) WHERE id=' . strval((integer)$this->id), 1, null, true);
            }
        }
    }
}
