<?php

define("XCUBE_CALLBACK_TYPE_NONE",0);
define("XCUBE_CALLBACK_TYPE_STATIC_METHOD",1);
define("XCUBE_CALLBACK_TYPE_INSTANCE_METHOD",2);
define("XCUBE_CALLBACK_TYPE_STATIC_FUNCTION",3);

/** 
 * *An experiment class*
 * This class abstracts "function pointer".
 * These classes identifies the static method and the instance method and the global function.
 */
class XCube_Delegate
{
	var $mType=XCUBE_CALLBACK_TYPE_NONE;
	
	var $mClassName=null;
	var $mInstance=null;
	var $mMethodName=null;
	
	function XCube_Delegate($major,$minor=null)
	{
		$this->_register($major,$minor);
	}
	
	function _register($major,$minor=null)
	{
		if(is_string($major) && $minor===null) {
			$this->mType=XCUBE_CALLBACK_TYPE_STATIC_FUNCTION;
			$this->mMethodName=$major;
		}
		elseif(is_string($major) && is_string($minor)) {
			$this->mType=XCUBE_CALLBACK_TYPE_STATIC_METHOD;
			$this->mClassName=$major;
			$this->mMethodName=$minor;
		}
	}
}

/**
 * *An experiment class*
 * This class abstracts the instance method.
 */
class XCube_InstanceDelegate extends XCube_Delegate
{
	function XCube_InstanceDelegate(&$major,$minor)
	{
		$this->_register($major,$minor);
	}

	function _register(&$major,$minor)
	{
		if(is_object($major)&&is_string($minor)) {
			$this->mType=XCUBE_CALLBACK_TYPE_INSTANCE_METHOD;
			$this->mInstance=&$major;
			$this->mMethodName=$minor;
		}
	}
}

/**
 * This class is a collector of Delegate object.
 * The registrant can use Array instead of Delegate instance for speed.
 */
class XCube_Event
{
	var $mName;
	var $_mDelegates=array();
	
	var $_mAnchorDelegate=array();
	
	function XCube_Event($name)
	{
		$this->mName=$name;
	}

	/**
	 * @param $Delegate Delegate object or Array.
	 */
	function add(&$delegate)
	{
		$this->_mDelegates[]=&$delegate;
	}
	
	function setAnchorDelegate(&$delegate)
	{
		$this->_mAnchorDelegate=&$delegate;
	}
	
	function &getDelegates()
	{
		$this->_mDelegates;
	}

	function raiseEvent(&$sender,&$eventArgs)
	{
		if(count($this->_mDelegates)) {
			for($i=0;$i<count($this->_mDelegates);$i++) {
				$this->_callback($this->_mDelegates[$i],$sender,$eventArgs);
			}
		}

		if($this->_mAnchorDelegate!=null)
			$this->_callback($this->_mAnchorDelegate,$sender,$eventArgs);
	}
	
	function _callback(&$delegate,&$sender,&$eventArgs)
	{
		if(is_object($delegate)) {
			$this->_callbackDelegate($delegate,$sender,$eventArgs);
		}
		elseif(is_array($delegate)) {
			$this->_callbackArray($delegate,$sender,$eventArgs);
		}
	}
	
	function _callbackDelegate(&$delegate,&$sender,&$eventArgs)
	{
		switch($delegate->mType) {
			case XCUBE_CALLBACK_TYPE_STATIC_METHOD:
//				if(method_exists($delegate->mClassName,$delegate->mMethodName)) {
					// [PHP BUG] call_user_func can not reference parameter!!
					// http://bugs.php.net/bug.php?id=17309
					// http://bugs.php.net/bug.php?id=17246
					// call_user_func(array($delegate->mClassName,$Delegate->mMethodName),$sender,$eventArgs);
					$operation = $delegate->mClassName."::".$delegate->mMethodName.'($sender,$eventArgs);';
					eval($operation);
//				}
				break;

			case XCUBE_CALLBACK_TYPE_INSTANCE_METHOD:
				if(method_exists($delegate->mInstance,$delegate->mMethodName)) {
					// [PHP BUG]
					// call_user_func(array($delegate->mInstance,$Delegate->mMethodName),$sender,$eventArgs);
					$methodName=$delegate->mMethodName;
					$delegate->mInstance->$methodName($sender,$eventArgs);
				}
				else {
					//
					// TODO raise NOTICE
					//
				}
				break;
			
			case XCUBE_CALLBACK_TYPE_STATIC_FUNCTION:
				if(function_exists($delegate->mMethodName)) {
					// [PHP BUG]
					// call_user_func($delegate->mMethodName,$sender,$eventArgs);
					$operation = $delegate->mMethodName.'($sender,$eventArgs);';
					eval($operation);
				}
				else {
					//
					// TODO raise NOTICE
					//
				}
				break;
		}
	}

	function _callbackArray(&$arr,&$sender,&$eventArgs)
	{
		if(isset($arr['class'])&&is_object($arr['class'])) {
			// [PHP BUG]
			// call_user_func(array($arr['class'],$arr['function']),$sender,$eventArgs);
			$methodName=$arr['function'];
			$arr['class']->$methodName($sender,$eventArgs);
		}
		elseif(isset($arr['class'])&&isset($arr['function'])) {
			// [PHP BUG]
			// call_user_func(array($arr['class'],$arr['function']),$sender,$eventArgs);
			$operation = $arr['class']."::".$arr['function'].'($sender,$eventArgs);';
			eval($operation);
		}
		elseif(isset($arr['function'])) {
			// [PHP BUG]
			// call_user_func($arr['function'],$sender,$eventArgs);
			$operation = $arr['function'].'($sender,$eventArgs);';
			eval($operation);
		}
	}
}

?>