<?php

// Show source if requested.
if (isset($_GET['source']) || isset($source))
{
    echo 
'<html><head><meta name="robots" content="noindex,nofollow"></head><body>';
    
highlight_file(__FILE__);
    die();
}

require_once(
"MyCSV.class.php");

if (isset(
$_SERVER['PHP_SELF'])) $PHP_SELF $_SERVER['PHP_SELF'];
$PHP_SELF preg_replace('/index\.\w+$/'''$PHP_SELF);
if (isset(
$_REQUEST['action'])) $action $_REQUEST['action'];
if (isset(
$_REQUEST['title'])) $title $_REQUEST['title'];

if (empty(
$title)) $title "Main Page";
else 
$title stripslashes($title);

$db = new MyCSV("pages");
$relationships = new MyCSV("relationships");

$record = @$db->data[$title];
if (empty(
$record))
{
    
header("HTTP/1.0 404 Not Found");
}

if (! empty(
$HTTP_POST_VARS['content']) && strlen($HTTP_POST_VARS['content']) < 10000)
{
    
$record['content'] = trim(stripslashes($HTTP_POST_VARS['content']));

    
// Transform Windows/Mac/whatever line breaks to simple "\n".
    
$record['content'] = preg_replace('{\s*?\n\r*|\s*?\r}'"\n"$record['content']);

    if (empty(
$record['created'])) $record['created'] = date("Y-m-d H:i:s");
    
$record['modified'] = date("Y-m-d H:i:s");
    if (empty(
$record['id']))
    {
        
$record['id'] = $title;
        
$db->insert($record);
    }
    else 
$db->update($record);
    
$db->write();

    
$relationships->reset();
    while (
$rel $relationships->each())
    {
        if (
$rel['subject'] == $title$relationships->delete($rel['id']);
    }
    foreach (
$HTTP_POST_VARS['predicate'] as $i => $predicate)
    {
        
$object $HTTP_POST_VARS['object'][$i];
        if (empty(
$predicate) || empty($object)) continue;
        
$relationships->insert(array(
            
'subject'   => $title,
            
'predicate' => $predicate,
            
'object'    => $object));
    }
    
$relationships->write();
}

if (empty(
$record['content'])) $action "edit";

function 
callback($matches)
{
    if (empty(
$matches[1])) return $matches[0];
    else
    {
        return 
'<a class="auto" href="./?title=' $matches[0] . '">' $matches[0] . '</a>';
    }
}

function 
echoPage($content$more false)
{
    global 
$PHP_SELF$db$title;

    
$content preg_replace('{<a>([^<]*)}is''<a href=\1>\1'$content);
    
$content preg_replace('{<img>([^<]*)</img>}is''<img src="\1">'$content);
    
$content preg_replace('{<a=}is''<a href='$content);
    
$content preg_replace('{<img=}is''<img src='$content);
    
$content preg_replace_callback('{<a\s+href\s*=\s*([^\s"][^>]*)}is', function ($matches) {
        return 
'<a href="' htmlspecialchars($matches[1]) . '"';
    }, 
$content);
    
$content preg_replace('{<a href="([^:"]*")}is'"<a href=\"$PHP_SELF?title=\\1"$content);

    
// Detect links/anchors even if they are not in <a href>.
    
$content preg_replace_callback('{
        <a\b.*?</a>|<img[^>]*>
        |
        \b(http://|(www\.))([^\s"\'<>\[\]\\\]{4,}[\w/=])
        }isx'
,
        function (
$matches) {
            return 
stripslashes($matches[1] ? '<a href="http://' $matches[2] . $matches[3] . '">' $matches[0] . '</a>' $matches[0]);
        },
        
$content);

    
// Generate unordered and ordered lists, two nested levels maximum.
    
for ($i 0$i 3$i++)
        
$content preg_replace_callback(
            
'/\n( *)(?:[*-]|\d\.) [^\n]+(\n\1(?: |[*-]|\d\.) [^\n]+)+/is',
            
'list_callback',
            
$content);

    if (
strpos($content'<pageindex>') !== false)
    {
        
$ids $db->ids();
        
usort($ids'strnatcasecmp');
        
$replacement "";
        foreach (
$ids as $id)
        {
            
$replacement .= htmlspecialchars($id) . " <small>(created " $db->data[$id]['created'] . ", modified " $db->data[$id]['modified'] . ")</small><br>";
        }
        
$content str_replace('<pageindex>'$replacement$content);
    }

    if (
strpos($content'<recentchanges>') !== false)
    {
        
$db->sort("modified DESC");
        
$replacement "";
        while (
$row $db->each())
        {
            
$replacement .= $row['modified'] . " " htmlspecialchars($row['id']) . " <small>(created " $row['created'] . ")</small><br>";
        }
        
$content str_replace('<recentchanges>'$replacement$content);
    }

    unset(
$db->data[$title]);

    
$pattern '{<a\b.*?</a>|<[^>]*|(' implode('|'array_map('preg_quote'array_map('htmlspecialchars'$db->ids()))) . ')}sS';
    
$content preg_replace_callback($pattern'callback'$content);

    
// Replace double quotes with &raquo;...&laquo; (German style).
    // See http://maettig.com/1058945580
    
$content preg_replace_callback(
        
'{<(code|head|pre|script)\b.+?</\1>|<[^>]*>|(?<!\w)"(([^"<]|<[^>]*>)+)"(?!\w)}sS',
        function (
$matches) {
            return 
stripslashes($matches[2] ? '&bdquo;' $matches[2] . '&ldquo;' $matches[0]);
        },
        
$content
    
);

    
// Replace remaining double quotes with their HTML entities.
    //- $content = str_replace('"', '&quot;', $content);

    // Replace " - " and " -- " with the n-dash (German style).
    // See http://maettig.com/1058945580
    
$content preg_replace_callback(
        
'!<(code|head|pre|script)\b.+?</\1>|<[^>]*>|(?<= )(-{1,2})(?= )!sS',
        function (
$matches) {
            return 
stripslashes($matches[2] ? '&ndash;' $matches[0]);
        },
        
$content);

    
// Preserve multiple vertical white spaces.
    //- $content = preg_replace('/(^|\s)[ \t]/mS', '\1&nbsp;', $content);

    
if ($more)
    {
        
$content preg_replace('{<more>.*$}is',
            
'<div>[<a href="' $PHP_SELF '?title=' htmlspecialchars($more) . '">read on...</a>]</div>'$content);
    }

    echo 
$content;
}

function 
list_callback($matches)
{
    
$listUO preg_match('/^\s*[*-]/s'$matches[0]) ? "ul" "ol";
    
$matches[0] = preg_replace(
        
'/\n' $matches[1] . '(?:[*-]|\d\.) ([^\n]+(\n' $matches[1] . '  [^\n]+)*)/s',
        
"<li>\\1\n</li>\n",
        
$matches[0]);
    return 
"\n<$listUO>\n" $matches[0] . "</$listUO>";
}

?><html>
<head>
<meta name="robots" content="noindex,nofollow">
<title>TM::Wiki-&gt;<?=htmlspecialchars($title)?></title>
<style type="text/css">
body{background-color:#EEE;}

#menu{
 background-color:white;
 border:1px solid #999;
 float:right;
 list-style-position:inside;
 margin:0;
 overflow:hidden;
 padding:0 1ex 1ex 1ex;
 width:27ex;
}
#menu ul{
 list-style-position:inside;
 margin:0;
 padding:0 0 0 3ex;
}
#menu li{
 margin:1ex 0 0 0;
 padding:0;
 white-space:nowrap;
}
#page{
 margin-right:31ex;
}

.rdfType{
 border:1px solid #999;
 margin:0 0 2ex 0;
 padding:1ex;
}

.rdfTypeA{
 background-color:#DDD;
 border-color:white;
 border-style:inset;
 border-width:1px 1px 0 1px;
 display:block;
 margin:2ex 0 0 0;
 padding:0 1ex;
}

h1{font-size:150%;}
h2{font-size:125%;font-style:italic;}
#title small{font-size:smaller;font-weight:normal;}
#content{
 background-color:white;
 border:1px solid #999;
 margin:0;
 padding:1ex;
}
p,ul,ol,dl,blockquote{margin-bottom:0.75em;margin-top:0.75em;}
li,dd{
 margin-bottom:0.25em;
}
blockquote,q{
 background-color:#F7F7DD;
 font-style:italic;
 quotes:'' '' '' '';
}
pre,code{
 background-color:#E6E6F7;
}
blockquote{
 border-left-color:#CC9;
 padding:0.2ex;
}
pre{
 border-left-color:#99C;
 padding:0.2ex;
}
dd{
 border-left-color:#DED;
 padding:0;
}
blockquote,pre,dd{
 border-left-width:3px;
 border-left-style:solid;
 padding-left:1ex;
}
.edit{
 margin:0;
 padding:0;
 text-align:right;
 margin-top:-1px;
}
.edit a{
 background-color:#DDD;
 border-color:white;
 border-style:outset;
 border-width:0 1px 1px 1px;
 margin:0 2ex;
 padding:0 2ex;
 text-align:right;
}
textarea{
 margin-right:31ex;
 /*width:100%;*/
}
textarea,input{
 border-width:1px;
 margin:1px 0;
}
textarea,input[type=text]{
 padding:2px;
}
input[type=submit]{
 background-color:#CCC;
 border-width:2px;
 padding:0 1ex;
}
a:link{color:#06C;font-weight:bold;text-decoration:none;}
a:visited{color:#039;font-weight:bold;text-decoration:none;}
a:active,a:hover,input:hover{background-color:#DEF;color:black;}

a:link.auto,a:visited.auto{font-weight:normal;}

a[href^="http://"]{font-weight:normal;text-decoration:underline;}
</style>
</head>
<body>

<h1 id="title"><a href="http://maettig.com/">TM</a>::<a href="<?=$PHP_SELF?>">Wiki</a>-&gt;<a href="<?=$PHP_SELF?>?title=<?=htmlspecialchars($title)?>" rel="bookmark" title="Permalink"><?=htmlspecialchars($title)?></a>
<small>(created <?=date("Y-m-d G:i", @strtotime($db->data[$title]['created']))?>,
modified <?=date("Y-m-d G:i", @strtotime($db->data[$title]['modified']))?>)</small></h1>

<ul id="menu">
<?php
$menu 
"";
$parents = array();
$relationships->sort('subject');
while (
$rel $relationships->each())
{
    if (
$rel['subject'] == $title && $rel['predicate'] == 'rdfs:subClassOf')
    {
        
$menu .= "<li><a href=\"" $PHP_SELF "?title=" htmlspecialchars($rel['object']) . "\">" htmlspecialchars($rel['object']) . "</a></li>";
        
$parents[$rel['object']] = true;
    }
}

if (
$title == "Main Page")
{
    
$menu .= "<li>Main Page</li>{subMenu}";
}
else
{
    
$menu .= "<ul>";
    
$relationships->reset();
    while (
$rel $relationships->each())
    {
        if (
$rel['predicate'] != 'rdfs:subClassOf') continue;
        foreach (
$parents as $parent => $bool)
        {
            if (
$rel['object'] == $parent)
            {
                if (
$rel['subject'] != $title)
                {
                    
$menu .= "<li><a href=\"" $PHP_SELF "?title=" htmlspecialchars($rel['subject']) . "\">" htmlspecialchars($rel['subject']) . "</a></li>";
                }
                else
                {
                    
$menu .= "<li>" htmlspecialchars($rel['subject']) . "</li>{subMenu}";
                }
                break;
            }
        }
    }
}

$subMenu "<ul>";
$relationships->reset();
while (
$rel $relationships->each())
{
    if (
$rel['predicate'] == 'rdfs:subClassOf' && $rel['object'] == $title)
    {
        
$subMenu .= "<li><a href=\"" $PHP_SELF "?title=" htmlspecialchars($rel['subject']) . "\">" htmlspecialchars($rel['subject']) . "</a></li>";
    }
}
$subMenu .= "</ul>";
echo 
str_replace("{subMenu}"$subMenu$menu);
?>
</ul></ul>

<? if (! empty($action)) { ?>
<form action="<?=$PHP_SELF?>" method="post">
<input name="title" type="hidden" value="<?=htmlspecialchars($title)?>">
<textarea cols="90" name="content" rows="25"><?=htmlspecialchars($record['content'])?></textarea><br>

<fieldset>
<legend>Relationships</legend>

<?php
$ids 
$db->ids();
natcasesort($ids);
$options "<option value=\"\">-</option>";
foreach (
$ids as $id)
{
    
$options .= "<option>" $id "</option>";
}
$relationships->sort("predicate, object");
while (
$rel $relationships->each())
{
    if (
$rel['subject'] != $title) continue;
    echo 
htmlspecialchars($title) . "&nbsp;";
    echo 
"<select name=\"predicate[]\" size=\"1\">" str_replace(">" $rel['predicate'] . "<"" selected>" $rel['predicate'] . "<"$options) . "</select>";
    echo 
"&nbsp;";
    echo 
"<select name=\"object[]\" size=\"1\">" str_replace(">" $rel['object'] . "<"" selected>" $rel['object'] . "<"$options) . "</select><br>";
}
echo 
htmlspecialchars($title) . "&nbsp;";
echo 
"<select name=\"predicate[]\" size=\"1\">" $options "</select>";
echo 
"&nbsp;";
echo 
"<select name=\"object[]\" size=\"1\">" $options "</select>";
?>

</fieldset>

<input type="submit" value="Save page">
<input name="action" type="submit" value="Save page and continue editing">
</form>
<? ?>

<div id="page">

<? if (! empty($record['content'])) { ?>
<div id="content"><?

echoPage
($record['content']);


echo 
"<div style=\"border:1px dotted black;margin:2ex 0;padding:1ex\">";
$relationships->reset();
while (
$rel $relationships->each())
{
    if (
$rel['subject'] != $title) continue;
    
$relH htmlspecialchars($title) . "&nbsp;";
    
$relH .= htmlspecialchars($rel['predicate']) . "&nbsp;";
    
$relH .= htmlspecialchars($rel['object']) . "<br>";
    if (
$rel['predicate'] == 'rdf:type' || $rel['predicate'] == 'rdfs:subClassOf')
        echo 
"<span style=\"color:#999\">" $relH "</span>";
    else echo 
$relH;
}
echo 
"</div>";


$parents = array();
$relationships->sort("object");
while (
$rel $relationships->each())
{
    if (
$rel['subject'] == $title && $rel['predicate'] == 'rdf:type')
    {
        
$parents[] = "<a href=\"" $PHP_SELF "?title=" htmlspecialchars($rel['object']) . "\">&lt; Back to " htmlspecialchars($rel['object']) . "</a>";
    }
}
if (! empty(
$parents)) echo "<p>[ " implode(" | "$parents) . " ]</p>";


function 
getChilds($title, &$childs)
{
    global 
$relationships;
    
$relA $relationships->data;
    foreach (
$relA as $rel)
    {
        if (
$rel['predicate'] == 'rdfs:subClassOf' && $rel['object'] == $title)
        {
            if (empty(
$childs[$rel['subject']]))
                
getChilds($rel['subject'], $childs);
            
$childs[$rel['subject']] = true;
        }
    }
    
$childs[$title] = true;
}
$childs = array();
getChilds($title$childs);

$db->sort("created DESC");
while (
$page $db->each())
{
    
$relationships->reset();
    while (
$rel $relationships->each())
    {
        if (
$rel['subject'] != $page['id'] || $rel['predicate'] != 'rdf:type' ||
            empty(
$childs[$rel['object']]))
        {
            continue;
        }
        echo 
"<a class=\"rdfTypeA\" href=\"" $PHP_SELF "?title=" htmlspecialchars($db->data[$rel['subject']]['id']) . "\">" htmlspecialchars($db->data[$rel['subject']]['id']);
        echo 
" (created " date("Y-m-d G:i"strtotime($db->data[$rel['subject']]['created']));
        echo 
", modified " date("Y-m-d G:i"strtotime($db->data[$rel['subject']]['modified'])) . ")";
        echo 
"</a>";
        echo 
"<div class=\"rdfType\">";
        echo 
echoPage($db->data[$rel['subject']]['content'], $db->data[$rel['subject']]['id']);
        echo 
"</div>";
        break;
    }
}

?>

<p><a href="feed.php?title=<?=htmlspecialchars($title)?>"
style="background-color:#F60;border:1px solid;border-color:#FCA #730 #420 #F95;color:white;font:bold 10px Verdana,sans-serif;padding:0 4px;text-decoration:none">RSS 1.0</a></p>

</div>
<? ?>

<? if (empty($action)) { ?>
<p class="edit"><a href="<?=$PHP_SELF?>?title=<?=htmlspecialchars($title)?>&amp;action=edit">Edit this page</a></p>
<? ?>

</div>

<p>
<a href="<?=$PHP_SELF?>?source=1">Show PHP source</a>
</p>

</body>
</html>