<?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>