<?php if (!defined('PmWiki')) exit();
/*  Copyright 2002-2006 Patrick R. Michaud (pmichaud@pobox.com)
    This file is part of PmWiki; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published
    by the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.  See pmwiki.php for full details.

    This script enables markup of the form <<|TrailPage|>> to be 
    used to build "trails" through wiki documents.

    This feature is automatically included from stdconfig.php unless
    disabled by $EnableWikiTrails = 0; .  To explicitly include this feature,
    execute
           include_once("scripts/trails.php");
    from config.php somewhere.

    Once enabled, the <<|TrailPage|>> markup is replaced with
    << PrevPage | TrailPage | NextPage >> on output.  TrailPage should
    contain either a bullet or number list defining the sequence of pages
    in the "trail".

    The ^|TrailPage|^ markup uses the depth of the bullets to display
    the ancestry of the TrailPage to the current one.  The <|TrailPage|> 
    markup is like <<|TrailPage|>> except that "< PrevPage |" and 
    "| NextPage >" are omitted if at the beginning or end of the 
    trail respectively.  Thanks to John Rankin for contributing these
    markups and the original suggestion for WikiTrails.
*/

Markup('<<|','<links','/&lt;&lt;\\|([^|]+|\\[\\[(.+?)\\]\\])\\|&gt;&gt;/e',
  "MakeTrailStop(\$pagename,'$1')");
Markup('<|','><<|','/&lt;\\|([^|]+|\\[\\[(.+?)\\]\\])\\|&gt;/e',
  "MakeTrailStopB(\$pagename,'$1')");
Markup('^|','<links','/\\^\\|([^|]+|\\[\\[(.+?)\\]\\])\\|\\^/e',
  "MakeTrailPath(\$pagename,'$1')");

SDVA($SaveAttrPatterns, array(
   '/<<\\|([^|]+|\\[\\[(.+?)\\]\\])\\|>>/' => '$1',
   '/<\\|([^|]+|\\[\\[(.+?)\\]\\])\\|>/' => '$1',
   '/\\^\\|([^|]+|\\[\\[(.+?)\\]\\])\\|\\^/' => '$1'));

$Conditions['ontrail'] = 'CondOnTrail($pagename, $condparm)';

function CondOnTrail($pagename, $condparm) {
  @list($trailname, $pn) = preg_split('/\\s+/', $condparm, 2);
  $trail = ReadTrail($pagename, $trailname);
  if (!$trail) return false;
  $pn = ($pn > '') ? MakePageName($pagename, $pn) : $pagename;
  foreach($trail as $t)
    if ($t['pagename'] == $pn) return true;
  return false;
}

function ReadTrail($pagename, $trailname) {
  global $RASPageName, $SuffixPattern, $GroupPattern, $WikiWordPattern,
    $LinkWikiWords;
  if (preg_match('/^\\[\\[(.+?)(-&gt;|\\|)(.+?)\\]\\]$/', $trailname, $m)) 
    $trailname = ($m[2] == '|') ? $m[1] : $m[3];
  $trailtext = RetrieveAuthSection($pagename, $trailname);
  $trailname = $RASPageName;
  $t = array();
  $n = 0;
  foreach(explode("\n", htmlspecialchars(@$trailtext, ENT_NOQUOTES)) 
          as $x) {
    $x = preg_replace("/\\[\\[([^\\]]*)-&gt;([^\\]]*)\\]\\]/",'[[$2|$1]]',$x);
    if (!preg_match("/^([#*:]+) \\s* 
          (\\[\\[([^:#!|][^|:]*?)(\\|.*?)?\\]\\]($SuffixPattern)
          | (($GroupPattern([\\/.]))?$WikiWordPattern)) (.*)/x",$x,$match))
       continue;
    if (@$match[6]) {
       if (!$LinkWikiWords) continue;
       $tgt = MakePageName($trailname, $match[6]);
    } else $tgt = MakePageName($trailname,
                               preg_replace('/[#?].+/', '', $match[3]));
    $t[$n]['depth'] = $depth = strlen($match[1]);
    $t[$n]['pagename'] = $tgt;
    $t[$n]['markup'] = $match[2];
    $t[$n]['detail'] = $match[9];
    for($i=$depth;$i<10;$i++) $d[$i]=$n;
    if ($depth>1) $t[$n]['parent']=@$d[$depth-1];
    $n++;
  }
  return $t;
}

/* Reads in the trail and returns an array of previous/next links
   results['next'], results['prev'] are the direct next/prev items in the trail at any level
   results['nextl'], results['prevl'] are the direct next/prev items at the SAME level as $pagename
*/
function FindNextPrev($pagename,$trailname) {
  $t = ReadTrail($pagename,$trailname);
  $results = array('prev'=>'', 'next'=>'', 'prevl'=>'', 'nextl'=>'');
  # Loop looking for our page
  for($i=0;$i<count($t);$i++) {
    if ($t[$i]['pagename']==$pagename) {
      # Found our page
      # Is there a previous (left) link
      if ($i>0) {
        $results['prev'] = $t[$i-1]['markup'];
        # Skim back looking for next link in the same sub-tree level
        for($j=$i-1;$j>=0;$j--) {
          if ($t[$j]['parent'] == $t[$i]['parent']) {
            $results['prevl'] = $t[$j]['markup'];
            break;
          }
          if (!$t[$j]['parent']) break; // optimisation - bailout if we hit top level
        }
      }
      # Is there a next (right) link
      if ($i+1<count($t)) {
        $results['next'] = $t[$i+1]['markup'];
        # Skim forward looking for next link in the same sub-tree level
        for($j=$i+1;$j<count($t);$j++) {
          if ($t[$j]['parent'] == $t[$i]['parent']) {
            $results['nextl'] = $t[$j]['markup'];
            break;
          }
          if (!$t[$j]['parent']) break; // optimisation - bailout if we hit top level
        }
      }
    }
  }
  return $results;
}

function MakeTrailStop($pagename,$trailname) {
  $links = FindNextPrev($pagename,$trailname);
  $prev=$links['prev'];
  $next=$links['next'];
  return "<span class='wikitrail'>&lt;&lt; $prev | $trailname | $next &gt;&gt;</span>";
}

function MakeTrailStopB($pagename,$trailname) {
  $links = FindNextPrev($pagename,$trailname);
  $prev=$links['prev'];
  $next=$links['next'];
  if ($prev) $prev = '&lt; '.$prev.' | ';
  if ($next) $next = ' | '.$next.' &gt;';
  return "<span class='wikitrail'>$prev$trailname$next</span>";


// Generates an array of all page items from root to pagename
function FindCrumbs($pagename,$trailname) {
  $t = ReadTrail($pagename,$trailname);
  $crumbs = array();
  for($i=0;$i<count($t);$i++) {
    if ($t[$i]['pagename']==$pagename) {
      while (@$t[$i]['depth']>0) {
        array_unshift($crumbs, $t[$i]['markup']);
        $i = @$t[$i]['parent'];
      }
      break;
    }
  }
  return $crumbs;
}

function MakeTrailPath($pagename,$trailname) {
  global $TrailPathSep;
  SDV($TrailPathSep,' | ');
  $crumbs = FindCrumbs($pagename,$trailname);

  if (count($crumbs)) {
    return "<span class='wikitrail'>$trailname$TrailPathSep" .
            join($TrailPathSep, $crumbs) .
            "</span>";
  } else {
    return $trailname;
  }
}