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

/**
 * Module page class.
 */
class Module_catalogues
{
    /**
     * 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'] = 8;
        $info['update_require_upgrade'] = true;
        $info['locked'] = false;
        return $info;
    }

    /**
     * Uninstall the module.
     */
    public function uninstall()
    {
        $GLOBALS['SITE_DB']->drop_table_if_exists('catalogues');
        $GLOBALS['SITE_DB']->drop_table_if_exists('catalogue_fields');
        $GLOBALS['SITE_DB']->drop_table_if_exists('catalogue_categories');
        $GLOBALS['SITE_DB']->drop_table_if_exists('catalogue_entries');
        $GLOBALS['SITE_DB']->drop_table_if_exists('catalogue_efv_long_trans');
        $GLOBALS['SITE_DB']->drop_table_if_exists('catalogue_efv_short_trans');
        $GLOBALS['SITE_DB']->drop_table_if_exists('catalogue_efv_long');
        $GLOBALS['SITE_DB']->drop_table_if_exists('catalogue_efv_short');
        $GLOBALS['SITE_DB']->drop_table_if_exists('catalogue_efv_float');
        $GLOBALS['SITE_DB']->drop_table_if_exists('catalogue_efv_integer');
        $GLOBALS['SITE_DB']->drop_table_if_exists('catalogue_entry_linkage');
        $GLOBALS['SITE_DB']->drop_table_if_exists('catalogue_cat_treecache');
        $GLOBALS['SITE_DB']->drop_table_if_exists('catalogue_childcountcache');

        $GLOBALS['SITE_DB']->query_delete('group_category_access', array('module_the_name' => 'catalogues_category'));
        $GLOBALS['SITE_DB']->query_delete('group_category_access', array('module_the_name' => 'catalogues_catalogue'));

        $GLOBALS['SITE_DB']->query_delete('trackbacks', array('trackback_for_type' => 'catalogues'));

        require_code('files');
        if (!$GLOBALS['DEV_MODE']) {
            deldir_contents(get_custom_file_base() . '/uploads/catalogues', true);
        }

        delete_privilege('high_catalogue_entry_timeout');

        delete_privilege('autocomplete_keyword_catalogue_category');
        delete_privilege('autocomplete_title_catalogue_category');
    }

    /**
     * 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($upgrade_from = null, $upgrade_from_hack = null)
    {
        require_lang('catalogues');
        require_code('catalogues');
        require_code('catalogues2');
        require_code('lang3');

        if (is_null($upgrade_from)) {
            $GLOBALS['SITE_DB']->create_table('catalogues', array(
                'c_name' => '*ID_TEXT',
                'c_title' => 'SHORT_TRANS',
                'c_description' => 'LONG_TRANS__COMCODE',
                'c_display_type' => 'SHORT_INTEGER', // C_DT_*
                'c_is_tree' => 'BINARY',
                'c_notes' => 'LONG_TEXT',
                'c_add_date' => 'TIME',
                'c_submit_points' => 'INTEGER',
                'c_ecommerce' => 'BINARY',
                'c_default_review_freq' => '?INTEGER',
                'c_send_view_reports' => 'ID_TEXT' // never,daily,weekly,monthly,quarterly
            ));

            $GLOBALS['SITE_DB']->create_table('catalogue_categories', array(
                'id' => '*AUTO',
                'c_name' => 'ID_TEXT',
                'cc_title' => 'SHORT_TRANS',
                'cc_description' => 'LONG_TRANS__COMCODE',
                'rep_image' => 'URLPATH',
                'cc_notes' => 'LONG_TEXT',
                'cc_add_date' => 'TIME',
                'cc_parent_id' => '?AUTO_LINK',
                'cc_move_target' => '?AUTO_LINK',
                'cc_move_days_lower' => 'INTEGER',
                'cc_move_days_higher' => 'INTEGER',
                'cc_order' => 'INTEGER',
            ));
            $GLOBALS['SITE_DB']->create_index('catalogue_categories', 'catstoclean', array('cc_move_target'));
            $GLOBALS['SITE_DB']->create_index('catalogue_categories', 'cataloguefind', array('c_name'));
            $GLOBALS['SITE_DB']->create_index('catalogue_categories', 'cc_parent_id', array('cc_parent_id'));

            $GLOBALS['SITE_DB']->create_table('catalogue_fields', array(
                'id' => '*AUTO',
                'c_name' => 'ID_TEXT',
                'cf_name' => 'SHORT_TRANS',
                'cf_description' => 'LONG_TRANS',
                'cf_type' => 'ID_TEXT',
                'cf_order' => 'INTEGER',
                'cf_defines_order' => 'SHORT_INTEGER', // 0, 1, or 2
                'cf_visible' => 'BINARY',
                'cf_searchable' => 'BINARY',
                'cf_default' => 'LONG_TEXT',
                'cf_required' => 'BINARY',
                'cf_put_in_category' => 'BINARY',
                'cf_put_in_search' => 'BINARY',
                'cf_options' => 'SHORT_TEXT',
            ));

            $GLOBALS['SITE_DB']->create_table('catalogue_entries', array(
                'id' => '*AUTO',
                'c_name' => 'ID_TEXT',
                'cc_id' => 'AUTO_LINK',
                'ce_submitter' => 'MEMBER',
                'ce_add_date' => 'TIME',
                'ce_edit_date' => '?TIME',
                'ce_views' => 'INTEGER',
                'ce_views_prior' => 'INTEGER',
                'ce_validated' => 'BINARY',
                'notes' => 'LONG_TEXT',
                'allow_rating' => 'BINARY',
                'allow_comments' => 'SHORT_INTEGER',
                'allow_trackbacks' => 'BINARY',
                'ce_last_moved' => 'INTEGER',
            ));
            $GLOBALS['SITE_DB']->create_index('catalogue_entries', 'ce_views', array('ce_views'));
            $GLOBALS['SITE_DB']->create_index('catalogue_entries', 'ces', array('ce_submitter'));
            $GLOBALS['SITE_DB']->create_index('catalogue_entries', 'ce_validated', array('ce_validated'));

            $GLOBALS['SITE_DB']->create_table('catalogue_efv_long_trans', array(
                'id' => '*AUTO', // NEVER use this column: cf_id and ce_id also provide a key. This only exists for the SQL-server fulltext indexing. This column doesn't exist on upgraded old installs.
                'cf_id' => 'AUTO_LINK',
                'ce_id' => 'AUTO_LINK',
                'cv_value' => 'LONG_TRANS__COMCODE', /* does your CV have value? */ // often Comcode but not always
            ));

            $GLOBALS['SITE_DB']->create_table('catalogue_efv_long', array(
                'id' => '*AUTO', // NEVER use this column: cf_id and ce_id also provide a key. This only exists for the SQL-server fulltext indexing. This column doesn't exist on upgraded old installs.
                'cf_id' => 'AUTO_LINK',
                'ce_id' => 'AUTO_LINK',
                'cv_value' => 'LONG_TEXT',
            ));

            $GLOBALS['SITE_DB']->create_table('catalogue_efv_short_trans', array(
                'id' => '*AUTO', // NEVER use this column: cf_id and ce_id also provide a key. This only exists for the SQL-server fulltext indexing. This column doesn't exist on upgraded old installs.
                'cf_id' => 'AUTO_LINK',
                'ce_id' => 'AUTO_LINK',
                'cv_value' => 'SHORT_TRANS__COMCODE', // often Comcode but not always
            ));

            $GLOBALS['SITE_DB']->create_table('catalogue_efv_short', array(
                'id' => '*AUTO', // NEVER use this column: cf_id and ce_id also provide a key. This only exists for the SQL-server fulltext indexing. This column doesn't exist on upgraded old installs.
                'cf_id' => 'AUTO_LINK',
                'ce_id' => 'AUTO_LINK',
                'cv_value' => 'SHORT_TEXT',
            ));
        }

        if ((is_null($upgrade_from)) || ($upgrade_from < 6)) {
            $GLOBALS['SITE_DB']->create_table('catalogue_entry_linkage', array(
                'catalogue_entry_id' => '*AUTO_LINK',
                'content_type' => 'ID_TEXT',
                'content_id' => 'ID_TEXT',
            ));
            $GLOBALS['SITE_DB']->create_index('catalogue_entry_linkage', 'custom_fields', array('content_type', 'content_id'));

            // This caches ancestor relationships. It is redundant to doing tree traversals on catalogue_categories.cc_id, allowing normal efficient SQL joins to be done instead
            // Note that self relationships (cc_id=cc_ancestor_id) are stored too, so that a single join covers that too.
            $GLOBALS['SITE_DB']->create_table('catalogue_cat_treecache', array(
                'cc_id' => '*AUTO_LINK',
                'cc_ancestor_id' => '*AUTO_LINK',
            ));
            $GLOBALS['SITE_DB']->create_table('catalogue_childcountcache', array(
                'cc_id' => '*AUTO_LINK',
                'c_num_rec_children' => 'INTEGER',
                'c_num_rec_entries' => 'INTEGER',
            ));
            $GLOBALS['SITE_DB']->create_index('catalogue_cat_treecache', 'cc_ancestor_id', array('cc_ancestor_id'));

            $GLOBALS['SITE_DB']->create_table('catalogue_efv_float', array(
                'id' => '*AUTO', // NEVER use this column: cf_id and ce_id also provide a key. This only exists for the SQL-server fulltext indexing. This column doesn't exist on upgraded old installs.
                'cf_id' => 'AUTO_LINK',
                'ce_id' => 'AUTO_LINK',
                'cv_value' => '?REAL',
            ));

            $GLOBALS['SITE_DB']->create_table('catalogue_efv_integer', array(
                'id' => '*AUTO', // NEVER use this column: cf_id and ce_id also provide a key. This only exists for the SQL-server fulltext indexing. This column doesn't exist on upgraded old installs.
                'cf_id' => 'AUTO_LINK',
                'ce_id' => 'AUTO_LINK',
                'cv_value' => '?INTEGER',
            ));

            $GLOBALS['SITE_DB']->create_index('catalogue_efv_float', 'fcv_value', array('cv_value'));
            $GLOBALS['SITE_DB']->create_index('catalogue_efv_integer', 'itv_value', array('cv_value'));

            $GLOBALS['SITE_DB']->create_index('catalogue_efv_float', 'fcf_id', array('cf_id'));
            $GLOBALS['SITE_DB']->create_index('catalogue_efv_integer', 'icf_id', array('cf_id'));
            $GLOBALS['SITE_DB']->create_index('catalogue_efv_float', 'fce_id', array('ce_id'));
            $GLOBALS['SITE_DB']->create_index('catalogue_efv_integer', 'ice_id', array('ce_id'));

            $GLOBALS['SITE_DB']->create_index('catalogue_efv_float', 'cefv_f_combo', array('ce_id', 'cf_id'));
            $GLOBALS['SITE_DB']->create_index('catalogue_efv_integer', 'cefv_i_combo', array('ce_id', 'cf_id'));
            $GLOBALS['SITE_DB']->create_index('catalogue_efv_long', 'cefv_l_combo', array('ce_id', 'cf_id'));
            $GLOBALS['SITE_DB']->create_index('catalogue_efv_short', 'cefv_s_combo', array('ce_id', 'cf_id'));
            $GLOBALS['SITE_DB']->create_index('catalogue_efv_long_trans', 'cefv_lt_combo', array('ce_id', 'cf_id'));
            $GLOBALS['SITE_DB']->create_index('catalogue_efv_short_trans', 'cefv_st_combo', array('ce_id', 'cf_id'));
        }

        if (is_null($upgrade_from)) {
            // Add the default catalogues
            // ==========================

            require_code('permissions2');

            // Projects
            actual_add_catalogue('projects', lang_code_to_default_content('c_title', 'DEFAULT_CATALOGUE_PROJECTS_TITLE', false, 2), '', C_DT_FIELDMAPS, 0, '', 30);
            $fields = array(
                array('NAME', 'DESCRIPTION_NAME', 'short_trans', 1, 1, ''),
                array('MAINTAINER', 'DESCRIPTION_MAINTAINER', 'member', 0, 1, '!'),
                array('DESCRIPTION', 'DESCRIPTION_DESCRIPTION', 'long_trans', 0, 1, ''),
                array('PROJECT_PROGRESS', 'DESCRIPTION_PROJECT_PROGRESS', 'integer', 0, 1, '0')
            );
            foreach ($fields as $i => $field) {
                actual_add_catalogue_field(
                    'projects', // $c_name
                    lang_code_to_default_content('cf_name', $field[0], false, 2), // $name
                    lang_code_to_default_content('cf_description', $field[1], false, 3), // $description
                    $field[2], // $type
                    $i, // $order
                    $field[3], // $defines_order
                    1, // $visible
                    1, // $searchable
                    $field[5], // $default
                    $field[4] // $required
                );
            }
            $cat_id = actual_add_catalogue_category('projects', lang_code_to_default_content('cc_title', 'DEFAULT_CATALOGUE_PROJECTS_TITLE', false, 2), lang_code_to_default_content('cc_description', 'DEFAULT_CATALOGUE_PROJECTS_DESCRIPTION', true, 3), '', null, '');
            set_global_category_access('catalogues_catalogue', 'projects');
            set_global_category_access('catalogues_category', $cat_id);

            // Links
            actual_add_catalogue('links', lang_code_to_default_content('c_title', 'DEFAULT_CATALOGUE_LINKS_TITLE', false, 2), lang_code_to_default_content('c_description', 'DEFAULT_CATALOGUE_LINKS_DESCRIPTION', true, 3), C_DT_TABULAR, 1, '', 0);
            $fields = array(
                // Name, Description, Type, Defines order, Required, Put in category
                array('TITLE', 'DESCRIPTION_TITLE', 'short_trans', 1, 1, 1),
                array('URL', 'DESCRIPTION_URL', 'url', 0, 1, 0),
                array('DESCRIPTION', 'DESCRIPTION_DESCRIPTION', 'long_trans', 0, 0, 1)
            );
            foreach ($fields as $i => $field) {
                actual_add_catalogue_field(
                    'links', // $c_name
                    lang_code_to_default_content('cf_name', $field[0], false, 2), // $name
                    lang_code_to_default_content('cf_description', $field[1], false, 3), // $description
                    $field[2], // $type
                    $i, // $order
                    $field[3], // $defines_order
                    1, // $visible
                    1, // $searchable
                    '', // $default
                    $field[4], // $required
                    $field[5] // $put_in_category
                );
            }
            $cat_id = $GLOBALS['SITE_DB']->query_select_value_if_there('catalogue_categories', 'id', array('c_name' => 'links'));
            set_global_category_access('catalogues_catalogue', 'links');
            set_global_category_access('catalogues_category', $cat_id);

            // FAQs
            actual_add_catalogue('faqs', lang_code_to_default_content('c_title', 'DEFAULT_CATALOGUE_FAQS_TITLE', false, 2), '', C_DT_FIELDMAPS, 0, '', 0);
            $fields = array(
                array('QUESTION', 'DESCRIPTON_QUESTION', 'short_trans', 0, 1, 1, ''),
                array('ANSWER', '_DESCRIPTION_ANSWER', 'long_trans', 0, 1, 1, ''),
                array('ORDER', 'DESCRIPTION_ORDER', 'integer', 1, 0, 0, 'AUTO_INCREMENT')
            );
            foreach ($fields as $i => $field) {
                actual_add_catalogue_field(
                    'faqs', // $c_name
                    lang_code_to_default_content('cf_name', $field[0], false, 2), // $name
                    lang_code_to_default_content('cf_description', $field[1], false, 3), // $description
                    $field[2], // $type
                    $i, // $order
                    $field[3], // $defines_order
                    $field[5], // $visible
                    1, // $searchable
                    '', // $default
                    $field[4], // $required
                    1, // $put_in_category
                    1, // $put_in_search
                    $field[6] // $options
                );
            }
            $cat_id = actual_add_catalogue_category('faqs', lang_code_to_default_content('cc_title', 'DEFAULT_CATALOGUE_FAQS_TITLE', false, 2), lang_code_to_default_content('cc_description', 'DEFAULT_CATALOGUE_FAQS_DESCRIPTION', true, 3), '', null, '');
            set_global_category_access('catalogues_catalogue', 'faqs');
            set_global_category_access('catalogues_category', $cat_id);

            // Contacts
            actual_add_catalogue('contacts', lang_code_to_default_content('c_title', 'CONTACTS', false, 2), lang_code_to_default_content('c_description', 'DEFAULT_CATALOGUE_CONTACTS_DESCRIPTION', true, 2), C_DT_FIELDMAPS, 0, '', 30);
            $fields = array(
                array('CONTACT_FIRST_NAME', '', 'short_text', 0, 1),
                array('CONTACT_LAST_NAME', '', 'short_text', 1, 1),
                array('EMAIL_ADDRESS', '', 'short_text', 0, 0),
                array('CONTACT_COMPANY', '', 'short_text', 0, 0),
                array('CONTACT_HOMEADDRESS', '', 'short_text', 0, 0),
                array('CONTACT_CITY', '', 'short_text', 0, 0),
                array('CONTACT_HOMEPHONE', '', 'short_text', 0, 0),
                array('CONTACT_WORKPHONE', '', 'short_text', 0, 0),
                array('CONTACT_HOMEPAGE', '', 'short_text', 0, 0),
                array('CONTACT_IM', '', 'short_text', 0, 0),
                array('NOTES', '', 'long_text', 0, 0),
                array('CONTACT_PHOTO', '', 'picture', 0, 0)
            );
            foreach ($fields as $i => $field) {
                actual_add_catalogue_field(
                    'contacts', // $c_name
                    lang_code_to_default_content('cf_name', $field[0], false, 2), // $name
                    insert_lang('cf_description', '', 3), // $description
                    $field[2], // $type
                    $i, // $order
                    $field[3], // $defines_order
                    1, // $visible
                    1, // $searchable
                    '', // $default
                    $field[4] // $required
                );
            }
            actual_add_catalogue_category('contacts', lang_code_to_default_content('cc_title', 'CONTACTS', false, 2), '', '', null, '');

            // Products
            actual_add_catalogue('products', lang_code_to_default_content('c_title', 'DEFAULT_CATALOGUE_PRODUCTS_TITLE', false, 2), lang_code_to_default_content('c_description', 'DEFAULT_CATALOGUE_PRODUCTS_DESCRIPTION', true, 2), C_DT_GRID, 1, '', 0, 1);
            $cat_id = $GLOBALS['SITE_DB']->query_select_value_if_there('catalogue_categories', 'id', array('c_name' => 'products'));
            $fields = array(
                //     Name  Description  Type  Defines order  Required  Visible  Searchable
                array('ECOM_CAT_product_title', 'DESCRIPTION_TITLE', 'short_trans', 1, 1, 1, 1),
                array('ECOM_CAT_sku', 'ECOM_CATD_sku', 'codename', 0, 1, 1, 1, 'RANDOM'),
                array('ECOM_CAT_price_pre_tax', 'ECOM_CATD_price_pre_tax', 'float', 0, 1, 1, 1, 'decimal_points_behaviour=price'),
                array('ECOM_CAT_stock_level', 'ECOM_CATD_stock_level', 'integer', 0, 0, 1, 0),
                array('ECOM_CAT_stock_level_warn_at', 'ECOM_CATD_stock_level_warn_at', 'integer', 0, 0, 0, 0),
                array('ECOM_CAT_stock_level_maintain', 'ECOM_CATD_stock_level_maintain', 'tick'/*will save as list*/, 0, 1, 0, 0),
                array('ECOM_CAT_tax_type', 'ECOM_CATD_tax_type', 'list', 0, 1, 0, 0, "0%|5%|17.5%"),
                array('ECOM_CAT_image', 'ECOM_CATD_image', 'picture', 0, 0, 1, 1),
                array('ECOM_CAT_weight', 'ECOM_CATD_weight', 'float', 0, 1, 0, 0),
                array('ECOM_CAT_description', 'DESCRIPTION_DESCRIPTION', 'long_trans', 0, 1, 1, 1)
            );
            foreach ($fields as $i => $field) {
                actual_add_catalogue_field(
                    'products', // $c_name
                    lang_code_to_default_content('cf_name', $field[0], false, 2), // $name
                    lang_code_to_default_content('cf_description', $field[1], false, 3), // $description
                    ($field[2] == 'tick') ? 'list' : $field[2], // $type
                    $i, // $order
                    $field[3], // $defines_order
                    $field[5], // $visible
                    $field[6], // $searchable
                    ($field[2] == 'tick') ? (do_lang('NO') . '|' . do_lang('YES')) : (array_key_exists(7, $field) ? $field[7] : ''), // $default
                    $field[4], // $required
                    array_key_exists(5, $field) ? $field[5] : 0, // $put_in_category
                    array_key_exists(5, $field) ? $field[5] : 0, // $put_in_search
                    array_key_exists(8, $field) ? $field[8] : '' // $options
                );
            }
            set_global_category_access('catalogues_catalogue', 'products');
            set_global_category_access('catalogues_category', $cat_id);

            add_privilege('CATALOGUES', 'high_catalogue_entry_timeout', false);

            $GLOBALS['SITE_DB']->create_index('catalogue_efv_long', '#lcv_value', array('cv_value'));
            $GLOBALS['SITE_DB']->create_index('catalogue_efv_short', '#scv_value', array('cv_value'));
            //$GLOBALS['SITE_DB']->create_index('catalogue_efv_long', 'ilcv_value', array('cv_value'));  Not allowed, LONG_TEXT can not be in an index (except fulltext indices). People shouldn't order by this anyway
            $GLOBALS['SITE_DB']->create_index('catalogue_efv_short', 'iscv_value', array('cv_value'));
            $GLOBALS['SITE_DB']->create_index('catalogue_efv_long', 'lcf_id', array('cf_id'));
            $GLOBALS['SITE_DB']->create_index('catalogue_efv_short', 'scf_id', array('cf_id'));
            $GLOBALS['SITE_DB']->create_index('catalogue_efv_long_trans', 'ltcf_id', array('cf_id'));
            $GLOBALS['SITE_DB']->create_index('catalogue_efv_short_trans', 'stcf_id', array('cf_id'));
            $GLOBALS['SITE_DB']->create_index('catalogue_efv_long', 'lce_id', array('ce_id'));
            $GLOBALS['SITE_DB']->create_index('catalogue_efv_short', 'sce_id', array('ce_id'));
            $GLOBALS['SITE_DB']->create_index('catalogue_efv_long_trans', 'ltce_id', array('ce_id'));
            $GLOBALS['SITE_DB']->create_index('catalogue_efv_short_trans', 'stce_id', array('ce_id'));
            $GLOBALS['SITE_DB']->create_index('catalogue_entries', 'ce_cc_id', array('cc_id'));
            $GLOBALS['SITE_DB']->create_index('catalogue_categories', 'ftjoin_cctitle', array('cc_title'));
            $GLOBALS['SITE_DB']->create_index('catalogue_categories', 'ftjoin_ccdescrip', array('cc_description'));
            $GLOBALS['SITE_DB']->create_index('catalogue_efv_long_trans', 'ltcv_value', array('cv_value'));
            $GLOBALS['SITE_DB']->create_index('catalogue_efv_short_trans', 'stcv_value', array('cv_value'));
        }

        if ((is_null($upgrade_from)) || ($upgrade_from < 6)) {
            $GLOBALS['SITE_DB']->create_index('catalogue_entries', 'ce_add_date', array('ce_add_date'));
            $GLOBALS['SITE_DB']->create_index('catalogue_entries', 'ce_c_name', array('c_name'));
        }

        if ((!is_null($upgrade_from)) && ($upgrade_from < 6)) {
            require_code('catalogues2');
            rebuild_catalogue_cat_treecache();

            // Move floats and integers into their own new tables
            if (php_function_allowed('set_time_limit')) {
                @set_time_limit(0);
            }
            $sql_integer = db_string_equal_to('cf_type', 'integer') . ' OR ' . db_string_equal_to('cf_type', 'member') . ' OR ' . db_string_equal_to('cf_type', 'tick');
            $sql_float = db_string_equal_to('cf_type', 'float');
            foreach (array($sql_float => 'float', $sql_integer => 'integer') as $where => $new_type) {
                $fields = $GLOBALS['SITE_DB']->query('SELECT id FROM ' . get_table_prefix() . 'catalogue_fields WHERE ' . $where, null, null, false, true);
                foreach ($fields as $field) {
                    do {
                        $or_list = '';
                        $rows = $GLOBALS['SITE_DB']->query_select('catalogue_efv_short', array('*'), array('cf_id' => $field['id']), '', 100);
                        foreach ($rows as $row) {
                            if ($or_list != '') {
                                $or_list .= ' OR ';
                            }
                            $or_list .= 'ce_id=' . strval($row['ce_id']) . ' AND cf_id=' . strval($row['cf_id']);

                            unset($row['id']);
                            if ($new_type == 'float') {
                                $row['cv_value'] = ($row['cv_value'] == '') ? null : floatval($row['cv_value']);
                            } elseif ($new_type == 'integer') {
                                $row['cv_value'] = ($row['cv_value'] == '') ? null : intval($row['cv_value']);
                            }
                            $GLOBALS['SITE_DB']->query_insert('catalogue_efv_' . $new_type, $row);
                        }
                        if ($or_list != '') {
                            $GLOBALS['SITE_DB']->query('DELETE FROM ' . get_table_prefix() . 'catalogue_efv_short WHERE ' . $or_list, null, null, false, true);
                        }
                    } while (count($rows) != 0);
                }
            }
        }

        if ((is_null($upgrade_from)) || ($upgrade_from < 8)) {
            $GLOBALS['SITE_DB']->create_index('catalogue_categories', '#cat_cat_search__combined', array('cc_title', 'cc_description'));

            add_privilege('SEARCH', 'autocomplete_keyword_catalogue_category', false);
            add_privilege('SEARCH', 'autocomplete_title_catalogue_category', false);
        }

        if ((!is_null($upgrade_from)) && ($upgrade_from < 8)) {
            $GLOBALS['SITE_DB']->add_table_field('catalogues', 'c_default_review_freq', '?INTEGER', null);

            require_code('content2');
            $GLOBALS['SITE_DB']->add_table_field('catalogue_categories', 'cc_order', 'INTEGER', ORDER_AUTOMATED_CRITERIA);

            $GLOBALS['SITE_DB']->add_table_field('catalogue_fields', 'cf_options', 'SHORT_TEXT');

            $GLOBALS['SITE_DB']->query_update('catalogue_fields', array('cf_type' => 'member'), array('cf_type' => 'user'));
            $GLOBALS['SITE_DB']->query_update('catalogue_fields', array('cf_type' => 'member_multi'), array('cf_type' => 'user_multi'));
            $GLOBALS['SITE_DB']->query_update('catalogue_fields', array('cf_type' => 'codename', 'cf_default' => 'RANDOM'), array('cf_type' => 'random'));
            $GLOBALS['SITE_DB']->query_update('catalogue_fields', array('cf_type' => 'list_multi', 'cf_options' => 'widget=vertical_checkboxes,custom_values=yes'), array('cf_type' => 'combo_multi'));
            $GLOBALS['SITE_DB']->query_update('catalogue_fields', array('cf_type' => 'list_multi'), array('cf_type' => 'multilist'));
            $GLOBALS['SITE_DB']->query_update('catalogue_fields', array('cf_type' => 'list_multi', 'cf_options' => 'widget=horizontal_checkboxes'), array('cf_type' => 'tick_multi'));
            $GLOBALS['SITE_DB']->query_update('catalogue_fields', array('cf_type' => 'list', 'cf_options' => 'widget=radio,custom_values=yes'), array('cf_type' => 'combo'));
            $GLOBALS['SITE_DB']->query_update('catalogue_fields', array('cf_type' => 'list', 'cf_options' => 'widget=radio'), array('cf_type' => 'radiolist'));
            $GLOBALS['SITE_DB']->query_update('catalogue_fields', array('cf_type' => 'integer', 'cf_default' => 'AUTO_INCREMENT'), array('cf_type' => 'auto_increment'));
        }

        if ((is_null($upgrade_from)) || ($upgrade_from < 8)) {
            $GLOBALS['SITE_DB']->create_index('catalogue_categories', 'cc_order', array('cc_order'));
        }
    }

    /**
     * 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 ($be_deferential) {
            return null;
        }

        $ret = array();
        if (!$support_crosslinks) { // Too low level if doing a full Sitemap
            $test = $GLOBALS['SITE_DB']->query_select_value_if_there('catalogue_entries', 'id');
            if ($test === null) {
                return null;
            }

            $ret['browse'] = array('CATALOGUES', 'menu/rich_content/catalogues/catalogues');
        }

        return $ret;
    }

    public $title;
    public $_title;
    public $catalogue_name;
    public $id;
    public $screen;
    public $catalogue;
    public $description_2;
    public $title_to_use;
    public $title_to_use_2;
    public $category;
    public $root;
    public $is_ecommerce;

    /**
     * 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()
    {
        $type = get_param_string('type', 'browse');

        require_lang('catalogues');
        require_code('catalogues');

        if ($type == 'browse') {
            $this->title = get_screen_title('CATALOGUES');

            set_feed_url('?mode=catalogues&select=');
        }

        if ($type == 'index') {
            $catalogue_name = get_param_string('id');
            set_feed_url('?mode=catalogues&select=' . urlencode($catalogue_name));

            // Read in catalogue details
            $catalogue = load_catalogue_row($catalogue_name);

            // Description
            $description_2 = get_translated_text($catalogue['c_description']);

            // Title
            $title_to_use = do_lang_tempcode($catalogue_name . '__CATALOGUE_INDEX', make_fractionable_editable('catalogue', $catalogue_name, get_translated_text($catalogue['c_title'])));
            $title_to_use_2 = do_lang($catalogue_name . '__CATALOGUE_INDEX', escape_html(get_translated_text($catalogue['c_title'])), null, null, null, false);
            if (is_null($title_to_use_2)) {
                $title_to_use = do_lang_tempcode('DEFAULT__CATALOGUE_INDEX', escape_html(get_translated_text($catalogue['c_title'])));
            }
            if ((get_value('no_awards_in_titles') !== '1') && (addon_installed('awards'))) {
                require_code('awards');
                $awards = find_awards_for('catalogue', $catalogue_name);
            } else {
                $awards = array();
            }
            $this->title = get_screen_title($title_to_use, false, null, null, $awards);

            // Check access
            if (!has_category_access(get_member(), 'catalogues_catalogue', $catalogue_name)) {
                access_denied('CATALOGUE_ACCESS');
            }

            // Breadcrumbs
            breadcrumb_set_parents(array(array('_SELF:_SELF:browse' . (($catalogue['c_ecommerce'] == 1) ? ':ecommerce=1' : ''), do_lang_tempcode('CATALOGUES'))));
            breadcrumb_set_self(get_translated_text($catalogue['c_title']));

            // Metadata
            set_extra_request_metadata(array(
                'identifier' => '_SEARCH:catalogues:index:' . $catalogue_name,
            ), $catalogue, 'catalogue', $catalogue_name);

            $this->catalogue_name = $catalogue_name;
            $this->catalogue = $catalogue;
            $this->description_2 = $description_2;
            $this->title_to_use = $title_to_use;
            $this->title_to_use_2 = $title_to_use_2;
        }

        if ($type == 'category') {
            // Find ID
            $id = get_param_integer('id', null);
            if ($id === null) {
                $id = $GLOBALS['SITE_DB']->query_select_value('catalogue_categories', 'MIN(id)', array('c_name' => get_param_string('catalogue_name'), 'cc_parent_id' => null));
                if (is_null($id)) {
                    warn_exit(do_lang_tempcode('NO_CATEGORIES', 'catalogue_category'));
                }
            }

            set_feed_url('?mode=catalogues&select=' . strval($id));

            // Get category
            $categories = $GLOBALS['SITE_DB']->query_select('catalogue_categories', array('*'), array('id' => $id), '', 1);
            if (!array_key_exists(0, $categories)) {
                return warn_screen(get_screen_title('CATALOGUES'), do_lang_tempcode('MISSING_RESOURCE', 'catalogue_category'));
            }
            $category = $categories[0];

            // Permission for here?
            if (!has_category_access(get_member(), 'catalogues_catalogue', $category['c_name'])) {
                access_denied('CATALOGUE_ACCESS');
            }
            if ((get_value('disable_cat_cat_perms') !== '1') && (!has_category_access(get_member(), 'catalogues_category', strval($id)))) {
                access_denied('CATEGORY_ACCESS');
            }

            // Pick up some data
            $catalogue_name = $category['c_name'];
            $root = get_param_integer('keep_catalogue_' . $catalogue_name . '_root', null);
            $_title = get_translated_text($category['cc_title']);

            // Screen title
            $title_to_use = do_lang_tempcode($catalogue_name . '__CATALOGUE_CATEGORY', make_fractionable_editable('catalogue_category', $id, $_title));
            $title_to_use_2 = do_lang($catalogue_name . '__CATALOGUE_CATEGORY', $_title, null, null, null, false);
            if (is_null($title_to_use_2)) {
                $title_to_use = do_lang_tempcode('DEFAULT__CATALOGUE_CATEGORY', escape_html($_title));
                $title_to_use_2 = do_lang('DEFAULT__CATALOGUE_CATEGORY', $_title);
            }
            $awards = array();
            if ((get_value('no_awards_in_titles') !== '1') && (addon_installed('awards'))) {
                require_code('awards');
                $awards = array_merge($awards, find_awards_for('catalogue', $catalogue_name));
                $awards = array_merge($awards, find_awards_for('catalogue_category', strval($id)));
            }
            $this->title = get_screen_title($title_to_use, false, null, null, $awards);

            // Metadata
            if (is_object($title_to_use_2)) {
                $title_to_use_2 = $title_to_use_2->evaluate();
            }
            seo_meta_load_for('catalogue_category', strval($id), $title_to_use_2);

            $catalogue = load_catalogue_row($catalogue_name);
            $is_ecommerce = is_ecommerce_catalogue($catalogue_name, $catalogue);

            $catalogue_title = get_translated_text($catalogue['c_title']);

            // Breadcrumbs
            $breadcrumbs = array();
            if ($root === null) {
                $breadcrumbs = array_merge($breadcrumbs, array(array('_SELF:_SELF:browse' . ($is_ecommerce ? ':ecommerce=1' : ''), do_lang_tempcode('CATALOGUES'))));
            }
            if ($catalogue['c_is_tree'] == 1) {
                $breadcrumbs = array_merge($breadcrumbs, catalogue_category_breadcrumbs($id, $root, true, true));
                if ((has_privilege(get_member(), 'open_virtual_roots')) && ($id != $root)) {
                    $page_link = build_page_link(array('page' => '_SELF', 'type' => 'category', 'id' => $id, 'keep_catalogue_' . $catalogue_name . '_root' => $id), '_SELF');
                    $breadcrumbs[] = array($page_link, $_title, do_lang_tempcode('VIRTUAL_ROOT'));
                } else {
                    $breadcrumbs[] = array('', $_title);
                }
            } else {
                if ($root === null) {
                    $page_link = build_page_link(array('page' => '_SELF', 'type' => 'index', 'id' => $catalogue_name, 'tree' => $catalogue['c_is_tree']), '_SELF');
                    $breadcrumbs[] = array($page_link, $catalogue_title);
                }
                $breadcrumbs[] = array('', $_title);
            }
            breadcrumb_set_parents($breadcrumbs);

            // Metadata
            set_extra_request_metadata(array(
                'type' => $catalogue_title . ' category',
                'identifier' => '_SEARCH:catalogues:category:' . strval($id),
            ), $category, 'catalogue_category', strval($id));

            $this->category = $category;
            $this->catalogue_name = $catalogue_name;
            $this->root = $root;
            $this->title_to_use = $title_to_use;
            $this->title_to_use_2 = $title_to_use_2;
            $this->id = $id;
            $this->catalogue = $catalogue;
            $this->is_ecommerce = $is_ecommerce;
            $this->_title = $_title;
            $this->catalogue_title = $catalogue_title;
        }

        if ($type == 'entry') {
            require_code('catalogues');
            $id = get_param_integer('id');
            $this->screen = render_catalogue_entry_screen($id);
        }

        if ($type == 'atoz') {
            $id = get_param_integer('id', null);
            $true_id = $id;

            if ($true_id === null) {
                $id = $GLOBALS['SITE_DB']->query_select_value('catalogue_categories', 'MIN(id)', array('c_name' => get_param_string('catalogue_name'), 'cc_parent_id' => null));
            }
            set_feed_url('?mode=catalogues&select=' . strval($id));

            $categories = $GLOBALS['SITE_DB']->query_select('catalogue_categories', array('*'), array('id' => $id), '', 1);
            if (!array_key_exists(0, $categories)) {
                return warn_screen(get_screen_title('CATALOGUES'), do_lang_tempcode('MISSING_RESOURCE', 'catalogue_category'));
            }
            $category = $categories[0];

            // Permission for here?
            if (!has_category_access(get_member(), 'catalogues_catalogue', $category['c_name'])) {
                access_denied('CATALOGUE_ACCESS');
            }

            breadcrumb_set_parents(array(array('_SELF:_SELF:browse' . (is_ecommerce_catalogue($category['c_name']) ? ':ecommerce=1' : ''), do_lang_tempcode('CATALOGUES'))));

            $catalogue = load_catalogue_row($category['c_name']);

            if ($true_id === null) {
                $_title = get_translated_text($catalogue['c_title']);
            } else {
                $_title = get_translated_text($category['cc_title']);
            }
            $title_to_use = do_lang_tempcode('DEFAULT__CATALOGUE_CATEGORY_ATOZ', escape_html($_title));
            $this->title = get_screen_title($title_to_use, false);

            $this->category = $category;
            $this->catalogue = $catalogue;
            $this->id = $id;
            $this->_title = $_title;
        }

        return null;
    }

    /**
     * Execute the module.
     *
     * @return Tempcode The result of execution.
     */
    public function run()
    {
        require_css('catalogues');

        $GLOBALS['NO_QUERY_LIMIT'] = true;

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

        if ($type == 'browse') {
            return $this->list_catalogues();
        }
        if ($type == 'index') {
            return $this->view_catalogue_index();
        }
        if ($type == 'category') {
            return $this->view_catalogue_category();
        }
        if ($type == 'atoz') {
            return $this->view_atoz();
        }
        if ($type == 'entry') {
            return $this->view_catalogue_entry();
        }

        return new Tempcode();
    }

    /**
     * The UI to show a list of catalogues to choose from.
     *
     * @return Tempcode The UI
     */
    public function list_catalogues()
    {
        $ecommerce = get_param_integer('ecommerce', null);

        $start = get_param_integer('catalogues_start', 0);
        $max = get_param_integer('catalogues_max', 30);

        // Not done via main_multi_content block due to need for custom filtering
        $query = 'FROM ' . get_table_prefix() . 'catalogues c';
        if (can_arbitrary_groupby()) {
            $query .= ' LEFT JOIN ' . get_table_prefix() . 'catalogue_entries e ON e.c_name=c.c_name';
        }
        $query .= ' WHERE ';
        $query .= is_null($ecommerce) ? '1=1' : ('c_ecommerce=' . strval($ecommerce));
        $query .= ' AND c.c_name NOT LIKE \'' . db_encode_like('\_%') . '\'';
        $rows = $GLOBALS['SITE_DB']->query('SELECT c.* ' . $query . (can_arbitrary_groupby() ? ' GROUP BY c.c_name' : ''), $max, $start);
        $max_rows = $GLOBALS['SITE_DB']->query_value_if_there('SELECT COUNT(DISTINCT c.c_name) ' . $query);
        $out = new Tempcode();
        foreach ($rows as $myrow) {
            $first_category = $GLOBALS['SITE_DB']->query_select_value_if_there('catalogue_categories', 'MIN(id)', array('c_name' => $myrow['c_name'], 'cc_parent_id' => null));
            if (is_null($first_category)) {
                continue; // No categories
            }

            if (!has_category_access(get_member(), 'catalogues_catalogue', $myrow['c_name'])) {
                continue; // No access
            }

            $test = $GLOBALS['SITE_DB']->query_select_value_if_there('catalogue_entries', 'id', array('c_name' => $myrow['c_name']));
            if ($test === null) {
                continue; // No entries
            }

            $out->attach(render_catalogue_box($myrow, '_SELF', false));
        }

        require_code('templates_pagination');
        $pagination = pagination(do_lang_tempcode('CATALOGUES'), $start, 'catalogues_start', $max, 'catalogues_max', $max_rows);

        $tpl = do_template('PAGINATION_SCREEN', array('_GUID' => '5af7dcb5bd26550ca6f26c2f9108f478', 'TITLE' => $this->title, 'CONTENT' => $out, 'PAGINATION' => $pagination));

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

    /**
     * The UI to show the index of a catalogue.
     *
     * @return Tempcode The UI
     */
    public function view_catalogue_index()
    {
        $catalogue_name = $this->catalogue_name;
        $catalogue = $this->catalogue;
        $description_2 = $this->description_2;
        $title_to_use = $this->title_to_use;
        $title_to_use_2 = $this->title_to_use_2;

        // Description
        $description = get_translated_tempcode('catalogues', $catalogue, 'c_description');

        // Read in categories
        if ($GLOBALS['SITE_DB']->query_select_value('catalogue_categories', 'COUNT(*)', array('c_name' => $catalogue_name)) > intval(get_option('general_safety_listing_limit')) * 3) {
            warn_exit(do_lang_tempcode('TOO_MANY_TO_CHOOSE_FROM'));
        }
        $rows_subcategories = $GLOBALS['SITE_DB']->query_select(
            'catalogue_categories',
            array('*'),
            array('c_name' => $catalogue_name),
            'ORDER BY cc_order,' . ((get_value('cc_sort_date__' . $catalogue_name) === '1') ? 'cc_add_date' : $GLOBALS['SITE_DB']->translate_field_ref('cc_title'))
        );

        // Render categories
        // Not done via main_multi_content block due to need for custom query
        $content = new Tempcode();
        foreach ($rows_subcategories as $myrow) {
            if ((get_value('disable_cat_cat_perms') !== '1') && (!has_category_access(get_member(), 'catalogues_category', strval($myrow['id'])))) {
                continue;
            }

            $content->attach(render_catalogue_category_box($myrow, '_SELF', false, false, null, true));
        }

        // Management links
        $edit_url = build_url(array('page' => 'cms_catalogues', 'type' => '_edit_catalogue', 'id' => $catalogue_name), get_module_zone('cms_catalogues'));
        if (has_actual_page_access(null, 'cms_catalogues', null, array('catalogues_catalogue', $catalogue_name), 'submit_cat_midrange_content')) {
            $add_cat_url = build_url(array('page' => 'cms_catalogues', 'type' => 'add_category', 'catalogue_name' => $catalogue_name), get_module_zone('cms_catalogues'));
        } else {
            $add_cat_url = new Tempcode();
        }

        // Render
        return do_template('PAGINATION_SCREEN', array(
            '_GUID' => '9ac6f5967177b020bebfe8b4ace35eff',
            'TITLE' => $this->title,
            'DESCRIPTION' => $description,
            'CATALOGUE' => $catalogue_name, // Not an official PAGINATION_SCREEN parameter, but could be useful
            'CONTENT' => $content,
            'ADD_CAT_URL' => $add_cat_url,
            'ADD_CAT_TITLE' => do_lang_tempcode('ADD_CATALOGUE_CATEGORY'),
            'EDIT_URL' => $edit_url,
            'EDIT_LABEL' => do_lang_tempcode('EDIT_CATALOGUE'),
        ));
    }

    /**
     * The UI to show a catalogue A-Z screen.
     *
     * @return Tempcode The UI
     */
    public function view_atoz()
    {
        $id = $this->id;
        $true_id = get_param_integer('id', null); // Needs to be true URL $id, not one automatically set to root category if not passed

        $_title = $this->_title;

        $category = $this->category;
        $catalogue_name = $category['c_name'];
        $root = get_param_integer('keep_catalogue_' . $catalogue_name . '_root', null);
        $catalogue = $this->catalogue;

        $tpl_set = $catalogue_name;

        $category_buildup = new Tempcode();

        $max = null;
        $start = null;

        if ($true_id === null) { // All entries in catalogue
            $sql_select = db_string_equal_to('c_name', $catalogue_name);
        } else { // All entries under category (going deep)
            require_code('selectcode');
            $sql_select = selectcode_to_sqlfragment(strval($id) . '*', 'cc_id', 'catalogue_categories', 'cc_parent_id', 'cc_id', 'id'); // Note that the parameters are fiddled here so that category-set and record-set are the same, yet SQL is returned to deal in an entirely different record-set (entries' record-set)
        }

        if ($GLOBALS['SITE_DB']->query_value_if_there('SELECT COUNT(*) FROM ' . get_table_prefix() . 'catalogue_entries p WHERE ce_validated=1 AND (' . $sql_select . ')', false, true) > intval(get_option('general_safety_listing_limit')) * 3) {
            warn_exit(do_lang_tempcode('TOO_MANY_TO_CHOOSE_FROM'));
        }
        $cats = array();

        $privacy_join = '';
        $privacy_where = '';
        if (addon_installed('content_privacy')) {
            require_code('content_privacy');
            list($privacy_join, $privacy_where) = get_privacy_where_clause('catalogue_entry', 'p');
        }

        // Not done via main_cc_entries block due to complex organisation
        $rows = $GLOBALS['SITE_DB']->query('SELECT * FROM ' . get_table_prefix() . 'catalogue_entries p' . $privacy_join . ' WHERE ce_validated=1 AND (' . $sql_select . ')' . $privacy_where, null, null, false, true);
        foreach ($rows as $row) {
            $entry_map = get_catalogue_entry_map($row, $catalogue, 'CATEGORY', 'DEFAULT', $root, null, array(0), false, false);
            $letter = strtoupper(substr(is_object($entry_map['FIELD_0_PLAIN']) ? $entry_map['FIELD_0_PLAIN']->evaluate() : $entry_map['FIELD_0_PLAIN'], 0, 1));

            if ((get_value('disable_cat_cat_perms') !== '1') && (!has_category_access(get_member(), 'catalogues_category', strval($row['cc_id'])))) {
                continue;
            }

            if (!array_key_exists($letter, $cats)) {
                $cats[$letter] = array();
            }
            $cats[$letter][] = $row;
        }
        unset($rows);

        if (count($cats) == 0) {
            inform_exit(do_lang_tempcode('NO_CATEGORIES', 'catalogue_category'));
        }

        ksort($cats);
        $_display_type = C_DT_FIELDMAPS;
        foreach ($cats as $letter => $entries) {
            list($entry_buildup, , , , $_display_type) = render_catalogue_category_entry_buildup(null, $catalogue_name, $catalogue, 'CATEGORY', $tpl_set, $max, $start, null, $root, null, true, $entries);

            $category_buildup->attach(do_template('CATALOGUE_CATEGORY_HEADING', array('_GUID' => '633d73ad882c9f28524ad27120b77b78', 'LETTER' => is_integer($letter) ? strval($letter) : $letter, 'ENTRIES' => escape_html($entry_buildup)), null, false, 'CATALOGUE_CATEGORY_HEADING'));
        }

        // Find display type
        $display_type = '';
        switch ($_display_type) {
            case C_DT_FIELDMAPS:
                $display_type = 'FIELDMAPS';
                break;
            case C_DT_TITLELIST:
                $display_type = 'TITLELIST';
                break;
            case C_DT_TABULAR:
                $display_type = 'TABULAR';
                break;
            case C_DT_GRID:
                $display_type = 'GRID';
                break;
        }

        // Management links
        if (has_actual_page_access(null, 'cms_catalogues', null, (get_value('disable_cat_cat_perms') === '1') ? array('catalogues_catalogue', $catalogue_name) : array('catalogues_catalogue', $catalogue_name, 'catalogues_category', strval($id)), 'submit_midrange_content')) {
            $add_link = build_url(array('page' => 'cms_catalogues', 'type' => 'add_entry', 'catalogue_name' => $catalogue_name, 'category_id' => $id), get_module_zone('cms_catalogues'));
        } else {
            $add_link = new Tempcode();
        }
        if (has_actual_page_access(null, 'cms_catalogues', null, (get_value('disable_cat_cat_perms') === '1') ? array('catalogues_catalogue', $catalogue_name) : array('catalogues_catalogue', $catalogue_name, 'catalogues_category', strval($id)), 'submit_cat_midrange_content')) {
            $add_cat_url = build_url(array('page' => 'cms_catalogues', 'type' => 'add_category', 'catalogue_name' => $catalogue_name, 'parent_id' => $id), get_module_zone('cms_catalogues'));
        } else {
            $add_cat_url = new Tempcode();
        }
        if (has_actual_page_access(null, 'cms_catalogues', null, (get_value('disable_cat_cat_perms') === '1') ? array('catalogues_catalogue', $catalogue_name) : array('catalogues_catalogue', $catalogue_name, 'catalogues_category', strval($id)), 'edit_cat_midrange_content')) {
            $edit_cat_url = build_url(array('page' => 'cms_catalogues', 'type' => '_edit_category', 'catalogue_name' => $catalogue_name, 'id' => $id), get_module_zone('cms_catalogues'));
        } else {
            $edit_cat_url = new Tempcode();
        }
        if (has_actual_page_access(null, 'cms_catalogues', null, (get_value('disable_cat_cat_perms') === '1') ? array('catalogues_catalogue', $catalogue_name) : array('catalogues_catalogue', $catalogue_name), 'edit_cat_highrange_content')) {
            $edit_catalogue_url = build_url(array('page' => 'cms_catalogues', 'type' => '_edit_catalogue', 'id' => $catalogue_name), get_module_zone('cms_catalogues'));
        } else {
            $edit_catalogue_url = new Tempcode();
        }

        return do_template(
            'CATALOGUE_' . $tpl_set . '_CATEGORY_SCREEN',
            array(
                'TITLE' => $this->title,
                '_TITLE' => $_title,
                'TAGS' => get_loaded_tags('catalogue_categories'),
                'CATALOGUE' => $catalogue_name,
                'ADD_ENTRY_URL' => $add_link,
                'ADD_CAT_URL' => $add_cat_url,
                'ADD_CAT_TITLE' => do_lang_tempcode('ADD_CATALOGUE_CATEGORY'),
                'EDIT_CAT_URL' => $edit_cat_url,
                'EDIT_CATALOGUE_URL' => $edit_catalogue_url,
                'ENTRIES' => $category_buildup,
                'SUBCATEGORIES' => '',
                'DESCRIPTION' => '',
                'ID' => '',
                'DISPLAY_TYPE' => $display_type,
            ),
            null,
            false,
            'CATALOGUE_DEFAULT_CATEGORY_SCREEN'
        );
    }

    /**
     * The UI to show a catalogue category.
     *
     * @return Tempcode The UI
     */
    public function view_catalogue_category()
    {
        require_code('feedback');
        require_code('images');

        $id = $this->id;
        $category = $this->category;
        $catalogue_name = $this->catalogue_name;
        $root = $this->root;
        $title_to_use = $this->title_to_use;
        $title_to_use_2 = $this->title_to_use_2;
        $is_ecommerce = $this->is_ecommerce;
        $catalogue = $this->catalogue;
        $_title = $this->_title;

        $tpl_set = $catalogue_name;

        // Is eCommerce?
        if ($is_ecommerce) {
            $tpl_set = 'products';
        }
        if ($is_ecommerce) {
            if (get_forum_type() != 'cns') {
                warn_exit(do_lang_tempcode('NO_CNS'));
            }
        }

        // Management links
        if (has_actual_page_access(null, 'cms_catalogues', null, (get_value('disable_cat_cat_perms') === '1') ? array('catalogues_catalogue', $catalogue_name) : array('catalogues_catalogue', $catalogue_name, 'catalogues_category', strval($id)), 'submit_midrange_content')) {
            $add_link = build_url(array('page' => 'cms_catalogues', 'type' => 'add_entry', 'catalogue_name' => $catalogue_name, 'category_id' => $id), get_module_zone('cms_catalogues'));
        } else {
            $add_link = new Tempcode();
        }
        if (has_actual_page_access(null, 'cms_catalogues', null, (get_value('disable_cat_cat_perms') === '1') ? array('catalogues_catalogue', $catalogue_name) : array('catalogues_catalogue', $catalogue_name, 'catalogues_category', strval($id)), 'submit_cat_midrange_content')) {
            $add_cat_url = build_url(array('page' => 'cms_catalogues', 'type' => 'add_category', 'catalogue_name' => $catalogue_name, 'parent_id' => $id), get_module_zone('cms_catalogues'));
        } else {
            $add_cat_url = new Tempcode();
        }
        if (has_actual_page_access(null, 'cms_catalogues', null, (get_value('disable_cat_cat_perms') === '1') ? array('catalogues_catalogue', $catalogue_name) : array('catalogues_catalogue', $catalogue_name, 'catalogues_category', strval($id)), 'edit_cat_midrange_content')) {
            $edit_cat_url = build_url(array('page' => 'cms_catalogues', 'type' => '_edit_category', 'catalogue_name' => $catalogue_name, 'id' => $id), get_module_zone('cms_catalogues'));
        } else {
            $edit_cat_url = new Tempcode();
        }
        if (has_actual_page_access(null, 'cms_catalogues', null, (get_value('disable_cat_cat_perms') === '1') ? array('catalogues_catalogue', $catalogue_name) : array('catalogues_catalogue', $catalogue_name), 'edit_cat_highrange_content')) {
            $edit_catalogue_url = build_url(array('page' => 'cms_catalogues', 'type' => '_edit_catalogue', 'id' => $catalogue_name), get_module_zone('cms_catalogues'));
        } else {
            $edit_catalogue_url = new Tempcode();
        }

        // Find display type
        $display_type = '';
        switch ($catalogue['c_display_type']) {
            case C_DT_FIELDMAPS:
                $display_type = 'FIELDMAPS';
                break;
            case C_DT_TITLELIST:
                $display_type = 'TITLELIST';
                break;
            case C_DT_TABULAR:
                $display_type = 'TABULAR';
                break;
            case C_DT_GRID:
                $display_type = 'GRID';
                break;
        }

        // Get category contents
        if (get_value('cc_sort_date__' . $catalogue_name) !== '1') {
            $cc_sort = 'title ASC';
        } else {
            $cc_sort = 'recent ASC';
        }
        $subcategories = do_block('main_multi_content', array('param' => 'catalogue_category', 'select' => strval($id) . '>', 'efficient' => '0', 'zone' => get_zone_name(), 'sort' => $cc_sort, 'max' => get_option('catalogue_subcats_per_page'), 'no_links' => '1', 'pagination' => '1', 'give_context' => '0', 'include_breadcrumbs' => '0', 'attach_to_url_filter' => '1', 'render_if_empty' => '0', 'guid' => 'module'));
        if (get_option('catalogues_subcat_narrowin') == '1') {
            $cat_select = strval($id) . '*';
        } else {
            $cat_select = strval($id) . '#';
        }
        $filter = either_param_string('active_filter', '');
        $entries = do_block('main_cc_embed', array('param' => strval($id), 'select' => $cat_select, 'zone' => get_zone_name(), 'max' => get_option('catalogue_entries_per_page'), 'pagination' => '1', 'sorting' => '1', 'filter' => $filter, 'block_id' => 'module'));

        // Render
        return do_template('CATALOGUE_' . $tpl_set . '_CATEGORY_SCREEN', array(
            'ID' => strval($id),
            'DISPLAY_TYPE' => $display_type,
            'ADD_DATE_RAW' => strval($category['cc_add_date']),
            'TITLE' => $this->title,
            '_TITLE' => $_title,
            'CATALOGUE_TITLE' => $this->catalogue_title,
            'TAGS' => get_loaded_tags('catalogue_categories'),
            'CATALOGUE' => $catalogue_name,
            'ADD_ENTRY_URL' => $add_link,
            'ADD_CAT_URL' => $add_cat_url,
            'ADD_CAT_TITLE' => do_lang_tempcode('ADD_CATALOGUE_CATEGORY'),
            'EDIT_CAT_URL' => $edit_cat_url,
            'EDIT_CATALOGUE_URL' => $edit_catalogue_url,
            'ENTRIES' => $entries,
            'SUBCATEGORIES' => $subcategories,
            'DESCRIPTION' => get_translated_tempcode('catalogue_categories', $category, 'cc_description'),
        ), null, false, 'CATALOGUE_DEFAULT_CATEGORY_SCREEN');
    }

    /**
     * The UI to show a catalogue entry.
     *
     * @return Tempcode The UI
     */
    public function view_catalogue_entry()
    {
        return $this->screen;
    }
}
