<?php
/**
 * PyCode plugin: it embeds a Python script hosted in a remote repository.
 *
 * syntax.php: it defines all the methods used by PyCode plugin
 *      who extend DokuWiki's syntax.
 *
 * @author Torpedo <dgtorpedo@gmail.com>
 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
 * @package syntax
 */

if (!defined("DOKU_INC")) die();  // the plugin must be run within Dokuwiki

require_once "method.php";  // common methods used by PyCode plugin

/**
 * This class defines all the methods used by the PyCode plugin to produce
 * the plugin's output.
 *
 * It extends DokuWiki's basic syntax defined in lib/plugins/syntax.php.
 *
 * @package syntax_pycode
 */
class syntax_plugin_pycode extends DokuWiki_Syntax_Plugin {

    /**
     * Constructor method for class suitable for any initialization.
     */
    public function __construct() {
        $this->mpp = new method_pycode_plugin;
    }

    /**
     * Define the syntax types that this plugin applies when founds
     * its token: it is simply replaced.
     *
     * @return (str)
     */
    public function getType() {
        return "substition";
    }

    /**
     * Define how the plugin's output is handled regarding paragraphs.
     *
     * Open paragraphs will be closed before plugin output and
     * the plugin output will not starts with a paragraph:
     *     <p>foo</p>
     *     <pycode>
     *     <p>bar</p>
     *
     * @return (str)
     */
    public function getPType() {
        return "block";
    }

    /**
     * Define the priority used to determine in which order modes are added:
     * the mode with the lowest sort number will win.
     *
     * Since this plugin provides text codes and internal links, it is
     * sorted at:
     *     Doku_Parser_Mode_code (= 200) < PyCode plugin
     *     Doku_Parser_Mode_internallink (= 310) < PyCode plugin
     *
     * @return (int)
     */
    public function getSort() {
        return 315;
    }

    /**
     * Define the regular expression needed to match the plugin's syntax.
     *
     * This plugin use the following general syntax:
     *     <pycode [list of parameters]>
     *
     * @param (str) $mode name for the format mode of the final output
     *     (at the present only $mode == "xhtml" is supported)
     */
    public function connectTo($mode) {
        $this->Lexer->addSpecialPattern("<pycode.*?>", $mode, "plugin_pycode");
    }

    /**
     * Handle the plugin's syntax matched.
     *
     * This method is called every time the parser encounters the
     * plugin's syntax in order to produce a list of instructions for the
     * renderer, which will be interpreted later.
     *
     * @param (str) $match the text matched
     * @param (int) $state the lexer state
     * @param (int) $pos the character position of the matched text
     * @param (obj) $handler object reference to the Doku_Handler class,
     *     defined in inc/parser/handler.php
     * @return (arr) $data it contains the parameters handed to the
     *     plugin's syntax and found in the wiki page, that is:
     *     array {
     *     [0] => (str) <src-url>
     *     [1] => (str) <flag-c|f|l>
     *     [2] => (str) <name-class|function|lines>
     *     [3] => (str) <name-class>
     *     }
     *     where only element [0] is obligatory so the following
     *     are valid combinations:
     *     <src-url>
     *     <src-url> c <name-class>
     *     <src-url> f <name-function> <name-class>
     *     <src-url> f <name-function>
     *     <src-url> l <name-lines>
     */
    public function handle($match, $state, $pos, Doku_Handler $handler) {
        $data = array();

        $match = $this->mpp->_remove_multi_space($match);
        $match = substr($match, 8, -1);  // strips "<pycode " and ">"

        // get user option for line numbers
        $usr_nums = null;
        $re = "/(-nums)(\s*)(=)(\s*)(0|1)/";
        preg_match($re, $match, $matches);
        if (preg_match($re, $match, $matches) == 1) {
            $usr_nums = $matches[5];
        }

        // get user option for title
        $usr_title = null;
        $re = "/(-title)(\s*)(=)(\s*)(\'|\")(.*)(\'|\")/";
        preg_match($re, $match, $matches);
        if (preg_match($re, $match, $matches) == 1) {
            $usr_title = $matches[6];
        }

        // get user option for docstrings
        $usr_docstr = null;
        $re = "/(-docstr)(\s*)(=)(\s*)(0|1)/";
        preg_match($re, $match, $matches);
        if (preg_match($re, $match, $matches) == 1) {
            $usr_docstr = $matches[5];
        }

        // remove user options and create data array
        $re = "/(\s*-nums.*|\s*-title.*|\s*-docstr.*)/";
        $subst = "";
        $match = preg_replace($re, $subst, $match);
        $data = explode(" ", $match);

        // append user options
        $data["usr_nums"] = $usr_nums;
        $data["usr_title"] = $usr_title;
        $data["usr_docstr"] = $usr_docstr;

        return $data;
    }

    /**
     * Process the list of instructions that render the final output.
     *
     * It's used an array to remember if, in the same wiki page,
     * the same <file> is called one or more times, in order to do only one
     * connection to the relative repository to download its code.
     * As soon as the content of <file> is downloaded, it's stored in a local
     * directory and used to render the output, even for the oher calls
     * of <file>.
     * If, visiting another wiki page, the same <file> is called again or
     * every time the page is refreshed, this array is unset (desired effect)
     * so, before download the code again, it's checked how much
     * up-to-date is the local copy of <file> against the original copy
     * in the repository.
     * The array is of the form:
     *     array {
     *     [<src-url>] => (int) 0|1|2
     *     }
     * with the following meaning:
     *     <src-url> = 0: <file> has been just downloaded so it's up-to-date
     *     <src-url> = 1: <file> has been downloaded in the current session
     *                    and can be reused in the same page
     *     <src-url> = 2: <file> was downloaded in a previous session so
     *                    it could be out-of-date
     *
     * Since is saved a copy of <file>, it is necessary to know when it's no
     * longer used in any wiki page.
     * Hence it's used a logfile in which are recorded, for each wiki page, all
     * the repository used. When all the references to the same repository are
     * deleted from all wiki pages, the relative local copy of <file> is
     * deleted too.
     *
     * @param (str) $mode name for the format mode of the final output
     *     (at the present only $mode == "xhtml" is supported)
     * @param (obj) $renderer object reference to the Doku_Render class,
     *     defined in /inc/parser/renderer.php, which defines functions for the
     *     output (see also /lib/styles/screen.css for some styles)
     * @param (arr) $data it contains the parameters handled to the
     *     plugin's syntax and found in the wiki page, that is:
     *     array {
     *     [0] => (str) <src-url>
     *     [1] => (str) <flag-c|f|l>
     *     [2] => (str) <name-class|function|lines>
     *     [3] => (str) <name-class>
     *     ["usr_nums"] => (str) -nums = 0|1
     *     ["usr_title"] => (str) -title = "<new-title>"
     *     ["usr-docstr"] => (str) -docstr = 0|1
     *     }
     *     where only element [0] is obligatory and element [3] is
     *     the name of the class at wich the method belongs to
     *     so the following are valid combinations:
     *     <src-url>
     *     <src-url> [c <name-class> [-docstr]]
     *     <src-url> [f <name-function> [<name-class>] [-nums] [-title]]
     *     <src-url> [l <name-lines> [-nums] [-title]]
     */
    public function render($mode, Doku_Renderer $renderer, $data) {
        global $INPUT;
        $repo = array();  // store all <src-url>(s) found in the current page
        $code_error = array("error", "notfound-lns", "notfound-def", "notfound-cls");

        // eventualy disable the cache
        $cache = $this->getConf("cache");
        if ($cache == 1){
            $renderer->nocache();
        }

        try {
            // check if url to the source code is right
            $src_url = $data[0];
            $src_url = $this->mpp->_check_src_url($src_url);
            if (in_array($src_url, $code_error)) {
                throw new Exception($this->mpp->_check_src_url($src_url));
            }

            // get info associated to the code
            $flag = $data[1];
            $name = $data[2];
            $subname = $data[3];
            $nums = $data["usr_nums"];
            $title = $data["usr_title"];
            $docstr = $data["usr_docstr"];
            list($name_host, $name_repo, $name_brch, $name_file) = $this->mpp->_get_names($src_url);
            $loc_url = $this->mpp->_get_loc_url($name_host, $name_repo, $name_brch, $name_file);
            $lang = $this->mpp->_get_lang($name_file);
            $raw_url = $this->mpp->_get_raw_url($src_url);

            // check if in this session <file> has been alredy downloaded
            if ((file_exists($loc_url) == false)) {
                $repo[$src_url] = 0;
            }
            elseif (file_exists($loc_url) == true and
                    in_array($src_url, array_keys($repo)) == false) {
                $repo[$src_url] = 2;
            }

            // get the code
            if ($flag == "" and $name != "") {
                throw new Exception("wrong-flag");
            }
            elseif ($flag != "" and $name == "") {
                throw new Exception("wrong-flag");
            }
            elseif (($flag == "f" or $flag == "c") and $lang != "python") {
                throw new Exception("wrong-flag");
            }
            if ($repo[$src_url] == 0) {
                // get the whole code
                list($code_raw, $sl_raw, $el_raw) = $this->mpp->_get_code($raw_url);
                if (in_array($code_raw, $code_error)) {
                    throw new Exception($code_raw);
                }
                // save in local and use this instead of the repo
                $this->mpp->_save_code($loc_url, $code_raw);
            }
            elseif ($repo[$src_url] == 2) {
                list($code_raw, $sl_raw, $el_raw) = $this->mpp->_get_code($raw_url, $flag, $name, $subname);
                if (in_array($code_raw, $code_error)) {
                    throw new Exception($code_raw);
                }
                if ($flag == "c") {
                    // temporaly save in local and use this instead of the repo
                    // because to chek if a class is changed is necessary to
                    // check if all its methods are changed too
                    $tmp_raw_loc_url = $loc_url . ".tmp";
                    $this->mpp->_save_code($tmp_raw_loc_url, $code_raw);
                }
            }
            list($code_loc, $sl_loc, $el_loc) = $this->mpp->_get_code($loc_url, $flag, $name, $subname);
            if (in_array($code_loc, $code_error)) {
                throw new Exception($code_loc);
            }

            // call the printer
            if ($repo[$src_url] == 0 or $repo[$src_url] == 1) {
                if (in_array($flag, array("", "l", "f"))) {
                    $range = range($sl_loc, $el_loc);
                    $this->_print_code($renderer, $src_url, $code_loc, $lang, $range, $flag, $name, $subname, $nums, $title);
                }
                elseif ($flag == "c") {
                    $tree_loc = $this->mpp->_get_tree($code_loc);
                    $this->_print_tree($renderer, $loc_url, $tree_loc, $docstr);
                }
                $repo[$src_url] = 1;
            }
            elseif ($repo[$src_url] == 2) {
                $code_dif = $this->mpp->_get_code_dif($code_raw, $code_loc);
                if (in_array($flag, array("", "l", "f"))) {
                    if ($code_dif == "dif") {
                        $this->_print_note($renderer, $loc_url, $code_raw, $sl_loc, $el_loc);
                        $range = range($sl_loc, $el_loc);
                    }
                    else {
                        $range = range($sl_raw, $el_raw);  // sth. is changed outside the range
                    }
                    $this->_print_code($renderer, $src_url, $code_loc, $lang, $range, $flag, $name, $subname, $nums, $title);
                }
                elseif ($flag == "c") {
                    $tree_loc = $this->mpp->_get_tree($code_loc);
                    if ($code_dif == "dif") {
                        $tree_raw = $this->mpp->_get_tree($code_raw);
                        $tree_dif = $this->mpp->_get_tree_dif($tmp_raw_loc_url, $loc_url, $tree_raw, $tree_loc);
                        $this->_print_note($renderer, $loc_url, $code_raw, $sl_loc, $el_loc);
                        $this->_print_tree($renderer, $loc_url, $tree_dif, $docstr);
                    }
                    else {
                        $this->_print_tree($renderer, $loc_url, $tree_loc, $docstr);
                    }
                    unlink($tmp_raw_loc_url);
                }
            }

            // record the <file>(s) embedded in this wiki page
            $tmp_log_url = DOKU_PLUGIN . "pycode/tmp/logfile.tmp";
            $this->mpp->_save_code($tmp_log_url, $loc_url);
        }

        catch (Exception $error) {
            if ($error->getMessage() == "error") {
                $this->_print_error($renderer);
            }
            elseif ($error->getMessage() == "wrong-flag") {
                $this->_print_wrong_flag($renderer);
            }
            elseif ($error->getMessage() == "notfound-lns") {
                $this->_print_notfound_lns($renderer);
            }
            elseif ($error->getMessage() == "notfound-def") {
                $this->_print_notfound_def($renderer);
            }
            elseif ($error->getMessage() == "notfound-cls") {
                $this->_print_notfound_cls($renderer);
            }
        }
    }

    /**
     * Print the code of <file>.
     *
     * @param (obj) $renderer object reference to the Doku_Render class,
     *     defined in /inc/parser/renderer.php, which defines functions for the
     *     output (see also /lib/styles/screen.css for some styles)
     * @param (str) $src_url the url to the source code of <file> in the repo
     *     Bitbucket <src-url> =
     *     "https://bitbucket.org/<user>/<repo>/src/<branch>/<file>"
     *     GitHub <src-url> =
     *     "https://github.com/<user>/<repo>/blob/<branch>/<file>"
     * @param (arr) $code the code to embed
     * @param (str) $lang the language name used in <file>
     * @param (arr) $range the numbers of the lines matching the code to embed
     * @param (str) $flag flag to indicate what kind of code we want to embed:
     *     "" = all | "c" = class | "f" = function | "l" = lines
     * @param (str) $name if specified, it can be only:
     *     name-function|lines
     * @param (str) $subname if specified, it can be only:
     *     name-class
     * @param (int) $nums if specified, it can be only:
     *     0 = hide line numbers | 1 = show line numbers
     * @param (str) $title if specified, it is the new user's title for the
     *     code embedded
     */
    private function _print_code(Doku_Renderer $renderer, $src_url, $code, $lang, $range, $flag,
                                 $name = null, $subname = null, $nums = null, $title = null) {
        if ($flag == "f") {
            $code = $this->mpp->_remove_indent($code);
        }
        $code = implode($code, PHP_EOL);

        if ($nums === null) {
            $nums = $this->getConf("nums");
        }

        // make the title for the code
        if ($title === null) {
            $title = $this->getConf("title");
            if ($title != "none") {
                if ($title == "file â‹… class â‹… def â‹… #:#") {
                    $src = basename($src_url) . " â‹… ";
                }
                elseif ($title == "src-url â‹… class â‹… def â‹… #:#") {
                    $src = $src_url . " â‹… ";
                }
                if ($flag == "") {
                    $class = "";
                    $def = "";
                }
                elseif ($flag == "f") {
                    if ($subname === null) {
                        $class = "";
                        $def = "def: " . $name . " â‹… ";
                    }
                    else {
                        $class = "class: " . $subname . " â‹… ";
                        $def = "def: " . $name . " â‹… ";
                    }
                }
                elseif ($flag == "l") {
                    $class = "";
                    $def = "";
                }
                $lns = "Ln: " . reset($range) . "-" . end($range);
                $title = "$src" . "$class" . "$def" . "$lns";
            }
        }
        else {
            if ($title == "") {
                $title = "none";
            }
        }

        // print
        if ($nums == 1) {
            $renderer->doc .= "<div class='nums_pycode'>";
            $renderer->doc .= "<dl class='code nums_pycode'>";
            if ($title != "none") {
                $renderer->doc .= "<dt>&nbsp;</dt>";
            }
            $renderer->doc .= "<dd>";
            $renderer->doc .= "<pre class='code nums_pycode'>";
            foreach ($range as $number) {
                if (strlen(end($range)) <= 4) {
                    $number = str_pad($number, 4, " ", STR_PAD_LEFT);
                }
                else {
                    $number = str_pad($number, 5, " ", STR_PAD_LEFT);
                }
                $renderer->doc .= "$number<br>";
            }
            $renderer->doc .= "</pre> </dd> </dl> </div>";
            $renderer->doc .= "<div class='code_pycode'>";
        }

        if ($title != "none") {
            $icon = $this->mpp->_get_icon($src_url);
            $renderer->doc .= "<dl class='code code_pycode'>";
            $renderer->doc .= "<dt><img class='code_pycode' src='" . $icon . "'>$title</dt>";
            $renderer->doc .= "<dd>";
        }

        $renderer->doc .= "<pre class='code $lang'>";
        $renderer->doc .= $this->mpp->_get_geshi_code($code, $lang);
        $renderer->doc .= "</pre>";

        if ($title != "none") {
            $renderer->doc .= "</dd> </dl>";
        }

        if ($nums == 1) {
            $renderer->doc .= "</div>";
        }
    }

    /**
     * Print the tree structure of a given class defined in <file>.
     *
     * @param (obj) $renderer object reference to the Doku_Render class,
     *     defined in /inc/parser/renderer.php, which defines functions for the
     *     output (see also /lib/styles/screen.css for some styles)
     * @param (str) $loc_url the url to the raw code of the copy of <file> in
     *     <srv-path>/lib/plugins/pycode/tmp/<host>/<repo>/<branch>/<file>
     * @param (arr) $tree the name of a class and its methods, that is:
     *     array {
     *     [0] => array {
     *         [0] => (str) "class <name-class>(<parameters>)"
     *         [1] => (str) <name-class>
     *         [2] => (int) <#>
     *         }
     *     [i] => array {
     *         [0] => (str) "class <name-function>(<parameters>)"
     *         [1] => (str) <name-function>
     *         [2] => (int) <#>
     *         }
     *     }
     *     where <#> is a flag used by the print function of the tree
     *     structure of the given class and which tells "how" to render
     *     each name; it can takes the following values:
     *     <#> = 0 means "unchanged"
     *     <#> = 1 means "changed"
     *     <#> = 2 means "deleted"
     *     <#> = 3 means "added"
     * @param (int) $docstr if specified, it can be only:
     *     0 = hide docstring | 1 = show docstring
     */
    private function _print_tree(Doku_Renderer $renderer, $loc_url, $tree, $docstr = null) {
        global $INFO;
        $namespace = $INFO["namespace"];

        if ($docstr === null) {
            $docstr = $this->getConf("docstr");
        }

        // get the descriptive part of the docstring
        if ($docstr == 1) {
            $all_brief = array();
            foreach ($tree as $key => $val) {
                if ($key == 0) {
                    list($code, $sl, $el) = $this->mpp->_get_code($loc_url, "c", $val[1]);
                    if ($code != "notfound-cls") {
                        $brief = $this->mpp->_get_docstr($code, $val[1], "c");
                    }
                }
                else {
                    list($code, $sl, $el) = $this->mpp->_get_code($loc_url, "f", $val[1], $tree[0][1]);
                    if ($code != "notfound-def") {
                        $brief = $this->mpp->_get_docstr($code, $val[1], "f");
                    }
                }
                array_push($all_brief, $brief);
            }
        }

        // this is what we want to produce:
        // * class <name-class>(<parameters>)
        //   * def <name-function>(<parameters>)
        //   * ...
        //   * def <name-function>(<parameters>)
        //
        // the equivalent xhtml code is:
        // <ul>
        //   <li>
        //   <div>class <name-class>(<parameters>)</div>
        //     <ul>
        //       <li>
        //       <div>def <name-function>(<parameters>)</div>
        //       </li>
        //       ...
        //       <li>
        //       <div>def <name-function>(<parameters>)</div>
        //       </li>
        //     </ul>
        //   </li>
        // </ul>

        $renderer->listu_open(); // <ul>
        $renderer->listitem_open(1); // <li>
        $renderer->listcontent_open(); // <div>
        if ($tree[0][2] == 1) {
            $renderer->strong_open(); // start bold
            $renderer->cdata($tree[0][0]);
            $renderer->strong_close(); // stop bold
        }
        else {
            $renderer->cdata($tree[0][0]);
        }
        if ($docstr == 1) {
            $renderer->doc .= "<blockquote class='quote_pycode'>";
            $renderer->emphasis_open();
            foreach ($all_brief[0] as $line) {
                $renderer->doc .= $line . "<br />";
            }
            $renderer->emphasis_close();
            $renderer->doc .= "</blockquote>";
        }
        $renderer->listcontent_close(); // </div>

        $renderer->listu_open(); // <ul> start indented
        foreach ($tree as $key => $val) {
            if ($key == 0) {
                continue;
            }
            $renderer->listitem_open(2); // <li>
            $renderer->listcontent_open(); // <div>
            if ($val[2] == 1) {
                $renderer->strong_open(); // start bold
            }
            elseif ($val[2] == 2) {
                $renderer->deleted_open(); // start strike out
            }
            $renderer->internallink($namespace . ":" . $val[1], $val[0]);
            if ($val[2] == 1) {
                $renderer->strong_close(); // stop bold
            }
            elseif ($val[2] == 2) {
                $renderer->deleted_close(); // stop strike out
            }
            if ($docstr == 1) {
                $renderer->doc .= "<blockquote class='quote_pycode'>";
                $renderer->emphasis_open();
                foreach ($all_brief[$key] as $line) {
                    $renderer->doc .= $line . "<br />";
                }
                $renderer->emphasis_close();
                $renderer->doc .= "</blockquote>";
            }
            $renderer->listcontent_close(); // </div>
            $renderer->listitem_close(); // </li>
        }
        $renderer->listu_close(); // </ul> stop indented

        $renderer->listitem_close(); // </li>
        $renderer->listu_close(); // </ul>
    }

    /**
     * Print a notificaton which informs that the copy of <file>
     * is out-of-date.
     *
     * Only users with a level permission greater than or equal to 2,
     * can flush it away (see DokuWiki's ACL):
     * level     |  0       1       2       4       8       16      255
     * permission|  none    read    edit    create  upload  delete  admin
     *
     * @param (obj) $renderer object reference to the Doku_Render class,
     *     defined in /inc/parser/renderer.php, which defines functions for the
     *     output (see also /lib/styles/screen.css for some styles)
     * @param (str) $loc_url the url to the raw code of the copy of <file> in
     *     <srv-path>/lib/plugins/pycode/tmp/<host>/<repo>/<branch>/<file>
     * @param (arr) $code_new the updated code got from the repository
     * @param (int) $sl the number of the starting line of the code
     * @param (int) $el the number of the ending line of the code
     */
    private function _print_note(Doku_Renderer $renderer, $loc_url, $code_new, $sl, $el) {
        global $INFO;
        $perm = $INFO["perm"];
        $note = $this->getLang("note");
        $code_new = base64_encode(serialize($code_new));

        $renderer->doc .= "<div class='notify'>";
        $renderer->cdata($note);
        if ($perm >= AUTH_EDIT) {
            $renderer->doc .= "<form method='post'>";
            $renderer->doc .= "<input type='hidden' name='url' value=$loc_url>";
            $renderer->doc .= "<input type='hidden' name='new' value=$code_new>";
            $renderer->doc .= "<input type='hidden' name='start' value=$sl>";
            $renderer->doc .= "<input type='hidden' name='end' value=$el>";
            $renderer->doc .= "<input class='button ok_pycode' type='submit'
            name='submit' value='Ok'>";
            $renderer->doc .= "</form>";
        }
        $renderer->doc .= "</div>";
    }

    /**
     * Print an error message which informs that the code between the
     * specified lines is out of range.
     *
     * @param (obj) $renderer object reference to the Doku_Render class,
     *     defined in /inc/parser/renderer.php, which defines functions for the
     *     output (see also /lib/styles/screen.css for some styles)
     */
    private function _print_notfound_lns(Doku_Renderer $renderer) {
        $notfound_lns = $this->getLang("notfound-lns");

        $renderer->doc .= "<div class='error'>";
        $renderer->cdata($notfound_lns);
        $renderer->doc .= "</div>";
    }

    /**
     * Print an error message which informs that the given function was
     * not found in <file>.
     *
     * @param (obj) $renderer object reference to the Doku_Render class,
     *     defined in /inc/parser/renderer.php, which defines functions for the
     *     output (see also /lib/styles/screen.css for some styles)
     */
    private function _print_notfound_def(Doku_Renderer $renderer) {
        $notfound_def = $this->getLang("notfound-def");

        $renderer->doc .= "<div class='error'>";
        $renderer->cdata($notfound_def);
        $renderer->doc .= "</div>";
    }

    /**
     * Print an error message which informs that the given class was
     * not found in <file>.
     *
     * @param (obj) $renderer object reference to the Doku_Render class,
     *     defined in /inc/parser/renderer.php, which defines functions for the
     *     output (see also /lib/styles/screen.css for some styles)
     */
    private function _print_notfound_cls(Doku_Renderer $renderer) {
        $notfound_cls = $this->getLang("notfound-cls");

        $renderer->doc .= "<div class='error'>";
        $renderer->cdata($notfound_cls);
        $renderer->doc .= "</div>";
    }

    /**
     * Prints an error message which informs that the flag is not correct.
     *
     * @param (obj) $renderer object reference to the Doku_Render class,
     *     defined in /inc/parser/renderer.php, which defines functions for the
     *     output (see also /lib/styles/screen.css for some styles)
     */
    private function _print_wrong_flag(Doku_Renderer $renderer) {
        $wrong_flag = $this->getLang("wrong-flag");

        $renderer->doc .= "<div class='error'>";
        $renderer->cdata($wrong_flag);
        $renderer->doc .= "</div>";
    }

    /**
     * Print an error message which informs that the file is not
     * a Python script.
     *
     * @param (obj) $renderer object reference to the Doku_Render class,
     *     defined in /inc/parser/renderer.php, which defines functions for the
     *     output (see also /lib/styles/screen.css for some styles)
     */
    private function _print_wrong_lang(Doku_Renderer $renderer) {
        $wrong_lang = $this->getLang("wrong-lang");

        $renderer->doc .= "<div class='error'>";
        $renderer->cdata($wrong_lang);
        $renderer->doc .= "</div>";
    }

    /**
     * Print an error message which informs that there was some problems
     * to contact the repository.
     *
     * @param (obj) $renderer object reference to the Doku_Render class,
     *     defined in /inc/parser/renderer.php, which defines functions for the
     *     output (see also /lib/styles/screen.css for some styles)
     */
    private function _print_error(Doku_Renderer $renderer) {
        $error = $this->getLang("error");

        $renderer->doc .= "<div class='error'>";
        $renderer->cdata($error);
        $renderer->doc .= "</div>";
    }
}