function controller_pages($args)
{
    default_html(true);
    html_add_css(base_url() . 'modules/page_browser/page_browser.css');
    if (USE_MIN_FILES) {
        html_add_js(base_url() . 'modules/page_browser/page_browser.min.js');
    } else {
        html_add_js(base_url() . 'modules/page_browser/page_browser.js');
    }
    html_add_js_var('$.glue.conf.page.startpage', startpage());
    $bdy =& body();
    elem_attr($bdy, 'id', 'pages');
    body_append('<h1>All pages</h1>');
    load_modules('glue');
    $pns = pagenames(array());
    $pns = $pns['#data'];
    foreach ($pns as $pn) {
        // display only pages with 'head'
        if (is_dir(CONTENT_DIR . '/' . $pn . '/head')) {
            body_append('<div class="page_browser_entry" id="' . htmlspecialchars($pn, ENT_COMPAT, 'UTF-8') . '"><span class="page_browser_pagename"><a href="' . base_url() . '?' . htmlspecialchars(urlencode($pn), ENT_COMPAT, 'UTF-8') . '">' . htmlspecialchars($pn, ENT_NOQUOTES, 'UTF-8') . '</a></span> ');
            if ($pn . '.head' == startpage()) {
                body_append('<span id="page_browser_startpage">[startpage]</span> ');
            }
        }
        body_append('</div>');
    }
    echo html_finalize();
}
function controller_revisions($args)
{
    page_canonical($args[0][0]);
    $page = $args[0][0];
    if (!page_exists($page)) {
        hotglue_error(404);
    }
    // get all revisions of page and determine the current revision's index
    load_modules('glue');
    $a = expl('.', $page);
    $revs = revisions_info(array('pagename' => $a[0], 'sort' => 'time'));
    $revs = $revs['#data'];
    $cur_rev = false;
    for ($i = 0; $i < count($revs); $i++) {
        if ($revs[$i]['revision'] == $a[1]) {
            $cur_rev = $i;
            break;
        }
    }
    if ($cur_rev === false) {
        // we didn't find the current revision
        hotglue_error(500);
    }
    default_html(true);
    html_add_css(base_url() . 'modules/revisions_browser/revisions_browser.css');
    if (USE_MIN_FILES) {
        html_add_js(base_url() . 'modules/revisions_browser/revisions_browser.min.js');
    } else {
        html_add_js(base_url() . 'modules/revisions_browser/revisions_browser.js');
    }
    html_add_js_var('$.glue.page', $page);
    $bdy =& body();
    elem_attr($bdy, 'id', 'revisions');
    render_page(array('page' => $page, 'edit' => false));
    body_append('<div id="revisions_browser_ctrl">');
    body_append('<div id="revisions_browser_prev">');
    if ($cur_rev + 1 < count($revs)) {
        body_append('<a href="' . base_url() . '?' . htmlspecialchars(urlencode($revs[$cur_rev + 1]['page']), ENT_COMPAT, 'UTF-8') . '/revisions">prev</a>');
    }
    body_append('</div><div id="revisions_browser_cur">');
    if (substr($revs[$cur_rev]['revision'], 0, 5) == 'auto-') {
        body_append(date('d M y H:i', $revs[$cur_rev]['time']));
    } else {
        body_append(htmlspecialchars($revs[$cur_rev]['revision'], ENT_NOQUOTES, 'UTF-8'));
    }
    body_append('<br>');
    if ($a[1] == 'head') {
        body_append('<a href="' . base_url() . '?' . htmlspecialchars(urlencode($page), ENT_COMPAT, 'UTF-8') . '/edit">back to editing mode</a>');
    } else {
        body_append('<a id="revisions_browser_revert_btn" href="#">revert</a>');
    }
    body_append('</div><div id="revisions_browser_next">');
    if (0 < $cur_rev) {
        body_append('<a href="' . base_url() . '?' . htmlspecialchars(urlencode($revs[$cur_rev - 1]['page']), ENT_COMPAT, 'UTF-8') . '/revisions">next</a>');
    }
    body_append('</div>');
    body_append('</div>');
    echo html_finalize();
}
/**
 *	controller that shows a textarea for editing either a page's or the global 
 *	user-defined css file
 */
function controller_user_css_stylesheet($args)
{
    if ($args[0][1] == 'stylesheet') {
        // changing page stylesheet
        $page = $args[0][0];
        page_canonical($page);
        if (!page_exists($page)) {
            hotglue_error(404);
        }
    } else {
        // changing global stylesheet
        $page = false;
    }
    default_html(true);
    html_add_js_var('$.glue.page', $page);
    html_add_css(base_url() . 'modules/user_css/user_css.css');
    if (USE_MIN_FILES) {
        html_add_js(base_url() . 'modules/user_css/user_css.min.js');
    } else {
        html_add_js(base_url() . 'modules/user_css/user_css.js');
    }
    $bdy =& body();
    elem_attr($bdy, 'id', 'user_css');
    if ($page === false) {
        body_append('<h1>Global stylesheet</h1>' . nl());
        // try to load css
        $css = @file_get_contents(CONTENT_DIR . '/usercss');
        if ($css === false) {
            $css = '';
        }
    } else {
        body_append('<h1>' . htmlspecialchars($page, ENT_NOQUOTES, 'UTF-8') . ' stylesheet</h1>' . nl());
        load_modules('glue');
        $obj = load_object(array('name' => $page . '.usercss'));
        if ($obj['#error']) {
            $css = '';
        } else {
            $css = $obj['#data']['content'];
        }
    }
    // encoding to html must come before the replacement below
    $css = htmlspecialchars($css, ENT_NOQUOTES, 'UTF-8');
    // replace newline characters by an entity to prevent render_object()
    // from adding some indentation
    $css = str_replace("\r\n", '&#10;', $css);
    $css = str_replace("\n", '&#10;', $css);
    // why not replace tabs as well why we are at it
    $css = str_replace("\t", '&#09;', $css);
    body_append('<textarea id="user_css_text" placeholder="enter css code here">' . $css . '</textarea>' . nl());
    body_append('<br>' . nl());
    body_append('<input id="user_css_save" type="button" value="save">' . nl());
    echo html_finalize();
}
/**
 *	controller that shows a textarea for editing either a page's or the global 
 *	user-defined code files
 */
function controller_user_code_stylesheet($args)
{
    if ($args[0][1] == 'code') {
        // changing page code
        $page = $args[0][0];
        page_canonical($page);
        if (!page_exists($page)) {
            hotglue_error(404);
        }
    } else {
        // changing global code
        $page = false;
    }
    default_html(true);
    html_add_js_var('$.glue.page', $page);
    html_add_css(base_url() . 'modules/user_code/user_code.css');
    if (USE_MIN_FILES) {
        html_add_js(base_url() . 'modules/user_code/user_code.min.js');
    } else {
        html_add_js(base_url() . 'modules/user_code/user_code.js');
    }
    $bdy =& body();
    // create array with names of code elements
    $code = array('head' => '', 'body' => '');
    elem_attr($bdy, 'id', 'user_code');
    if ($page === false) {
        body_append('<h1>Global code</h1>' . nl());
        // try to load code
        foreach ($code as $x => $v) {
            $code[$x] = @file_get_contents(CONTENT_DIR . '/user' . $x);
            if ($code[$x] === false) {
                $code[$x] = '';
            }
        }
    } else {
        body_append('<h1>"' . htmlspecialchars(substr($page, 0, strpos($page, '.')), ENT_NOQUOTES, 'UTF-8') . '" page code</h1>' . nl());
        load_modules('glue');
        foreach ($code as $x => $v) {
            $obj = load_object(array('name' => $page . '.user' . $x));
            if ($obj['#error']) {
                $code[$x] = '';
            } else {
                $code[$x] = $obj['#data']['content'];
            }
        }
    }
    foreach ($code as $k => $v) {
        // encoding to html must come before the replacement below
        $v = htmlspecialchars($v, ENT_NOQUOTES, 'UTF-8');
        // replace newline characters by an entity to prevent render_object()
        // from adding some indentation
        $v = str_replace("\r\n", '&#10;', $v);
        $v = str_replace("\n", '&#10;', $v);
        // why not replace tabs as well why we are at it
        $v = str_replace("\t", '&#09;', $v);
        $code[$k] = $v;
    }
    body_append('<div id=\'text\'>add your custom code to &lt;head&gt; and &lt;body&gt; sections of this ' . ($page ? 'page.' : 'site.') . nl());
    body_append('<br>' . nl());
    body_append('be cautious - errors in the code below may render the whole ' . ($page ? 'page' : 'site') . ' unusable.</div>' . nl());
    body_append('<br>' . nl());
    body_append('<div id=\'fake_tags\'>&lt;head&gt;</div>' . nl());
    body_append('<textarea id="user_head_text" placeholder="enter code here">' . $code['head'] . '</textarea>' . nl());
    body_append('<br>' . nl());
    body_append('<div id=\'fake_tags\'>&lt;/head&gt;<br>' . nl());
    body_append('&lt;body&gt;</div>' . nl());
    body_append('<textarea id="user_body_text" placeholder="enter code here">' . $code['body'] . '</textarea>' . nl());
    body_append('<div id=\'fake_tags\'>&lt;/body&gt;</div><br>' . nl());
    body_append('<input id="user_code_save" type="button" value="save">' . nl());
    echo html_finalize();
}
function page_render_page_early($args)
{
    if ($args['edit']) {
        if (USE_MIN_FILES) {
            html_add_js(base_url() . 'modules/page/page-edit.min.js');
        } else {
            html_add_js(base_url() . 'modules/page/page-edit.js');
        }
        html_add_css(base_url() . 'modules/page/page-edit.css');
        // set default grid
        $grid = page_get_grid(array());
        $grid = $grid['#data'];
        html_add_js_var('$.glue.conf.page.default_grid_x', $grid['x']);
        html_add_js_var('$.glue.conf.page.default_grid_y', $grid['y']);
        // set guides
        $guide = expl(' ', PAGE_GUIDES_X);
        for ($i = 0; $i < count($guide); $i++) {
            $guide[$i] = intval(trim($guide[$i]));
        }
        html_add_js_var('$.glue.conf.page.guides_x', $guide);
        $guide = expl(' ', PAGE_GUIDES_Y);
        for ($i = 0; $i < count($guide); $i++) {
            $guide[$i] = intval(trim($guide[$i]));
        }
        html_add_js_var('$.glue.conf.page.guides_y', $guide);
    }
    // set the html title to the page name by default
    html_title(page_short($args['page']));
}
function object_render_page_early($args)
{
    if ($args['edit']) {
        if (USE_MIN_FILES) {
            html_add_js(base_url() . 'modules/object/object-edit.min.js');
        } else {
            html_add_js(base_url() . 'modules/object/object-edit.js');
        }
        // add default colors
        html_add_js_var('$.glue.conf.object.default_colors', expl(' ', OBJECT_DEFAULT_COLORS));
    }
}
function text_render_page_early($args)
{
    if ($args['edit']) {
        if (USE_MIN_FILES) {
            html_add_js(base_url() . 'modules/text/text-edit.min.js');
        } else {
            html_add_js(base_url() . 'modules/text/text-edit.js');
        }
        html_add_css(base_url() . 'modules/text/text-edit.css');
        html_add_js_var('$.glue.conf.text.auto_br', TEXT_AUTO_BR);
        if (TEXT_USE_WOFF_FONTS) {
            $woff_fonts = _woff_fonts();
            foreach ($woff_fonts as $font => $styles) {
                _include_woff_font($font);
                // TODO (later): check css encoding
                $rule = '.glue-font-woff-' . $font . ' {' . nl();
                // we use single quotes as they don't clash with inline styles
                $rule .= tab() . 'font-family: \'' . $font . '\';' . nl();
                $rule .= '}';
                html_add_css_inline($rule, 6);
            }
        }
    }
}
/**
 *	show a site to edit pages
 */
function controller_edit($args)
{
    handle_updates();
    // this is a good spot to log the server's php version as well
    log_msg('debug', 'controller_edit: running on php version ' . phpversion());
    // most of these checks are only necessary if the client calls
    // page/edit directly
    page_canonical($args[0][0]);
    $page = $args[0][0];
    if (!page_exists($page)) {
        log_msg('debug', 'controller_edit: page ' . quot($page) . ' does not exist, invoking controller_create_page');
        controller_create_page($args);
        return;
    }
    // create page on the fly
    load_modules('glue');
    default_html(true);
    html_add_js_var('$.glue.page', $page);
    html_add_css(base_url() . 'css/farbtastic.css', 2);
    html_add_css(base_url() . 'css/edit.css', 5);
    if (USE_MIN_FILES) {
        html_add_js(base_url() . 'js/jquery-ui-1.8.6.custom.min.js', 2);
    } else {
        html_add_js(base_url() . 'js/jquery-ui-1.8.6.custom.js', 2);
    }
    if (USE_MIN_FILES) {
        html_add_js(base_url() . 'js/farbtastic.min.js', 2);
    } else {
        html_add_js(base_url() . 'js/farbtastic.js', 2);
    }
    if (USE_MIN_FILES) {
        html_add_js(base_url() . 'js/jquery.xcolor-1.2.1.min.js', 2);
    } else {
        html_add_js(base_url() . 'js/jquery.xcolor-1.2.1.js', 2);
    }
    if (USE_MIN_FILES) {
        html_add_js(base_url() . 'js/edit.min.js', 4);
    } else {
        html_add_js(base_url() . 'js/edit.js', 4);
    }
    render_page(array('page' => $page, 'edit' => true));
    echo html_finalize();
    log_msg('debug', 'controller_edit: invoking check_auto_snapshot');
    check_auto_snapshot(array('page' => $page));
}
/**
 *	implements render_page_early
 */
function image_render_page_early($args)
{
    if ($args['edit']) {
        if (USE_MIN_FILES) {
            html_add_js(base_url() . 'modules/image/image-edit.min.js');
        } else {
            html_add_js(base_url() . 'modules/image/image-edit.js');
        }
        if (!_gd_available()) {
            html_add_js_var('$.glue.conf.image.resizing', false);
            log_msg('debug', 'image: disabling image resizing as gd is not available');
        } else {
            html_add_js_var('$.glue.conf.image.resizing', IMAGE_RESIZING);
        }
        html_add_js_var('$.glue.conf.image.upload_resize_larger', IMAGE_UPLOAD_RESIZE_LARGER);
        html_add_js_var('$.glue.conf.image.upload_resize_to', IMAGE_UPLOAD_RESIZE_TO);
    }
}
/**
 *	setup a default html page
 *
 *	see html.inc.php.
 *	@param bool $add_glue true for adding the glue code
 */
function default_html($add_glue)
{
    html_title(SITE_NAME);
    $favicon = FAVICON;
    if (!empty($favicon)) {
        if (is_url($favicon)) {
            html_favicon($favicon);
        } else {
            html_favicon(base_url() . $favicon);
        }
    }
    if (USE_MIN_FILES) {
        html_add_css(base_url() . 'css/reset.min.css', 1);
    } else {
        html_add_css(base_url() . 'css/reset.css', 1);
    }
    // 2 can be used for third-party components
    html_add_css(base_url() . 'css/main.css', 3);
    if ($add_glue) {
        html_add_css(base_url() . 'css/glue.css', 4);
    }
    if ($add_glue) {
        $jquery = JQUERY;
        if (is_url($jquery)) {
            html_add_js($jquery, 1);
        } else {
            html_add_js(base_url() . $jquery, 1);
        }
        // 2 can be used for third-party components
        if (USE_MIN_FILES) {
            html_add_js(base_url() . 'js/glue.min.js', 3);
        } else {
            html_add_js(base_url() . 'js/glue.js', 3);
        }
        html_add_js_var('$.glue.base_url', base_url());
        html_add_js_var('$.glue.conf.show_frontend_errors', SHOW_FRONTEND_ERRORS);
        html_add_js_var('$.glue.version', glue_version());
    }
}