<?php
/**
 * The Horde_Array:: class provides various methods for array manipulation.
 *
 * $Horde: horde/lib/Array.php,v 1.6 2003/08/21 15:49:22 mdjukic Exp $
 *
 * Copyright 2003 Michael Slusarz <slusarz@bigworm.colorado.edu>
 * Copyright 2003 Marko Djukic <marko@oblo.com>
 *
 * See the enclosed file COPYING for license information (LGPL). If you
 * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
 *
 * @author  Michael Slusarz <slusarz@bigworm.colorado.edu>
 * @author  Marko Djukic <marko@oblo.com>
 * @version $Revision: 1.6 $
 * @since   Horde 3.0
 * @package horde
 */
class Horde_Array {

    /**
     * Prepare a list of addresses for storage.
     * Namely, trims and lowercases all addresses and then sort.
     *
     * @access public
     *
     * @param array $addr  The list of addresses.
     *
     * @return array  The list of addresses, prepared for storage.
     */
    function prepareAddressList($addr)
    {
        /* Remove any extra space in the address and make it lowercase. */
        $addr = array_map('trim', $addr);
        $addr = array_map(array('String', 'lower'), $addr);

        /* Remove duplicate entries. */
        $addr = array_unique($addr);

        /* Sort the list. */
        usort($addr, array('Horde_Array', 'sortAddressList'));

        return $addr;
    }

    /**
     * Function used by usort() to sort an address list.
     * e.g. usort($foo, array('Horde_Array', 'sortAddressList'));
     *
     * @access public
     *
     * @param string $a  Address #1.
     * @param string $b  Address #2.
     *
     * @return integer  -1, 0, or 1.
     */
    function sortAddressList($a, $b)
    {
        $a = explode('@', $a);
        $b = explode('@', $b);

        /* One of the addresses doesn't have a host name. */
        if (empty($a[0])) {
            array_shift($a);
        }
        if (empty($b[0])) {
            array_shift($b);
        }
        if (count($a) != count($b)) {
            return (count($a) > count($b));
        }

        /* The addresses have different hostname or not hostname and
           different mailbox names. */
        if ($a[(count($a) - 1)] != $b[(count($b) - 1)]) {
            return strcmp($a[(count($a) - 1)], $b[(count($b) - 1)]);
        }

        /* Compare mailbox names. */
        return strcmp($a[0], $b[0]);
    }

    /**
     * Sorts an array on a specified key. If the key does not exist,
     * defaults to the first key of the array.
     *
     * @access public
     *
     * @param array &$array                The array to be sorted, passed
     *                                     by reference.
     * @param optional string $key         The key by which to sort. If not
     *                                     specified then the first key is
     *                                     used.
     * @param optional integer $direction  Sort direction
     *                                     0 = ascending (default)
     *                                     1 = descending
     */
    function arraySort(&$array, $key = null, $direction = 0)
    {
        /* Return if an empty array. */
        if (empty($array)) {
            return;
        }

        /* No key to sort by is specified, use the first key. */
        if (is_null($key)) {
            $keys = array_keys($array);
            $key = $keys[0];
        }

        /* Create the function that will be used to sort the keys. */
        $function = sprintf('return String::lower($a[\'%1$s\']) %2$s String::lower($b[\'%1$s\']) ? 1 : -1;', $key, ($direction ? '<' : '>'));

        /* Call the sort function, preserving array key association. */
        uasort($array, create_function('$a, $b', $function));
    }

    /**
     * Given an HTML type array field "example[key1][key2][key3]" breaks up the
     * keys so that they could be used to reference a regular PHP array.
     *
     * @access public
     *
     * @param string $field                The field name to be examined.
     */
    function getArrayParts($field, &$base, &$keys)
    {
        if (preg_match('|([^\[]*)((\[[^\[\]]*\])+)|', $field, $matches)) {
            $base = $matches[1];
            $keys = explode('][', $matches[2]);
            $keys[0] = substr($keys[0], 1);
            $keys[count($keys) - 1] = substr($keys[count($keys) - 1], 0, strlen($keys[count($keys) - 1]) - 1);
            return true;
        } else {
            return false;
        }
    }

    /**
     * Using an array of keys itarate through the array following the keys to
     * find the final key value. If a value is passed then set that value.
     *
     * @access public
     *
     * @param array &$array          The array to be used.
     * @param array &$keys           The key path to follow as an array.
     * @param optional array $value  If set the target element will have this
     *                               value set to it.
     *
     * @returns mixed  The final value of the key path.
     */
    function getElement(&$array, &$keys, $value = null)
    {
        if (count($keys) > 0) {
            $key = array_shift($keys);
            return Horde_Array::getElement($array[$key], $keys, $value);
        } else {
            if (!is_null($value)) {
                $array = $value;
            }
            return $array;
        }
    }

}
