// Software engineers look away now unless you wish to be horrified by the amount
// of coupling and cohesion in these functions. I'm warning you... it's not pretty
if (!class_exists('smd_MLP')) {
class smd_MLP {
	var $smd_strings;
	var $smd_owner;
	var $smd_prefix;
	var $smd_lang;
	var $smd_event;
	function smd_MLP($plug, $prefx, $strarray, $lng='en-gb', $ev='public') {
		$this->smd_owner = $plug;
		$this->smd_prefix = $prefx;
		$this->smd_strings = $strarray;
		$this->smd_lang = $lng;
		$this->smd_event = $ev;
		register_callback(array(&$this, 'smd_Callback'), 'l10n.enumerate_strings');
	}
	function smd_Callback($event='l10n.enumerate_strings', $step='', $pre=0) {
		$r = array(
			'owner' => $this->smd_owner,
			'prefix' => $this->smd_prefix,
			'lang' => $this->smd_lang,
			'event' => $this->smd_event,
			'strings' => $this->smd_strings,
		);
		return $r;
	}
	// Generic lookup
	//  $what = key to look up
	//  $args = any arguments the key is expecting for replacement
	function gTxt($what, $args = array()) {
		global $textarray;

		// Prepare the prefixed key for use
		$key = $this->smd_prefix . '-' . $what;
		$key = strtolower($key);

		// Grab from the global textarray (possibly edited by MLP) if we can
		if(isset($textarray[$key])) {
			$str = $textarray[$key];
		} else {
			// The string isn't in the localised textarray so fallback to using
			// the (non prefixed) string array in the plugin
			$key = strtolower($what);
			$str = (isset($this->smd_strings[$key])) ? $this->smd_strings[$key] : $what;
		}
		// Perform substitutions
		if(!empty($args)) {
			$str = strtr($str, $args);
		}

		return $str;
	}
}
}

if (!function_exists("smd_doList")) {
function smd_doList($lst, $rng=true, $sub="", $qte=true, $dlm=",", $lax=true) {
	global $thisarticle, $thisimage, $thisfile, $thislink, $pretext, $variable;

	$inc = $exc = array();
	$lst = do_list($lst, $dlm);

	// Sometimes pesky Unicode is not compiled in. Detect if so and fall back to ASCII
	if (!@preg_match('/\pL/u', 'a')) {
		$modRE = ($lax) ? '/(\?|\!)([A-Za-z0-9_\- ]+)/' : '/(\?|\!)([A-Za-z0-9_\-]+)/';
	} else {
		$modRE = ($lax) ? '/(\?|\!)([\p{L}\p{N}\p{Pc}\p{Pd}\p{Zs}]+)/' : '/(\?|\!)([\p{L}\p{N}\p{Pc}\p{Pd}]+)/';
	}

	foreach ($lst as $item) {
		$mod = 0; // 0 = include, 1 = exclude
		$numMods = preg_match_all($modRE, $item, $mods);

		for ($modCtr = 0; $modCtr < $numMods; $modCtr++) {
			// mod "type" is governed by the first one found only. i.e. if "article-?c!s" was used in one field
			// it would be an "include" of the word "article-" plus the category and section concatenated
			$mod = ($mods[1][0] === "!") ? 1 : 0;
			$modChar = $mods[1][$modCtr];
			$modItem = trim($mods[2][$modCtr]);
			$lowitem = strtolower($modItem);
			if (isset($variable[$lowitem])) {
				$item = str_replace($modChar.$modItem, $variable[$lowitem], $item);
			} else if (isset($thisimage[$lowitem])) {
				$item = str_replace($modChar.$modItem, $thisimage[$lowitem], $item);
			} else if (isset($thisfile[$lowitem])) {
				$item = str_replace($modChar.$modItem, $thisfile[$lowitem], $item);
			} else if (isset($thislink[$lowitem])) {
				$item = str_replace($modChar.$modItem, $thislink[$lowitem], $item);
			} else if (array_key_exists($lowitem, $pretext)) {
				$item = str_replace($modChar.$modItem, $pretext[$lowitem], $item);
			} else if (isset($_POST[$modItem])) {
				$item = str_replace($modChar.$modItem, $_POST[$modItem], $item);
			} else if (isset($_GET[$modItem])) {
				$item = str_replace($modChar.$modItem, $_GET[$modItem], $item);
			} else if (isset($_SERVER[$modItem])) {
				$item = str_replace($modChar.$modItem, $_SERVER[$modItem], $item);
			} else if (isset($thisarticle[$lowitem])) {
				$item = str_replace($modChar.$modItem, $thisarticle[$lowitem], $item);
			} else {
				$item = str_replace($modChar.$modItem, $modItem, $item);
			}
		}

		// Handle ranges of values
		$sitem = do_list($item, $dlm);
		foreach ($sitem as $idx => $elem) {
			if ($rng && preg_match('/^(\d+)\-(\d+)$/', $elem)) {
				list($lo, $hi) = explode("-", $elem, 2);
				$sitem[$idx] = implode($dlm, range($lo, $hi));
			}
		}
		$item = implode($dlm, $sitem);

		// Item may be empty; ignore it if so
		if ($item) {
			$item = do_list($item, $dlm);

			// Handle sub-categories
			if ($sub) {
				list($subtype, $level) = explode(":", $sub);
				$level = (empty($level)) ? 0 : $level;
				$level = (strtolower($level)=="all") ? 99999 : $level;
				$outitems = array();
				foreach ($item as $cat) {
					$cats = getTree(doslash($cat), $subtype);
					foreach ($cats as $jdx => $val) {
						if ($cats[$jdx]['level'] <= $level) {
							$outitems[] = $cats[$jdx]['name'];
						}
					}
				}
				$item = $outitems;
			}

			// Quote if asked
			$item = ($qte) ? doArray($item, 'doQuote') : $item;
			if ($mod === 0) {
				$inc = array_unique(array_merge($inc, $item));
			} else {
				$exc = array_unique(array_merge($exc, $item));
			}
		}
	}
	return array($inc, $exc);
}
}

// Split a string on a pattern and allow integer ranges to be expanded
if (!function_exists("smd_split")) {
function smd_split($str, $allowRange=true, $splitat="/(,|,\s)+/", $pregopt = PREG_SPLIT_NO_EMPTY) {
	$retarr = array();
	if ((substr($splitat,0,1) == "/") && (substr($splitat, strlen($splitat)-1, 1) == "/")) {
		$pat = $splitat;
	} else {
		$pat = '/['.$splitat.']+/';
	}
	$elems = preg_split($pat, $str, -1, $pregopt);
	foreach ($elems as $item) {
		$item = trim($item);
		$negate = false;
		// Does the item start with a negation character
		if (substr($item,0,1) === "!") {
			$negate = true;
			$item = substr($item,1);
		}
		// Is the item an integer list range
		if ($allowRange && preg_match('/^(\d+)\-(\d+)$/', $item)) {
			list($lo, $hi) = explode("-", $item, 2);
			$rng = range($lo, $hi);
			// Reapply the negation if necessary
			for($idx = 0; $idx < count($rng); $idx++) {
				$rng[$idx] = (($negate) ? "!" : "") . $rng[$idx];
			}
			$retarr = array_merge($retarr, $rng);
		} else {
			$retarr[] = (($negate) ? "!" : "") . $item;
		}
	}
	return $retarr;
}
}

if (!function_exists("smd_doDblQuote")) {
function smd_doDblQuote($val) {
	return '"'.$val.'"';
}
}

if (!function_exists("smd_removeQSVar")) {
function smd_removeQSVar($url, $key) {
	$url = preg_replace('/(.*)(\?|&)' . $key . '=[^&]+?(&)(.*)/i', '$1$2$4', $url . '&');
	$url = substr($url, 0, -1);
	return ($url);
}
}

if (!function_exists("smd_addQSVar")) {
function smd_addQSVar($url, $key, $value) {
	$url = smd_removeQSVar($url, $key);
	if (strpos($url, '?') === false) {
		return ($url . '?' . $key . '=' . $value);
	} else {
		return ($url . '&' . $key . '=' . $value);
	}
}
}

// DEPRECATED: for backwards compatibility only
if (!function_exists("smd_getSubCats")) {
function smd_getSubCats($parent,$cattype) {
	return getTree($parent,$cattype); //getTree() or getTreePath()??
}
}

// DEPRECATED: for backwards compatibility only
if (!function_exists("smd_getOpts")) {
function smd_getOpts($str, $allowed, $idprefix="", $allowRange=true, $splitat="/(,|,\s)+/", $pregopt = PREG_SPLIT_NO_EMPTY) {
	global $pretext, $thisarticle;

	$out = array();
	$notout = array();
	$matches = smd_split($str, $allowRange, $splitat, $pregopt);
	// An array that tells the loop what to do with each of the valid strings
	//  arg1: type (1=exact match, 2=anywhere within string, 3=custom field)
	//  arg2: prefix, if any
	//  arg3: variable to substitute
	//  arg4: extra check, if applicable
	//  arg5: store in the in/exclude list (1=include; 2=exclude)
	$opt = array(
		"?c" => array(2, "", $pretext['c'], "1", 1),
		"!c" => array(2, "", $pretext['c'], "1", 2),
		"?s" => array(2, "", $pretext['s'], "1", 1),
		"!s" => array(2, "", $pretext['s'], "1", 2),
		"?q" => array(2, "", $pretext['q'], "1", 1),
		"!q" => array(2, "", $pretext['q'], "1", 2),
		"?t" => array(2, "", $thisarticle['url_title'], '$thisarticle!=NULL', 1),
		"!t" => array(2, "", $thisarticle['url_title'], '$thisarticle!=NULL', 2),
		"?id" => array(1, $idprefix, $pretext['id'], '$thisarticle!=NULL', 1),
		"!id" => array(1, $idprefix, $pretext['id'], '$thisarticle!=NULL', 2),
		"?" => array(3, "", "", '$thisarticle!=NULL', 1),
		"!" => array(3, "", "", '$thisarticle!=NULL', 2),
	);

	for ($idx = 0; $idx < count($matches); $idx++) {
		$matched = false;
		$thismatch = $matches[$idx];
		foreach ($opt as $var => $args) {
			$opvar = ($args[4] == 1) ? "out" : "notout";
			switch ($args[0]) {
				case 1:
					if (($thismatch === $var) && in_array($var,$allowed)) {
						$matched = true;
						if ($args[2] != "" && $args[3]) {
							$rep = str_replace($var, $args[1].$args[2], $thismatch);
							if (!in_array($rep, ${$opvar})) {
								${$opvar}[] = $rep;
							}
						}
					}
					break;
				case 2:
					$pat = '/\\'.$var.'$|\\'.$var.'[^A-Za-z0-9]/';
					if ((is_int(smd_pregPos($pat, $thismatch, $fnd))) && in_array($var,$allowed)) {
						$matched = true;
						if ($args[2] != "" && $args[3]) {
							$rep = str_replace($var, $args[1].$args[2], $thismatch);
							if (!in_array($rep, ${$opvar})) {
								${$opvar}[] = $rep;
							}
						}
					}
					break;
				case 3:
					$len = strlen($var);
					if ((substr($thismatch,0,$len) === $var) && in_array($var."field",$allowed)) {
						$matched = true;
						// Use the given field name; which may be a comma-separated sublist.
						// Split off the field name from the question mark
						$fieldname = substr($thismatch,$len);
						if (($args[3]) && (isset($thisarticle[strtolower($fieldname)]))) {
							$fieldContents = $thisarticle[strtolower($fieldname)];
						} else {
							$fieldContents = $fieldname;
						}
						if (!empty($fieldContents)) {
							$subout = smd_split(strip_tags($fieldContents), $allowRange, $splitat, $pregopt);
							foreach ($subout as $subname) {
								if (!in_array($subname, ${$opvar})) {
									${$opvar}[] = $subname;
								}
							}
						}
					}
					break;
			}
			if ($matched) {
				break;
			}
		}
		if (!$matched) {
			// Assign the variable verbatim
			if (!in_array($thismatch, $out)) {
				$out[] = $thismatch;
			}
		}
	}
	return array($out,$notout);
}
}

// Stolen from php.net: strpos page comments...
if (!function_exists("smd_pregPos")) {
function smd_pregPos($sPattern, $sSubject, &$FoundString, $iOffset = 0) {
	$FoundString = null;
	if (preg_match($sPattern, $sSubject, $aMatches, PREG_OFFSET_CAPTURE, $iOffset) > 0) {
		$FoundString = $aMatches[0][0];
		return $aMatches[0][1];
	} else {
		return false;
	}
}
}
//... and array_combine...
if (!function_exists("array_combine")) {
	function array_combine($arr1,$arr2) {
		$out = array();
		foreach($arr1 as $key1 => $value1) {
			$out[$value1] = $arr2[$key1];
		}
   	return $out;
	}
}
//... and htmlspecialchars_decode
if (!function_exists("htmlspecialchars_decode")) {
	function htmlspecialchars_decode($string, $quote_style = ENT_COMPAT) {
		return strtr($string, array_flip(get_html_translation_table(HTML_SPECIALCHARS, $quote_style)));
	}
}