<?php if (!defined('PmWiki')) exit();

## FPLTemplate2: an alternative FPLTemplate function
## version 2009-03-15

## Use template found in first of template pages:
SDV($FPLTemplatePageFmt, array('{$FullName}',
	'{$SiteGroup}.LocalTemplates', '{$SiteGroup}.PageListTemplates'));

## Set $FPLFormatOpt array defaults to use FPLTemplate2:
## $FPLFormatOpt is a list of options associated with fmt=
## values.  'default' is used for any undefined values of fmt=.
SDVA($FPLFormatOpt, array(
  'default' => array('fn' => 'FPLTemplate2', 'fmt' => '#default'),
  'bygroup' => array('fn' => 'FPLTemplate2', 'template' => '#bygroup',
                     'class' => 'fplbygroup'),
  'simple'  => array('fn' => 'FPLTemplate2', 'template' => '#simple',
                     'class' => 'fplsimple'),
  'group'   => array('fn' => 'FPLTemplate2', 'template' => '#group',
                     'class' => 'fplgroup'),
  'title'   => array('fn' => 'FPLTemplate2', 'template' => '#title',
                     'class' => 'fpltitle', 'order' => 'title'),
  'count'   => array('fn' => 'FPLCountA'),
  ));

## Default chain of functions called by FPLTemplate2 (defined below)
SDV($FPLTemplateFunctions, array(
	'FPLTemplateLoad','FPLTemplateDefaults','FPLTemplatePageList','FPLTemplateSliceList','FPLTemplateFormat')); 

/* Comment:
The original FPLTemplate function has been broken into five logical parts,
each becoming a seperate function called in sequence as defined 
in array $FPLTemplateFunctions by main FPLTemplate2() function.
Each function called can return HTML formatted output, but only the last, 
FPLTemplateFormat(), does so.
Each function changes relevant arrays passed by reference:
pagelist $matches; pagelist options $opt; template parts $tparts. 
*/
## Main function: call each of $FPLTemplateFunctions in turn
function FPLTemplate2($pagename, &$matches, $opt) {
	global $FPLTemplateFunctions;
	StopWatch("FPLTemplate: Chain begin");
	$fnlist = $FPLTemplateFunctions;
	$out = array();
	foreach((array)$fnlist as $fn) {
		StopWatch("FPLTemplate: $fn");
		$out[] = $fn($pagename, $matches, $opt, $tparts);
	}
	StopWatch("FPLTemplate: Chain end ");
	return implode('',$out);
} //}}}


## load pagelist template from page
function FPLTemplateLoad($pagename, $matches, $opt, &$tparts) {
	global $Cursor, $FPLTemplatePageFmt, $RASPageName, $PageListArgPattern, $FmtV, $FmtPV;
	$template = @$opt['template'];
	if (!$template) $template = @$opt['fmt'];
	$ttext = RetrieveAuthSection($pagename, $template, $FPLTemplatePageFmt);
	$ttext = PVSE(Qualify($RASPageName, $ttext));
	
	##  save any escapes
	$ttext = MarkupEscape($ttext);
	##  remove any anchor markups to avoid duplications
	$ttext = preg_replace('/\\[\\[#[A-Za-z][-.:\\w]*\\]\\]/', '', $ttext);
	
	##  extract portions of template
	$tparts = preg_split('/\\(:(template)\\s+(\\w+)\\s*(.*?):\\)/i', $ttext, -1,
	                 PREG_SPLIT_DELIM_CAPTURE);
} //}}}


## extract args from (:template defaults .....:) and merge with options from (:pagelist :)
function FPLTemplateDefaults($pagename, $matches, &$opt, &$tparts) {
	global $PageListArgPattern;
	$i = 0;
	while ($i < count($tparts)) {
		if ($tparts[$i] != 'template') { $i++; continue; }
		if ($tparts[$i+1] != 'defaults' && $tparts[$i+1] != 'default') { $i+=4; continue; }
		$opt = array_merge(ParseArgs($tparts[$i+2], $PageListArgPattern), $opt);
		array_splice($tparts, $i, 3);
	}
	SDVA($opt, array('class' => 'fpltemplate', 'wrap' => 'div'));	
} //}}}

/* Comment:
Added capability of merging pagelist with any list supplied previously
by custom function.
*/
## get list of pages by calling MakePageList; 
## merge lists if any $matches are supplied previously   
function FPLTemplatePageList($pagename, &$matches, $opt, $tparts) {
  $matches = array_unique(array_merge($matches, MakePageList($pagename, $opt, 0))); 
} //}}}


/* Comment:
Added a start= parameter for (:pagelist .. :)
Added a {$$PageListCount} template variable, 
for total $matches count before any slicing of $matches.
*/
## slice matches according to count= and start= 
function FPLTemplateSliceList($pagename, &$matches, &$opt, $tparts) {
	## count matches before any slicing and save value as template var {$$PageListCount}
	$opt['PageListCount'] = $pagelistcount = count($matches);
	
	##  extract page subset according to 'start=' parameter
	if (@$opt['start']) {
		if ($opt['start'] >= 0)
			$matches = array_slice($matches, $opt['start']-1);
		else 
			$matches = array_slice($matches, $pagelistcount+$opt['start']);
	}
	##  further extract page subset according to 'count=' parameter
	if (@$opt['count']) {
		list($r0, $r1) = CalcRange($opt['count'], $pagelistcount);
		if ($r1 < $r0) 
			$matches = array_reverse(array_slice($matches, $r1-1, $r0-$r1+1));
		else 
			$matches = array_slice($matches, $r0-1, $r1-$r0+1);
	}
} //}}}


/* Comment:
Added of (:template none:) optional template section.
The control structure for the main loop has been changed 
to allow handling of 'no matches' cases.
*/
## format items according to template 
function FPLTemplateFormat($pagename, &$matches, &$opt, &$tparts) {	
	global $Cursor;
	$savecursor = $Cursor;
	$pagecount = 0; $groupcount = 0; $grouppagecount = 0;
	$pseudovars = array('{$$PageCount}' => &$pagecount, 
	                   '{$$GroupCount}' => &$groupcount, 
	                   '{$$GroupPageCount}' => &$grouppagecount);

	foreach(preg_grep('/^[\\w$]/', array_keys($opt)) as $k) 
		if (!is_array($opt[$k]))
			$pseudovars["{\$\$$k}"] = htmlspecialchars($opt[$k], ENT_NOQUOTES);

	$vk = array_keys($pseudovars);
	$vv = array_values($pseudovars);
	
	$lgroup = ''; $out = '';
	$mcount = count($matches);
	for($i=0; $i <= $mcount; $i++) {
		if($i>0 && $i==$mcount) break;
		$pn = $matches[$i];
		$group = PageVar($pn, '$Group');
		if ($group != $lgroup) { $groupcount++; $grouppagecount = 0; $lgroup = $group; }
		$grouppagecount++; $pagecount++;
		$t = 0;
		while ($t < count($tparts)) {
			if ($tparts[$t] != 'template') { 
				if ($mcount!=0) $item = $tparts[$t]; 
				$t++;
			}
			elseif ($mcount==0) {
				if ($tparts[$t] == 'template' && $tparts[$t+1] == 'none')
					$item = $tparts[$t+3];
				$t+=4;
			}
			else {
				list($when, $control, $item) = array_slice($tparts, $t+1, 3); $t+=4;
				if (!$control) {
					if ($when == 'none') continue;
					if ($when == 'first' && $i != 0) continue;
					if ($when == 'last' && $i != $mcount - 1) continue;
				} else {
					if ($when == 'none') continue;
					if ($when == 'first' || !isset($last[$t])) {
						$Cursor['<'] = $Cursor['&lt;'] = (string)@$matches[$i-1];
						$Cursor['='] = $pn;
						$Cursor['>'] = $Cursor['&gt;'] = (string)@$matches[$i+1];
						$curr = str_replace($vk, $vv, $control);
						$curr = preg_replace('/\\{(=|&[lg]t;)(\\$:?\\w+)\\}/e',
						            "PageVar(\$pn, '$2', '$1')", $curr);
						if ($when == 'first' && $i > 0 && $last[$t] == $curr) continue;
						$last[$t] = $curr;
					}
					if ($when == 'last') {
						$Cursor['<'] = $Cursor['&lt;'] = $pn;
						$Cursor['='] = (string)@$matches[$i+1];
						$Cursor['>'] = $Cursor['&gt;'] = (string)@$matches[$i+2];
						$next = str_replace($vk, $vv, $control);
						$next = preg_replace('/\\{(=|&[lg]t;)(\\$:?\\w+)\\}/e',
						            "PageVar(\$pn, '$2', '$1')", $next);
						if ($next == $last[$t] && $i != count($matches) - 1) continue;
						$last[$t] = $next;
					}
				}
			}
			$Cursor['<'] = $Cursor['&lt;'] = (string)@$matches[$i-1];
			$Cursor['='] = $pn;
			$Cursor['>'] = $Cursor['&gt;'] = (string)@$matches[$i+1];
			$item = str_replace($vk, $vv, $item);
			$item = preg_replace('/\\{(=|&[lg]t;)(\\$:?\\w+)\\}/e',
			            "PVSE(PageVar(\$pn, '$2', '$1'))", $item);
			$out .= MarkupRestore($item);
		}
	}
	$class = preg_replace('/[^-a-zA-Z0-9\\x80-\\xff]/', ' ', @$opt['class']);
	if ($class) $class = " class='$class'";
	$wrap = @$opt['wrap'];
	if ($wrap != 'inline') {
		$out = MarkupToHTML($pagename, $out, array('escape' => 0, 'redirect'=>1));
		if ($wrap != 'none') $out = "<div$class>$out</div>";
	}
	$Cursor = $savecursor;
	return $out;
} //}}}