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

/*
 * DESCRIPTION:  The Cluster recipe adds group-clustering
 * functionality to PmWiki, in a pseudo-hierarchical way.
 * For info, see http://www.pmwiki.org/wiki/Cookbook/Cluster
 * Based on Hg by Dan Vis  <editor àt fast döt st>, Copyright 2007.
 * 	see http://www.pmwiki.org/wiki/Cookbook/Hg
 * Modified by: Kathryn Andersen
 */

/*
 * Set up various variables
 */
$RecipeInfo['Cluster']['Version'] = '2007-03-19';
SDV($ClusterSeparator, '-');
SDV($ClusterMaxLevels, 7);
SDV($ClusterBreadCrumbSeparator, $ClusterSeparator);

/* ================================================================
 * Page Variables
 */
$FmtPV['$g0'] = 'ClusterCountLevels($group)';
$FmtPV['$n0'] = 'ClusterCountLevels($name)';
for ($i=0; $i < $ClusterMaxLevels; $i++) {
	$hg = "g" . ($i + 1);
	$hn = "n" . ($i + 1);
	$FmtPV['$' . $hg] = 'ClusterSplitName($group, ' . $i . ')';
	$FmtPV['$' . $hn] = 'ClusterSplitName($name, ' . $i . ')';
}
$FmtPV['$SideBar'] = 'ClusterSideBarName($group)';
$FmtPV['$GroupTitle'] = 'ClusterGroupTitle($pn, $var)';
$FmtPV['$GroupTitlespaced'] = 'ClusterGroupTitle($pn, $var)';
//$FmtPV['$ClusterRightBar'] = 'ClusterRightBarName($group)';
$FmtPV['$RightBar'] = 'ClusterRightBarName($group)';
$FmtPV['$BreadCrumb'] = 'ClusterBreadCrumb($pn)';
$FmtPV['$BreadCrumbTitles'] = 'ClusterBreadCrumb($pn,true)';

/* ================================================================
 * Markup for link shortcuts
 */
Markup('[[cluster','<var','/\\[\\[(-|[\\*\\^]+)(.*?)\\]\\]/e', 'ClusterLinks($pagename, "$1", "$2")');

/* ================================================================
 * Set up clustered configurations
 */
$pagename = ResolvePageName($pagename);
$EnablePGCust = 0;
$m = preg_split('/[.\\/]/', $pagename);
$group = $m[0];
$name = $m[1];

$found_config = false;
$found_grouphead = false;
$found_groupfoot = false;
$found_attr = false;
if (file_exists("$LocalDir/$group.$name.php")) {
	include_once("$LocalDir/$group.$name.php");
	$found_config = true;
}
$PageCSSListFmt["pub/css/$group.$name.css"] = "$PubDirUrl/css/$group.$name.css"; 
$groups = explode($ClusterSeparator, $group);
while (count($groups) != 0) {
	$cluster_group = implode ($ClusterSeparator, $groups);
	if (!$found_config && file_exists("$LocalDir/$cluster_group.php")) {
		include_once("$LocalDir/$cluster_group.php");
		$found_config = true;
	}
	if (!$found_grouphead && PageExists("$cluster_group.GroupHeader")) {
//		$GroupHeaderFmt = "(:include $cluster_group.GroupHeader self=0 basepage={*$FullName}:)(:nl:)";
		$GroupHeaderFmt = "(:include $cluster_group.GroupHeader self=0:)(:nl:)";
		$found_grouphead = true;
	}
	if (!$found_groupfoot && PageExists("$cluster_group.GroupFooter")) {
//		$GroupFooterFmt = "(:nl:)(:include $cluster_group.GroupFooter self=0 basepage={*$FullName}:)";
		$GroupFooterFmt = "(:nl:)(:include $cluster_group.GroupFooter self=0:)";
		$found_groupfoot = true;
	}
	if (!$found_attr && PageExists("$cluster_group.GroupAttributes")) {
		$GroupAttributesFmt = "$cluster_group.GroupAttributes";
		$found_groupfoot = true;
	}
	$PageCSSListFmt["pub/css/$cluster_group.css"] = "$PubDirUrl/css/$cluster_group.css"; 
	array_pop($groups);
}
// set the defaults for those that haven't been found
if (!$found_config && file_exists("$LocalDir/$default.php")) {
	include_once("$LocalDir/$default.php");
}
if (!$found_grouphead && PageExists("$SiteGroup.GroupHeader")) {
//	$GroupHeaderFmt = "(:include $SiteGroup.GroupHeader self=0 basepage={*$FullName}:)(:nl:)";
	$GroupHeaderFmt = "(:include $SiteGroup.GroupHeader self=0:)(:nl:)";
}
if (!$found_groupfoot && PageExists("$SiteGroup.GroupFooter")) {
//	$GroupFooterFmt = "(:nl:)(:include $SiteGroup.GroupFooter self=0 basepage={*$FullName}:)";
	$GroupFooterFmt = "(:nl:)(:include $SiteGroup.GroupFooter self=0:)";
}
$PageCSSListFmt["pub/css/local.css"] = "$PubDirUrl/css/local.css";
$PageCSSListFmt = array_reverse($PageCSSListFmt, true);

/* ================================================================
 * Vars, mostly to help the skins know we have pieces they do not realize.
 * Inserted for clever skins, such as triad, so they can determine if we have a
 * right bar they do not know about.
 *
 * [Feral:075/07@19:23] Note that Cookbook:TriadSkin defines it's own
 * $RightBar; In my opinion it is always good practice to avoid name colisions
 * ;)
 *
 */
$ClusterRightBar = ClusterRightBarName($group);

/* ================================================================
 * Functions
 */
function ClusterCountLevels($name) {
	global $ClusterSeparator;
	$parts = explode($ClusterSeparator, $name);
	return count($parts);
}

function ClusterSplitName($name, $ind) {
	global $ClusterSeparator;
	$parts = explode($ClusterSeparator, $name);
	if ($ind < 0 || $ind >= count($parts)) return '';
	else return $parts[$ind];
}

function ClusterGroupTitle($pagename, $var, $fmt = NULL) {
	global $DefaultName, $SpaceWikiWords, $AsSpacedFunction;
	// look for a group-title for this specific group, first
	if (is_null($fmt)) {
		SDV($GroupTitlePathFmt,
		    array(
			  '$Group.GroupAttributes', '$Group.GroupHeader', 
			  '$Group.GroupFooter', '$Group.$Group', "\$Group.$DefaultName"));
		$fmt = $GroupTitlePathFmt;
	}
	foreach((array)$fmt as $f) {
		$pn = FmtPageName($f, $pagename);
		$page = ReadPage($pn, READPAGE_CURRENT);
		if ($page['title']) { return $page['title']; }
	}

	// okay, didn't find one
	$num_parts = PageVar($pagename, '$g0');
	if ($num_parts == 1)
	{
		$grouptitle = PageVar($pagename, '$Group');
	}
	else {
		// get the last part of the group
		$grouptitle = PageVar($pagename, '$g' . PageVar($pagename, '$g0'));
	}
	return ($var == '$GroupTitlespaced' || $SpaceWikiWords)
		? $AsSpacedFunction($grouptitle) : $grouptitle;
}

function ClusterSideBarName($group) {
	global $ClusterSeparator;
	global $SiteGroup;
	$groups = explode($ClusterSeparator, $group);
	while (count($groups) != 0) {
		$cluster_group = implode ($ClusterSeparator, $groups);
		if (PageExists("$cluster_group.SideBar")) {
			// short-circuit return!
			return "$cluster_group.SideBar";
		}
		array_pop($groups);
	}
	return "$SiteGroup.SideBar";
}

function ClusterRightBarName($group) {
	global $ClusterSeparator;
	global $SiteGroup;
	$groups = explode($ClusterSeparator, $group);
	while (count($groups) != 0) {
		$cluster_group = implode ($ClusterSeparator, $groups);
		if (PageExists("$cluster_group.RightBar")) {
			// short-circuit return!
			return "$cluster_group.RightBar";
		}
		array_pop($groups);
	}
	return "$SiteGroup.RightBar";
}

function ClusterLinks($pagename, $prefix, $inlink) {
	global $ClusterSeparator;
	$group = FmtPageName('$Group', $pagename);
	if ($prefix == "-") {
		return "[[$group$ClusterSeparator$inlink]]";
	}
	$groups = explode($ClusterSeparator, $group);
	$c = strlen($prefix);
	$i = 0;
	while ($i < $c) {
		if (substr($prefix, 0, 1) == "*") $link = $link . $groups[$i] . $ClusterSeparator;
		if (substr($prefix, 0, 1) == "^") array_pop($groups);
		$i = $i + 1;
	}
	if (substr($prefix, 0, 1) == "*") $link = substr ($link, 0, -1);
	if (substr($prefix, 0, 1) == "^") $link = implode($ClusterSeparator, $groups);
	return "[[$link$inlink]]";
}


function ClusterBreadCrumb($pagename, $usetitles=false)
{
	global $ClusterSeparator;
	global $ClusterBreadCrumbSeparator;
	global $DefaultName;

	$m = preg_split('/[.\\/]/', $pagename);
	$group = $m[0];
	$name = $m[1];

	$out = "";
	$groups = explode($ClusterSeparator, $group);

	$number = count($groups);
	for ($i=0; $i < $number; $i++)
	{
		if	(	$i != 0)
		{
			$out.= " $ClusterBreadCrumbSeparator ";
		}

		$out.= '[[';

		$path = '';
		for	($num = 0; $num <= $i; $num++)
		{
			if	(	$num != 0)
			{
				$path.= $ClusterSeparator;
			}

			$path.= $groups[$num];
		}

		$out.= $path.'/|';
		if	(	$usetitles)
		{
			$out.= '{'.$path.'$Title}';
		}
		else
		{
			$out.= $groups[$i];
		}
		$out.= ']]';
	}

	if ($name != $DefaultName && $name != $group)
	{
		$out .= " $ClusterBreadCrumbSeparator ";
		$out .= "'''" . '{*$Namespaced}' . "'''";
	}

	return $out;
}

// [Feral:075/07@16:35] Seems to work great!
// Usage: Place in config.php: // (This is for Cookbook:TriadSkin, but the idea is the same for any)
//$GroupTitleFmt="<div id='pagegroup'>";
//$GroupTitleFmt.="<div id=\"ClusterBreadCrumbTrail\">";
//$GroupTitleFmt.=ClusterBreadCrumbHTML($pagename, false);
//$GroupTitleFmt.="</div>";
//$GroupTitleFmt.="<div id=\"ClusterBreadCrumbTrailLast\">";
//$GroupTitleFmt.="<a href='\$ScriptUrl/\$Group/'>$grouptitle</a>";
//$GroupTitleFmt.="</div>";
//$GroupTitleFmt.="</div>";
function ClusterBreadCrumbHTML($pagename, $include_last=false, $usetitles=false)
{
	global $DefaultName;
	global $ClusterSeparator;
	global $ScriptUrl;
	global $EnablePathInfo;

	// For $usetitles = true;
	// In pmwiki.php: $PagePathFmt = array('{$Group}.$1','$1.$1','$1.{$DefaultName}');
	$pagepossibles = array("$group_path.$group_path","$group_path.$DefaultName");

	if	(	$EnablePathInfo)
	{
		$path_part = '/';
		$path_tail = $path_part;
	}
	else
	{
		$path_part = '?n=';
		$path_tail = '';
	}

	$m = preg_split('/[.\\/]/', $pagename);
	$group = $m[0];
	$name = $m[1];

	$out = "";
	$groups = explode($ClusterSeparator, $group);

	$depth = 0;
	$count_groups = count($groups) -1;
	foreach($groups as $item)
	{

		if	(	!$include_last)
		{
			if	(	$depth >= $count_groups)
			{
				break;
			}
		}

		$depth_index = 0;
		$group_path = '';
		for($depth_index = 0; $depth_index <= $depth; $depth_index++)
		{
			if	(	$depth_index>0)
			{
				$group_path .= "$ClusterSeparator";
			}
			$group_path .= $groups[$depth_index];
		}

		if	(	$usetitles)
		{
			$path_name = '';
			foreach($pagepossibles as $try)
			{
				if	(	PageExists($try) )
				{
					$page = ReadPage($try, READPAGE_CURRENT);
					if	(	$page['title'])
					{
						$path_name = $page['title'];
						break;
					}
				}
			}
			if	(	!$path_name)
			{
				$path_name = $item;
			}
		}
		else
		{
			$path_name = $item;
		}

		if	(	$depth>0)
		{
			$out.= " $ClusterSeparator ";
		}
		$out.= "<a href=\"$ScriptUrl$path_part$group_path$path_tail\">$path_name</a>";

		$depth++;
	}

	return $out;
}