<cfcomponent
	output="false"
	hint="I demonstrate how to proxy a component.">


	<!---
		To make this demo as easy as possible, we are going to
		create our target component directly from within our proxy
		component. Typically, you'd pass the taret component in
		during initialization.
	--->
	<cfset variables.target = new Test() />

	<!---
		When proxying a given component, we need a way to identify
		the target component such that if a method invocation returns
		the target component, we can return the proxy component in
		its stead.
	--->
	<cfset this.proxyUUID = createUUID() />

	<!--- Copy the UUID flag into the target component. --->
	<cfset variables.target.proxyUUID = this.proxyUUID />

	<!---
		Create our three proxy methods. Notice that both of our proxy
		methods just point to the one defined local method. That
		method will pass on the invocation message based on the name
		of the invoked method.
	--->
	<cfset this.getValue = variables.proxyMethod />
	<cfset this.getVoid = variables.proxyMethod />
	<cfset this.getComponent = variables.proxyMethod />


	<!--- ------------------------------------------------- --->
	<!--- ------------------------------------------------- --->


	<cffunction
		name="proxyMethod"
		access="private"
		returntype="any"
		output="false"
		hint="I proxy the invoked method on the target component.">

		<!---
			Pass the invocation message onto the target component
			and get the result.
		--->
		<cfinvoke
			returnvariable="local.proxyResult"
			component="#variables.target#"
			method="#getFunctionCalledName()#"
			argumentcollection="#arguments#"
			/>

		<!---
			Now that we have the result, we have a few special cases
			to test for; we might have a void return, which will
			leave our result undefined. We might also have the target
			object returned (such as is done with method chaining).
		--->
		<cfif isNull( local.proxyResult )>

			<!---
				The proxy invocation returned void. Therefore, we
				can't return the result without error. As such,
				return void explicitly.
			--->
			<cfreturn />

		</cfif>

		<!---
			Check to see if the result is the actual target component
			(as methods will often do to allow for chaining).
		--->
		<cfif (
			!isNull( local.proxyResult.proxyUUID ) &&
			(this.proxyUUID eq local.proxyResult.proxyUUID)
			)>

			<!---
				We don't want to allow access to the proxied
				target! Return the proxy instead to allow for
				method chaining.
			--->
			<cfreturn this />

		</cfif>

		<!---
			If we made it this far then we have no special use-cases
			for return values; simply echo the value that was returned
			by the target.
		--->
		<cfreturn local.proxyResult />
	</cffunction>

</cfcomponent>