<?php
/** @package    verysimple::IO */

/** import supporting libraries */
require_once("IncludeException.php");

/**
 * Provides helper functions for including classes and files dynamically
 * so that Exceptions are thrown instead of PHP errors and warnings
 *
 * @package    verysimple::IO
 * @author Jason Hinkle
 * @copyright  1997-2008 VerySimple, Inc.
 * @license    http://www.gnu.org/licenses/lgpl.html  LGPL
 * @version 1.0
 */
class Includer
{

	/**
	 * Includes a file with the given path.  If PHP is unable to include the file,
	 * an IncludeException is thrown instead of a PHP warning
	 * @param string path to file passed to the include_once statement
	 */
	public static function IncludeFile($path)
	{
		// re-route error handling temporarily so we can catch errors
		// use include instead of require so we can catch runtime exceptions
		// reset error handling back to whatever it was
		//*
		set_error_handler(array("Includer", "IncludeException"), E_WARNING);
		include_once($path);
		restore_error_handler();
		//*/
		
		// this doesn't work but it seems like it should
		// if (@include_once($path) === false) throw new IncludeException("Unable to include file: " . $path);

	}

	/**
	 * Ensures that a class is defined.  If not, attempts to include the file
	 * using the provided path. If unable to locate the class, an IncludeException
	 * will be thrown.  The path that will be used for include_once is
	 * $classpath . "/" . $classname . ".php"
	 * 
	 * @param string name of class (ex Phreeze)
	 * @param string or array [optional] the relative path(s) where the file would be found
	 */
	public static function RequireClass($classname, $classpath = "")
	{
		if (class_exists($classname)) return true;
		
		// normalize this as an array
		$classpaths = is_array($classpath) ? $classpath : array($classpath);
		$attempts = "";
		
		foreach ($classpaths as $path)
		{
			if (class_exists($classname)) break;

			try
			{
				// append a directory separater if necessary
				if ($path && substr($path,-1) != "/") $path .= "/";
				Includer::IncludeFile($path . $classname . ".php");
			}
			catch (IncludeException $ex) {$attempts .= " " . $ex->getMessage();}

		}
		
		if (!class_exists($classname))
		{
			// the class still isn't defined so there was a problem including the model
			throw new IncludeException("Unable to locate class '$classname': " . $attempts);
		}
	}	
	
	/**
	* Handler for catching file-not-found errors and throwing an IncludeException
	*/
	public static function IncludeException($code, $string, $file, $line, $context)
	{
		// check for repressed errors
		if (error_reporting() == 0) return;
		
		$tmp1 = explode(")",$string);
		$tmp2 = explode("(",$tmp1[0]);
		$mfile = isset($tmp2[1]) ? $tmp2[1] : "";
		
		$msg = "Error $code: " .  ($mfile ? "Unable to include file: '" . $mfile . "'" : $string);
		
		throw new IncludeException($msg,$code);
	}
	
}

?>