<?php

class FishTreeLite
{
    function 
findme($values$branch)
    {
        static 
$tick 0;
        if (
$tick++ > 100)
        {
            print 
"OOPS! loopy! $tick\n";
            exit;
        }

        if (!
is_array($values))
            
$values = array($values);

        
// test the whole branch
        
$result FishTreeLite::quicktest($branch$values);
        if (
$result === false)
            return 
false;
        if (
$result === $branch)
            return 
$branch;

        
$output = array();
        
$result false;

        
// test the branch keys
        
$bkeys array_keys($branch);
        
$found array_intersect($values$bkeys);
        if (!empty(
$found))
        {
            
$newvalues array_diff($values$found);
            if (empty(
$newvalues))
            {
                foreach (
$found as $k)
                {
                    
$v $branch[$k];
                    if (empty(
$output[$k]))    
                        
$output[$k] = array();
                    
$output[$k] = FishTreeLite::load_output($output[$k], $v);
                }
            }
            else
            {
                foreach (
$found as $k)
                {
                    
$v $branch[$k];
                    
$result FishTreeLite::findme($newvalues$v);
                    if (
$result !== false)
                    {
                        if (empty(
$output[$k]))    
                            
$output[$k] = array();
                        
$output[$k] = FishTreeLite::load_output($output[$k], $result);
                    }
                }
            }
        }
        else
        {
            foreach (
$branch as $k => $v)
            {
                
$result FishTreeLite::findme($values$v);
                if (
$result !== false)
                    
$output FishTreeLite::load_output($output$result);
            }
        }

        if (empty(
$output))
            
$result false;
        else
            
$result $output;
        return 
$result;
    }

    function 
load_output($output$result)
    {
        foreach (
$result as $rk => $rv)
        {
            if (empty(
$output[$rk]))
                
$output[$rk] = $rv;
            else
                
$output[$rk] = FishTreeLite::mergeme($output[$rk], $rv);
        }
        return 
$output;
    }

    function 
make_tree($rows$rankfields)
    {
        if (empty(
$rows))
            return 
$rows;
        if (empty(
$rankfields))
            return 
$rows;
        
$row current($rows);
        
$fields array_keys($row);
        
$usedrankfields = array();
        
$usedrank 0;
        foreach (
$rankfields as $rank => $fs)
        {
            foreach (
$fs as $f)
            {
                if (
in_array($f$fields))
                    
$usedrankfields[$usedrank][] = $f;
            }
            if (!empty(
$usedrankfields[$usedrank]))
                
$usedrank++;
        }

        
$revranks array_reverse(array_keys($usedrankfields));
        
$maxrank = empty($revranks) ? max($revranks);
        
$tree = array();
        foreach (
$rows as $row)
        {
            
$rt = array();
            foreach (
$revranks as $rank)
            {
                if (
$rank == $maxrank)
                {
                    
$rt null;
                    foreach (
$usedrankfields[$rank] as $f)
                    {
                        
$v $row[$f];
                        if (
$rt === null)
                        {
                            
$rt $v;
                        }
                        elseif (!
is_array($rt) && $rt != $v)    
                        {
                            
$tv $rt;
                            
$rt = array($tv => $v);
                        }
                        else
                        {
                            
$trt $rt;
                            
$rt = array();
                            foreach (
$trt as $rtk => $rtv)
                            {
                                
$rt[$rtk][$rtv] = $v;
                            }
                        }
                    }
                }
                else
                {
                    
$prt $rt;
                    
$rt = array();
                    foreach (
$usedrankfields[$rank] as $f)
                    {
                        if (empty(
$row[$f]))
                            continue;
                        
$v $row[$f];
                        
$rt[$v] = $prt;
                    }
                }
            }
            
$tree FishTreeLite::mergeme($tree$rt);
        }
        
$oosp array_diff(array_keys($tree), array_keys(array_filter($tree'is_array')));
        foreach (
$oosp as $k)
        {
            
$tree[$k] = array($tree[$k]);
        }

        return 
$tree;
    }

    function 
maybe_array_mergeme($output$test$dunno)
    {
        if (
is_array($test))
            return 
$output;

        if (
is_array($dunno))
            
$output FishTreeLite::not_array_mergeme($dunno$test);
        else
            
$output FishTreeLite::not_array_mergeme($output$test);
        return 
$output;
    }

    function 
mergeme($a$b)
    {
        
$output = array();
        
$output FishTreeLite::maybe_array_mergeme($output$a$b);
        
$output FishTreeLite::maybe_array_mergeme($output$b$a);
        if (
count($output) > 0)
            return 
$output;

        
$keys array_unique(array_merge(array_keys($a), array_keys($b)));
        foreach (
$keys as $k)
        {
            if (
                !
FishTreeLite::one_side_only($output$k$a$b)
                &&
                !
FishTreeLite::one_side_only($output$k$b$a)
            )
            {
                if (
$a[$k] == $b[$k])
                    
$output[$k] = $a[$k];
                else
                    
$output[$k] = FishTreeLite::mergeme($a[$k], $b[$k]);
            }
        }
        return 
$output;
    }

    function 
not_array_mergeme($array$notarray)
    {
        if (empty(
$array))
        {
            
$array $notarray;
        }
        elseif (!
is_array($array) and $array != $notarray)
        {
            
$t $array;
            
$array = array($t,$notarray);
        }
        elseif (!
in_array($notarray$array))
        {
            
$array[] = $notarray;
        }
        return 
$array;
    }

    function 
one_side_only(&$output$key$maybe$gotta)
    {
        if (
array_key_exists($key,$maybe))
            return 
false;
        
$output[$key] = $gotta[$key];
        return 
true;
    }

    function 
printable($thing)
    {
        return 
preg_replace('/[[:space:]]+/'' 'var_export($thingTRUE));
    }

    function 
quicktest($branch$values)
    {
        if (!
is_array($branch))
        {
            if (
count($values) > 1)
                return 
false;
            
$values array_shift($values);
            if (
$branch != $values)
                return 
false;
            return 
true;
        }

        
$bstring var_export($branchtrue);
        
$result false;
        foreach (
$values as $v)
        {
            if (
strpos($bstring$v) !== FALSE)
            {
                
$result true;
                break;
            }
        }
        return 
$result;
    }
}
?>