#!/usr/bin/php-cgi -dcgi.force_redirect=0
<?php
# encoding: utf-8
# api: cgi
# type: config
# category: admin
# title: Extra config
# description: Additional list of options to configure, read from ext/* PMD
# version: 0.1
# state: beta
# config:
#    { name: project-twitter, type: str, value: "", description: "Twitter handle for project (e.g. @sqlite1)" }
#    { name: project-license, type: select, select: "0BSD|AAL|ADSL|AFL-3.0|AGPL-1.0|AGPL-3.0|AGPL-3.0-or-later|Apache-2.0|APSL-2.0|Artistic-1.0|Artistic-2.0|BSD-1-Clause|BSD-2-Clause|BSD-2-Clause-FreeBSD|BSD-2-Clause-NetBSD|BSD-2-Clause-Patent|BSD-3-Clause|BSD-3-Clause-Attribution|BSD-3-Clause-Clear|BSD-3-Clause-Modification|BSD-4-Clause|BSD-4-Clause-Shortened|BSL-1.0|CAL-1.0|CC0-1.0|CC-BY-2.0|CC-BY-3.0|CC-BY-4.0|CC-BY-NC-2.0|CC-BY-NC-4.0|CC-BY-NC-ND-2.0|CC-BY-NC-ND-3.0|CC-BY-NC-ND-4.0|CC-BY-NC-SA-2.0|CC-BY-NC-SA-3.0|CC-BY-NC-SA-4.0|CC-BY-ND-4.0|CC-BY-SA-2.0|CC-BY-SA-4.0|CDDL-1.1|CPL-1.0|ECL-2.0|EFL-2.0|EPL-2.0|EUPL-1.2|GFDL-1.1|GFDL-1.3-only|GFDL-1.3-or-later|GPL-1.0|GPL-1.0+|GPL-2.0|GPL-2.0+|GPL-2.0-only|GPL-3.0|GPL-3.0+|IPL-1.0|ISC|LGPL-2.0|LGPL-2.1|LGPL-2.1+|LGPL-3.0|LGPL-3.0+|MIT|MIT-0|MIT-Modern-Variant|MPL-1.0|MPL-1.1|MPL-2.0|MS-PL|MS-RL|NPL-1.1|OFL-1.0|OSL-2.0|OSL-3.0|PSF-2.0|Python-2.0|SPL-1.0|TCL|Unlicense|W3C|WTFPL|X11|Zend-2.0|ZPL-2.1", value: "", description: "Source code license (SPDX identifier)" }
#    { name: project-description, type: text, value: "", description: "Fossil repository and project description" }
# new: -
#
# Reads the #config:{} fields, and updates fossils’ config table.
# Allows extroot scripts to provide additional options, or just
# an alternative to the builtin settings.
#

error_reporting(E_ALL);

#-- fossil HTML output
function page_md($text) {
    header("Content-Type: text/html; charset=utf-8");
    print <<<EOF
<div class='fossil-doc' data-title='Extra configuration'>
<style>
 .config-list label {
    display: block;
    margin-bottom: 10pt;
    border-left: 3pt #ddd solid;
    border-radius: 5pt 0 0 5pt;
    padding-left: 10pt;
 }
</style>
$text
EOF;
}

#-- database (== fossil repo)
function db($sql="", $params=[]) {
    static $db;
    if (empty($db)) {
        $db = new PDO("sqlite:$_SERVER[FOSSIL_REPOSITORY]");
    }
    if ($params) {
        $stmt = $db->prepare($sql);
        $stmt->execute($params);
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }
    else {
        return $db->query($sql)->fetchAll(PDO::FETCH_ASSOC);
    }
}
function get_config($name, $default) {
    $r = db("SELECT value FROM config WHERE name=?", [$name]);
    return $r ? $r[0]["value"] : $default;
}
function h($s) {
    return htmlspecialchars($s, ENT_QUOTES, "utf-8");
}

#-- filtered file list
function ls($dir) {
    $ls = [];
    foreach (glob("$dir/*") as $fn) {
        if (is_file($fn) and is_executable($fn) and is_readable($fn)) {
            $ls[] = basename($fn);
        }
    }
    return $ls;
}

#-- plugin meta data reading (pluginconf version)
function meta($fn) {
    $src = file_get_contents($fn, false, NULL, 0, 4096);
    $src = preg_replace("~\R~", "\n", $src);
    preg_match_all("~(^\h{0,4}(#(?!!)|//|/?\*).*\n)+~m", $src, $uu);
    $src = implode("", $uu[0]);
    $src = preg_replace("~^\h{0,4}(#|//|/?\*)\h{0,3}\r*~m", "", $src);
    preg_match_all("~^([\w-]+):(.*$\\n(?:\n(?![\w-]+:).+$\\n)*)~xm", $src, $uu);
    $r = array_combine($uu[1], $uu[2]);
    return $r;
}
#-- split up config: field
function config($meta, $r=[]) {
    if (empty($meta["config"])) {
        return [];
    }
    preg_match_all("~\{ (.+?) \} | \< (.+?) \>~x", $meta["config"], $uu);
    foreach ($uu[0] as $row) {
        preg_match_all("~ [\"':$]?(\w*)[\"']?   \s*[:=]+\s*  (?: \"([^\"]*)\" | '([^']*)' | ([^,]*) )~x", $row, $uu, PREG_SET_ORDER);
        $opt = [];
        foreach ($uu as $f) {
            $f = array_values(array_filter($f, "strlen"));
            $opt[$f[1]] = isset($f[2]) ? $f[2] : "";
        }
        $r[] = $opt;
    }
    return $r;
}

#-- run
page_md("<div class=config-list>\n");
foreach (ls(__DIR__) as $fn) {
    $meta = meta($fn);
    $h = "h";
    if ($config = config($meta)) {
        $title = $meta["title"] ?: $fn;
        print "<h3>$title</h3>\n";
        foreach ($config as $opt) {
            if (empty($opt["name"])) {
                continue;
            }
            $name = $opt["name"];
            $value = get_config($name, $opt["value"]);
            print "<label><b>{$h($name)}</b><br>\n";
            switch ($opt["type"]) {
                case "long":
                case "text":
                    print "<textarea name={$h($name)} rows=4 cols=70>{$h($value)}</textarea>";
                    break;
                case "choose":
                case "select":
                    print "<select name={$h($name)}>\n";
                    $opts = preg_split("~[|;,]~", $opt["select"]);
                    if (!in_array($value, $opts)) {
                        $opts[-1] = $value;
                    }
                    foreach ($opts as $o) {
                        $selected = $o == $value ? " selected" : "";
                        print "<option value=\"{$h($o)}\"$selected>{$h($o)}</option>\n";
                    }
                    print "</select>";
                    break;
                default:
                    print "<input type=\"$opt[type]\" name={$h($name)} value=\"{$h($value)}\" size=60>";
            }
            print "<br>\n<small>{$h($opt['description'])}</small></label>\n\n";
        }
    }
}
?></div>