<?php

/*
** Fishlib - a collection of utilities for db-driven applications in PHP
** Copyright (C) 2002  LTWD, LLC DBA The Madfish Group
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License as published by the Free Software Foundation; either
** version 2.1 of the License, or (at your option) any later version.
**
** This library 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
** Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public
** License along with this library; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

require_once('fisherror.class.php');
class 
FishDebug
{
    function 
trace_list($what=NULL$status=NULL)
    {
        static 
$list = array();
        if (
$what)
        {
            if (
$status === TRUE)
            {
                
$list[$what] = 1;
            }
            elseif (
$status === FALSE && isset($list[$what]))
            {
                unset(
$list[$what]);
            }
            return isset(
$list[$what]);
        }
        return 
$list;
    }

    function 
start_trace($file=NULL)
    {
        if (
$file)
        {
            
FishError::push_handler(E_USER_NOTICEH_ALL);
            
$from 'UNKNOWN';
            
$backtrace debug_backtrace();
            if (
count($backtrace))
            {
                
$here array_shift($backtrace);
                
$from = isset($here['file']) ? $here['file'] : $from;
            }
            if (
strstr($file,'()') === FALSE && strstr($file,'::') === FALSE)
            {
                
$file realpath($file);
            }
            else
            {
                
$file strtolower($file);
            }
            echo 
"trace:<ul>\n<li>start_trace: $file\n\tfrom $from\n</ul>\n";
            
$out FishDebug::trace_list($fileTRUE);
            
$out FishDebug::trace_list();
        }
    }

    function 
stop_trace($file=NULL)
    {
        if (
$file)
        { 
            if (
strstr($file,'()') === FALSE && strstr($file,'::') === FALSE)
            {
                
$file realpath($file);
            }
            else
            {
                
$file strtolower($file);
            }
            echo 
"trace:<ul>\n<li>stop_trace: file="$file"\n</ul>\n";
            
FishDebug::trace_list($fileFALSE);
            
FishError::pop_handler(E_USER_NOTICE);
        }
    }

    function 
trace()
    {
        static 
$last_where NULL;
        static 
$failed = array();

        
$p func_get_args();
        
$backtrace debug_backtrace();
        if (
count($backtrace) == 0)
        {
            return;
        }
        
$buf '';

        
$here array_shift($backtrace);
        
$file = isset($here['file']) ? $here['file'] : NULL;
        
$class = isset($here['class']) ? $here['class'] : NULL;
        
$line = isset($here['line']) ? $here['line'] : NULL;
        
// because function ref will be 'trace', back up one to see where
        // we came from
        
$here array_shift($backtrace);
        
$function = isset($here['function']) ? $here['function'] : NULL;
        if (
FishDebug::trace_list($file))
        {
            
// error_log("<li>trace: found file $file in trace list\n");
        
}
        elseif (
FishDebug::trace_list($function.'()'))
        {
            
// error_log( "<li>trace: found function $function in trace list\n");
        
}
        elseif (
FishDebug::trace_list($class.'::'))
        {
            
// error_log("<li>trace: found class $class in trace list\n");
        
}
        else
        {
            if (!isset(
$failed[$file]))
            {
                
// error_log( "<li>trace: did not find file $file in trace list\n");
                
$failed[$file] = 1;
            }
            if (!isset(
$failed[$function]))
            {
                
// error_log( "<li>trace: did not find function $function in trace list\n");
                
$failed[$function] = 1;
            }
            if (!isset(
$failed[$class]))
            {
                
// error_log( "<li>trace: did not find class $class in trace list\n");
                
$failed[$class] = 1;
            }
            return;
        }
        
$buf .= '<li>';
        foreach (
$p as $arg)
        {
            
$tmp $arg;
            if (!
is_string($arg))
            {
                if (
is_object($tmp) && isset($tmp->dbh))
                {
                    
// this is a reference that is getting trashed -
                    // unset it first
                    
unset($tmp->dbh);
                    
$tmp->dbh "used to be dbh here";
                }
                
$tmp var_export($tmpTRUE);
            }
            
$buf .= $tmp;
        }
        
$where '';
        if (
$class)
        {
            
$where .= $class.'::';
        }
        if (
$function)
        {
            
$where .= $function.':';
        }
        
$where .= $file;
        if (
$where != $last_where)
        {
            
$buf .= "\n\tfrom $where";
            
$last_where $where;
        }
        
$buf .= ": line $line\n<hr>\n";
        echo 
"trace:<ul>\n"$buf"\n</ul>\n";
        
// error_log('trace:'.$buf);
    
}

    function 
watch($files=array(),$direction=TRUE)
    {
        static 
$stack = array();
        foreach((array)
$files as $file)
        {
            
$stack[] = $file;
            if (
$direction)
            {
                
FishError::push_handler(FishError::get_constant($file), H_DEBUG);
            }
            else
            {
                
FishError::pop_handler(FishError::get_constant($file), H_DEBUG);
            }
        }
    }

    function 
unwatch($files=array())
    {
        
call_user_func(array('FishError','watch'), $filesFALSE);
    }

    function 
dumpvar($var, &$vlist,$tick=0)
    {
        if (!
is_array($vlist))
        {
            
$vlist = array();
        }
        if (empty(
$var))
        {
            
$output "(empty)\n";
        }
        elseif (!
is_array($var) && !is_object($var))
        {
            
$output "<xmp>$var</xmp>";
        }
        else
        {
            
$output "(var is ".gettype($var).")<ul>\n";
            foreach ((array)
$var as $k => $v)
            {
                if (
preg_match('/^(GLOBALS|HTTP_|_)/',$k))
                {
                    continue;
                }
    
//echo '<hr>k:',var_dump($k), 'v:', var_dump($v) ;
    //echo '<hr>vlist:', var_dump($vlist);
                
if (array_key_exists($k,$vlist) && $vlist[$k] === $v)
                {
                    
// nothing - we've already seen this
                    // you can uncomment this line if you're suspicious
                    
$output .= "<li>k=($k) already displayed\n";
                }
                else
                {
                    
$vlist[$k] = $v;
                    
$output .= "\n<li>k=($k)\nv=(".FishDebug::dumpvar($v,$vlist,$tick++).")\n";
                }
            }
            
$output .= "</ul>\n";
        }
        return 
$output;
    }

    function 
check_timing($loc='')
    {
        static 
$timestamps = array();
        static 
$last_time NULL;
        
$now time();
        if (
$last_time === NULL)
        {
            
$last_time $now;
        }
        
$output NULL;
        if (!empty(
$loc))
        {
            
$timestamps[][$loc] = $now $last_time;
        }
        else
        {
            
$output var_export($timestampsTRUE);
        }
        
$last_time $now;
        return 
$output;
    }

    function 
nlecho()
    {
        
$args func_get_args();
        echo 
'<li>';
        foreach (
$args as $arg)
        {
            if (
is_string($arg))
                echo 
$arg;
            else
                echo 
var_export($argTRUE);
        }
        echo 
"\n";
    }
}
?>