<?php
/*
	Question2Answer by Gideon Greenspan and contributors
	http://www.question2answer.org/

	File: qa-include/util/sort.php
	Description: A useful general-purpose 'sort by' function


	This program is free software; 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.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	More about this license: http://www.question2answer.org/license.php
*/

	if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser
		header('Location: ../');
		exit;
	}


	function qa_sort_by(&$array, $by1, $by2=null)
/*
	Sort the $array of inner arrays by sub-element $by1 of each inner array, and optionally then by sub-element $by2
*/
	{
		global $qa_sort_by_1, $qa_sort_by_2;

		$qa_sort_by_1=$by1;
		$qa_sort_by_2=$by2;

		uasort($array, 'qa_sort_by_fn');
	}


	function qa_sort_by_fn($a, $b)
/*
	Function used in uasort to implement qa_sort_by()
*/
	{
		global $qa_sort_by_1, $qa_sort_by_2;

		$compare=qa_sort_cmp($a[$qa_sort_by_1], $b[$qa_sort_by_1]);

		if (($compare==0) && $qa_sort_by_2)
			$compare=qa_sort_cmp($a[$qa_sort_by_2], $b[$qa_sort_by_2]);

		return $compare;
	}


	function qa_sort_cmp($a, $b)
/*
	General comparison function for two values, textual or numeric
*/
	{
		if (is_numeric($a) && is_numeric($b)) // straight subtraction won't work for floating bits
			return ($a==$b) ? 0 : (($a<$b) ? -1 : 1);
		else
			return strcasecmp($a, $b); // doesn't do UTF-8 right but it will do for now
	}


	function qa_array_insert(&$array, $beforekey, $addelements)
/*
	Inserts $addelements into $array, preserving their keys, before $beforekey in that array.
	If $beforekey cannot be found, the elements are appended at the end of the array.
*/
	{
		$newarray=array();
		$beforefound=false;

		foreach ($array as $key => $element) {
			if ($key==$beforekey) {
				$beforefound=true;

				foreach ($addelements as $addkey => $addelement)
					$newarray[$addkey]=$addelement;
			}

			$newarray[$key]=$element;
		}

		if (!$beforefound)
			foreach ($addelements as $addkey => $addelement)
				$newarray[$addkey]=$addelement;

		$array=$newarray;
	}


//	Special values for the $beforekey parameter for qa_array_reorder() - use floats since these cannot be real keys

	define('QA_ARRAY_WITH_FIRST', null); // collect the elements together in the position of the first one found
	define('QA_ARRAY_WITH_LAST', 0.6); // collect the elements together in the position of the last one found
	define('QA_ARRAY_AT_START', 0.1); // place all the elements at the start of the array
	define('QA_ARRAY_AT_END', 0.9); // place all the elements at the end of the array

	function qa_array_reorder(&$array, $keys, $beforekey=null, $reorderrelative=true)
/*
	Moves all of the elements in $array whose keys are in the parameter $keys. They can be moved to before a specific
	element by passing the key of that element in $beforekey (if $beforekey is not found, the elements are moved to the
	end of the array). Any of the QA_ARRAY_* values defined above can also be passed in the $beforekey parameter.
	If $reorderrelative is true, the relative ordering between the elements will also be set by the order in $keys.
*/
	{

	//	Make a map for checking each key in $array against $keys and which gives their ordering

		$keyorder=array();
		$keyindex=0;
		foreach ($keys as $key)
			$keyorder[$key]=++$keyindex;

	//	Create the new key ordering in $newkeys

		$newkeys=array();
		$insertkeys=array();
		$offset=null;

		if ($beforekey==QA_ARRAY_AT_START)
			$offset=0;

		foreach ($array as $key => $value) {
			if ($beforekey==$key)
				$offset=count($newkeys);

			if (isset($keyorder[$key])) {
				if ($reorderrelative)
					$insertkeys[$keyorder[$key]]=$key; // in order of $keys parameter
				else
					$insertkeys[]=$key; // in order of original array

				if ( ($beforekey==QA_ARRAY_WITH_LAST) || (($beforekey===QA_ARRAY_WITH_FIRST) && !isset($offset)) )
					$offset=count($newkeys);

			} else
				$newkeys[]=$key;
		}

		if (!isset($offset)) // also good for QA_ARRAY_AT_END
			$offset=count($newkeys);

		if ($reorderrelative)
			ksort($insertkeys, SORT_NUMERIC); // sort them based on position in $keys parameter

		array_splice($newkeys, $offset, 0, $insertkeys);

	//	Rebuild the array based on the new key ordering

		$newarray=array();

		foreach ($newkeys as $key)
			$newarray[$key]=$array[$key];

		$array=$newarray;
	}


/*
	Omit PHP closing tag to help avoid accidental output
*/