/*

                com.jgraup.utils.jgDelegate2.as -- Flash Actionscript 2 Delegate class
                Copyright (C) 2006 Just Good Design | Jesse Graupmann

                www.justgooddesign.com | www.jessegraupmann.com

*/


//              Three approaches to component event handling
//              http://www.bdontwerp.nl/articles/component_eventhandling.html
//
//              Application of arguments.callee
//              http://www.helpqlodhelp.com/blog/archives/000149.html
//
//              Scope Chain and Memory waste in Flash MX
//              http://timotheegroleau.com/Flash/articles/scope_chain.htm
//
//              Class Delegate
//              http://www.flashdevelop.org/community/viewtopic.php?t=258&highlight=delegate
//
//              Delegate class refined
//              http://dynamicflash.com/2005/02/delegate-class-refined/
//
//              Proxying Events with the mx.utils.Delegate Class
//              http://www.adobe.com/devnet/flash/articles/eventproxy.html
//
//              EventProxy.as : Proxying Events
//              http://weblogs.macromedia.com/mesh/archives/2004/01/eventproxyas_pr.html
//
//
//              http://www.createage.com/blog/?p=77
//              http://labs.bigspaceship.com/blog/?p=9
//              http://www.boostworthy.com/blog/?p=10
//              http://www.person13.com/articles/proxy/Proxy.htm
//              http://www.actionscript.org/resources/articles/205/1/The-Delegate-Class/Page1.html
//              http://www.zefxis.gr/en/article-delegates/



class com.jgraup.utils.jgDelegate2
{

        /*

        *
        *
        *
        *
                        @parameter scope = Scope to run function
                        @paramater func = Function to run.
                        ----------------------------
                        @paramater self = reference to inline function - can be used with event proxies
                        ----------------------------
                        @paramater args = (optional) PROXY arguments without scope & func to strore in function
                        @paramater returnFunction = (optional) internal function to run on the results of func
                        ----------------------------
                        @paramater return = Scoped Function
        *
        *
        *
        *

        //
        //              ADD / REMOVE | EVENT PROXY
        //
        //              obj.addEventListener( ’onEvent’, jgDelegate2.create ( listener, onEvent ) );
        //              obj.removeEventListener( ’onEvent’, arguments.callee.self ); // onEvent

        *
        *
        *
        *

        //
        //              DELETE A DELEGATE
        //
        //              jgDelegate2.empty ( delegate ), delete delegate;

        *
        *
        *
        *
        *
        *
        //
        //              EXAMPLE FUNCTION
        //
        //              function o (){ trace( arguments.join(' ') )}; // output of function - traces the arguments passed



        */


        public function jgDelegate2 () {}





        public static function create( obj:Object,  func:Function ):Function
        {
                //              SCOPED FUNCTION
                //              ______________________________
                //
                //              dFunc = jgDelegate2.create ( this, o );
                //              dFunc ( 'Hello World' ); // Hello World

                var f = function ( )
                {
                        var scope = arguments.callee.scope; // scope
                        var func = arguments.callee.func; // function
                        func.self = arguments.callee; // refernce for listeners

                        return func.apply( scope, arguments); // method
                };

                f.scope = obj;
                f.func = func;

                return f;
        }






        public static function proxy ( obj:Object,  func:Function ):Function
        {
                //              SCOPED FUNCTION WITH STORED PRAMS
                //              ______________________________
                //
                //              dFunc = jgDelegate2.proxy ( this, o, 'Hello World' );
                //              dFunc ( "Won't take new args" ); // Hello World

                var f = function ( )
                {
                        var scope = arguments.callee.scope; // scope
                        var func = arguments.callee.func; // function
                        var args = arguments.callee.args; // stored arguments
                        func.self = arguments.callee; // refernce for listeners

                        return func.apply( scope, args); // method
                };

                f.scope = obj;
                f.func = func;
                f.args = arguments.slice ( 2, arguments.length ); // store arguments

                return f;
        }






        public static function proxyAFTER ( obj:Object,  func:Function ):Function
        {

                //              SCOPED FUNCTION TO RUN RUNTIME ARGUMENTS WITH PROXY ARGUMENTS APPENDED TO THE END
                //              ______________________________
                //
                //              dFunc = jgDelegate2.proxyAFTER ( this, o, 'World.' );
                //              dFunc ( 'Hello' ); // Hello World


                var f = function ( )
                {
                        var scope = arguments.callee.scope; // scope
                        var func = arguments.callee.func; // function
                        var args = arguments.callee.args; // stored arguments
                        func.self = arguments.callee; // refernce for listeners

                        return func.apply( scope, arguments.concat ( args )); // method
                };

                f.scope = obj;
                f.func = func;
                f.args = arguments.slice ( 2, arguments.length ); // store arguments

                return f;
        }

        public static function proxyBEFORE ( obj:Object,  func:Function ):Function
        {

                //              SCOPED FUNCTION TO RUN PROXY ARGUMENTS WITH RUNTIME ARGUMENTS APPENDED TO THE END
                //              ______________________________
                //
                //              dFunc = jgDelegate2.proxyBEFORE ( this, o, 'Hello' );
                //              dFunc ( 'World.' ); // Hello World.


                var f = function ( )
                {
                        var scope = arguments.callee.scope; // scope
                        var func = arguments.callee.func; // function
                        var args = arguments.callee.args; // stored arguments
                        func.self = arguments.callee; // refernce for listeners

                        return func.apply( scope, args.concat ( arguments )); // method
                };

                f.scope = obj;
                f.func = func;
                f.args = arguments.slice ( 2, arguments.length ); // store arguments

                return f;
        }






        public static function proxyRETURN ( obj:Object,  func:Function ):Function
        {
                //              SCOPED FUNCTION TO RETURN VALUE TO THE SECOND PROXY FUNCTION
                //              ______________________________
                //
                //              f1 = function ( v ) { return (v + 2) };
                //              f2 = function ( v ) { trace ( 'sum = ' + (v + 2) ) };
                //              dFunc = jgDelegate2.proxyRETURN ( this, f1, jgDelegate2.create ( this, f2 ) );
                //              dFunc ( 2 ); // sum = 6
                //
                //              //       access to the return function
                //              //      dFunc.returnFunction
                //              //       or
                //              /       dFunc.func.self.returnFunction

                var f = function ( )
                {
                        var scope = arguments.callee.scope; // scope
                        var func = arguments.callee.func; // function
                        func.self = arguments.callee; // refernce for listeners

                        return arguments.callee.returnFunction ( func.apply ( scope, arguments ) ); ;
                };

                f.scope = obj;
                f.func = func;
                f.returnFunction = f.arguments [ 2 ];

                return f;
        }






        public static function proxyOVERWRITTEN ( obj:Object,  func:Function ):Function
        {
                //              ARGUMENTS OVERRIDE PROXY ARGUMENTS
                //              ______________________________
                //
                //              dFunc = jgDelegate2.proxyOVERWRITTEN ( this, o, 'Hello', 'World' );
                //              dFunc ( ); // Hello World
                //              dFunc ( 'GoodBye' ); // GoodBye World
                //              dFunc ( 'GoodBye', 'Amigo' ); // GoodBye Amigo

                var f = function ( )
                {
                        var scope = arguments.callee.scope; // scope
                        var func = arguments.callee.func; // function
                        var args = arguments.callee.args; // stored arguments
                        func.self = arguments.callee; // refernce for listeners

                        return func.apply ( scope,  arguments.concat ( args.slice ( arguments.length, args.length ) ) ); // method
                };

                f.scope = obj;
                f.func = func;
                f.args = arguments.slice ( 2, arguments.length ); // store arguments

                return f;
        }






        public static function proxyOVERWRITE ( obj:Object,  func:Function ):Function
        {
                //              ARGUMENTS OVERWRITE RUNTIME ARGUMENTS
                //              ______________________________
                //
                //              dFunc = jgDelegate2.proxyOVERWRITE ( this, o, 'Hello' );
                //              dFunc ( ); // Hello
                //              dFunc ( 'GoodBye' ); // Hello
                //              dFunc ( 'GoodBye', 'World' ); // Hello World

                var f = function ( )
                {
                        var scope = arguments.callee.scope; // scope
                        var func = arguments.callee.func; // function
                        var args = arguments.callee.args; // stored arguments
                        func.self = arguments.callee; // refernce for listeners

                        return func.apply ( scope,  args.concat( arguments.slice( 0, arguments.length ).slice( args.length, arguments.length ) ) ); // method
                };

                f.scope = obj;
                f.func = func;
                f.args = arguments.slice ( 2, arguments.length ); // store arguments

                return f;
        }






        public static function empty ( delegate:Function, toTrace:Boolean )
        {
                //
                //      Delete the stored properties inside a delegate produced by jgDelegate2
                //

                // show ( delegate, 'before' ); // output before

                delete delegate.func.self.scope;  // scope reference
                delete delegate.func.self.args; // stored arguments
                delete delegate.func.self.returnFunction; // stored function
                delete delegate.func.self.func;  // function
                delete delegate.func.self; // reference to inline function
                delete delegate.func;    // delegate function | must delete outside this call

                // show ( delegate, 'after' ); // output after
        }






        public static function show ( delegate:Function )
        {
                trace( '*************');
                trace( arguments + newline );

                trace('delegate: ' + delegate);
                trace('delegate.scope: ' + delegate.scope);
                trace('delegate.func : ' + delegate.func );
                trace('delegate.args: ' + delegate.args);
                trace('delegate.returnFunction: ' + delegate.returnFunction);
                trace('delegate.func.self: ' + delegate.func.self);
                trace('delegate.func.self.func: ' + delegate.func.self.func);
                trace('delegate.func.self.scope: ' + delegate.func.self.scope);
                trace('delegate.func.self.returnFunction: ' + delegate.func.self.returnFunction);

                trace( '*************');
        }






        public static function inline ( delegate:Function ):Function
        {
                return delegate.func.self;  // get inline function
        }







}