/**
* Wraps an object's method call to preserve scope when the call is made.
* Based on Mochikit's "method()" call.
*
* @usage var f = Delegate(this, this.methodname);
* @usage var f = Delegate(this, methodName);
* @param object self    An object reference.
* @param function or string : func A function reference to a function on 'self' or
* the name of a member method of self as a string.
*/
Delegate=function(self, func)
{
    if(typeof(func) == "string"){
        func = self[func];
    }
    //this vars will init to undefined if func has not already been delegated.
    //but we can delegate delegates so this is necessary.
    var im_func = func.im_func;
    var im_preargs = func.im_preargs;
    var im_self = func.im_self;
    if(typeof(func) == "function" && typeof(func.apply) == "undefined"){
        /* hmmm... This condition should almost never happen. */
        /* if it does, maybe you shouldn't be delegating builtin functions. */
    }
    if(typeof(im_func) != 'function'){
        im_func = func;
    }
    if(typeof(self) != 'undefined'){
        im_self = self;
    }
    if(typeof(im_preargs) == 'undefined'){
        im_preargs = [];
    } else {
        im_preargs = im_preargs.slice();
    }
    var newFunc = function(){
        var args = [];
        for(var i=0; i<arguments.length; i++){
            args.push(arguments[i]);
        }
        var me = arguments.callee;
        if (me.im_preargs.length > 0) {
            args = me.im_preargs.concat(args);
        }
        var self = me.im_self;
        if (!self) {
            self = this;
        }

        return me.im_func.apply(self, args);
    }
    newFunc.im_self = im_self;
    newFunc.im_func = im_func;
    newFunc.im_preargs = im_preargs;
    return newFunc;
}

/**
*   Mixin for Classes that want to dispatch their own custom events.
*   Adds functionality into a class so the class can manage its own listeners
*   and dispatch its own events. 
*   Does not support DOM events.
*
*   @usage:
*       var myClass = Class.create();
*       myClass.prototype = {
*           initialize:function()
*           {
*               EventDispatcher.register(this);
*           },
*           signalEvent:function()
*           {
*               this.dispatchEvent("eventName", "some parameter", "some other parameter");
*           }
*       }
*   @name NewsOK.com
*   @author Eric Johnson
*   @license http://opensource.org/licenses/gpl-license.php GNU Public License
*   @copyright (c)2003-2007 by NewsOK - {@link http://newsok.com/}
*   @package common
*   @version 1.0
*/
EventDispatcher = {

    /**
    *   Adds the event dispatcher interface to the object passed. 
    *   @param object obj The class instance to mix into.
    */
    register:function(obj)
    {
        obj._listeners = []; //a map of listeners
        obj.dispatchEvent = this._dispatchEvent;
        obj.addEventListener = this._addEventDispatcher;
        obj.removeEventListener = this._removeEventListener;
    },

    /**
    *   Removes the event dispatcher interface to the object passed. 
    *   @param object obj The class instance to unregister.
    */
    unregister:function(obj)
    {
        obj._listeners = null;
        obj.dispatchEvent = null;
        obj.addEventListener = null;
        obj.removeEventListener = null;
    },

    /**
    *   Alerts subscribers to the event
    *   
    *   @param string eventName The name of the event to dispatch
    *   @param mixed  params    The parameters to pass to the callback. 
        params [, params1, params2, ...  paramsN]
    */
    _dispatchEvent:function(evtName)
    {
        var ls = this._listeners[evtName];
        var args = [];

        //get any args to pass to the callback
        for(var i =1; i<arguments.length; i++){
            args.push(arguments[i]);
        }
        //dispatch the calls to the listeners
        for(var i = 0; i < ls.length; i++){
            ls[i].funct.apply(ls[i].obj, args);
        }
    },

    /**
    *   Subscribes the specified object to the specified event using the 
    *   specified callback function. The callback will execute in the scope of obj.
    *
    *   @param object obj The object subscribing to the event.
    *   @param string eventName The event being subscribed to.
    *   @param mixed functOrStr Either a function reference, or the name of a member method on obj.
    */
    _addEventListener:function(obj, eventName, functOrStr)
    {
        var funct;
        if(typeof(eventName) != 'string'){
            return;
        }
        
        /* sanity check. If obj isn't an object default to the window object. */
        if(typeof(obj) != 'object') {
            obj = window;
        }
        
        /* Default to a method with the same name as the event if a funct was not provided. */
        if(!functOrStr)
            functOrStr = eventName;
        
        //resolve the function reference
        if(typeof(functOrStr) == 'function'){
            funct = functOrStr;
        } else if(typeof(functOrStr) == 'string'){
            if(typeof(obj[functOrStr]) == 'function'){
                funct=obj[functOrStr];
            }
        }
        if(!funct){
            return;
        }

        /* remove any previous incarnations of this listener. */
        this._removeEventListener(obj, eventName);

        /* add the listener */
        this._listeners[eventName].push({'obj':obj, 'funct':funct});
    },

    /**
    *   Unsubscribes the specified object from the specified event name.<b> 
    *
    *	@param object obj  The object to remove
    *	@param string eventName The event being unsubscribed
    */
    _removeEventListener:function(obj, eventName)
    {
        var ls = this._listeners[eventName];
        for(var i = 0; i< ls.length; i++){
            if(ls[i].obj == obj){
                ls.splice(i,1);
            }
        }
    }
}

/**
*   Provides a common mechanism for observing and broadcasting events.
*   Unlike the EventDispatcher class, DOM events can be observed.
*
*   @usage:
        var link = Builder.node(a.{'href':'javascript:void(0);'},['click me']);
        Broadcaster.subscribe(link, 'click', function(evtObj){
            alert('clicked');
        });
        
        var foo = Class.create();
        foo.prototype = {
            initialize:function()
            {
                this.link = Builder.node(a.{'href':'javascript:void(0);'},['click me']);
                Broadcaster.subscribe(this.link, 'click', this, 'handleClick');
                
                Broadcaster.subscribe(this, 'myEvent', this, 'alertMyEvent');
            },
            
            handleClick:function(evtObj)
            {
                alert('clicked');
            },
            
            signalEvent:function()
            {
                Broadcaster.broadcast(this, 'myEvent', 'fired from foo.signalEvent');
            },
            
            alertMyEvent:function(param)
            {
                alert(param);
            }
        }

*   @name NewsOK.com
*   @author Eric Johnson
*   @license http://opensource.org/licenses/gpl-license.php GNU Public License
*   @copyright (c)2003-2007 by NewsOK - {@link http://newsok.com/}
*   @package common
*   @version 1.0
*/
Broadcaster = {
    /**
    *   The master list of observers.
    */
    _subscribers:[],
    
    _wrappers:[],

    /**
    *   Destroyes a subscriber listing
    */
    _destroy:function(subs, i)
    {
        //since wrappers are reused only remove it if its the only subscriber
        //subscribing to this object
        var rmWrapper = true;
        var self = Broadcaster;
        var arr = self._subscribers[subs[i].event];
        for(var j = 0; j < arr.length; j++){
            if(arr[j].caster == subs[i].caster && arr[j].subs != subs[i].subs){
                rmWrapper = false; //not the last.
            }
        }
        if (rmWrapper) {
            if (subs[i].wrapper != null) {
                
                var arr = self._wrappers[subs[i].event];
                for(var j = 0; j<arr.length; j++) {
                    if(arr[j].evtObj == subs[i].caster && arr[j].wrapper == subs[i].wrapper){
                        arr[j].wrapper = null;
                        arr[j].evtObj = null;
                        arr.splice(j,1);
                        break;
                    }
                }

                var obj = subs[i].wrapper.evtObj;
                if (obj.detachEvent) {
                    obj.detachEvent(subs[i].event, subs[i].wrapper);
                } else if (obj.removeEventListener) {
                    obj.removeEventListener(subs[i].event, subs[i].wrapper, true);
                }
            }
        }
        subs[i].wrapper = null;
        subs[i].caster = null;
        subs[i].event = null;
        subs[i].subs = null;
        subs[i].funct = null;
        subs[i] = null;
        subs.splice(i,1);
    },

    /**
    *   Should be called when the window unloads to prevent memory leaks in some browsers
    */
    _destroyAll:function()
    {
        var self = Broadcaster;
        var arr = self._subscribers;
        for(var key in arr){
            var sub = arr[key];
            for(var i=sub.length-1; i > -1; i++){
                self._destroy(sub[i],i);
            }
        }
    },
    
    /**
    *   Broadcasts the specified event and parameters to all subscribers of 
    *   the event on obj.
    *
    *   @param object obj       A reference to the broadcaster.
    *   @param string eventName The event name to broadcast.
    *   @param array params     Parameters to pass to the subscribers.
    */
    broadcast:function(obj, eventName, params)
    {
        if(!obj || !eventName) return;
        params = params || [];
        if(!(params instanceof Array)){
            params = [params];
        }
        var self = Broadcaster;
        var arr = self._subscribers[eventName] || [];

        /* clone the array cos someone might unsubscribe from the list in the middle of it all */
       arr = arr.concat();
        for(var i = 0; i<arr.length; i++){

            if(arr[i].caster == obj){
                arr[i].funct.apply(arr[i].sub, params);
            }
        }
    },

    /**
    *   Registers a broadcaster to a subscriber.  Supports subscribing to DOM events.
    *
    *   @param object obj   The object being subscribed to.
    *   @param string event The event being subscribed to.
    *   @param mixed objOrFunt  The object or function that will handle the broadcast.
    *   @param mixed functOrStr If objOrFunct is an object, a function reference or string of a method member
    *   of objOrFunt that will handle the broadcast.
    *   @return The id object of the subscription.  Use the id to unsubscribe.
    */
    subscribe:function(obj, event, objOrFunct, functOrStr)
    {
        //validate
        if(!obj || !event || !objOrFunct){
            if (typeof(console) != 'undefined') {
                console.log('subscribe was not passed the correct params :');
                console.log("obj : " + obj);
                console.log("event : " + event);
                console.log("objOrFunct : " + objOrFunct);
            }
            return;
        }

        var sub;
        var funct;
        var wrapper;
        var self = Broadcaster;
        
        //resolve the obj and funct
        if(typeof(objOrFunct) == 'function'){
            sub = window;
            funct = objOrFunct;
        } else if(typeof(objOrFunct) == 'object'){
            sub = objOrFunct;

            //resolve the function reference
            if(typeof(functOrStr) == 'function'){
                funct = functOrStr;
            } else if(typeof(functOrStr) == 'string'){
                if(typeof(sub[functOrStr]) == 'function'){
                    funct=sub[functOrStr];
                }
            } else {
               alert('Broadcaster.subscribe: functOrStr was invalid');
               return;
            }
        } else {
            alert('Broadcaster.subscribe: objOrFunct was invalid');
            return;
        }

        //resolve obj
        if(typeof(obj.nodeType) != 'undefined' || obj == window){
            //this is a DOM element that is being subscribed to.
            //we need to handle the different browser implementations
            if(obj.attachEvent){
                if(event.toLowerCase().indexOf('on') != 0){
                    event= "on"+event;
                }
            } else {
                if(event.toLowerCase().indexOf('on') == 0){
                    event= event.substr(2);
                }
            }
            
            
            //*TODO* I have a feeling this may leak... need to check
            /* wrapper creates a function call that we can attach to DOM events
                that will call the Broadcaster.broadcast method. 
                We only want ONE wrapper per dom object, so track these suckers
                and reuse them.
            */
            if(!self._wrappers[event]) self._wrappers[event]=[];
            var found = false;
            for(var i=0; i<self._wrappers[event].length; i++){
                if(self._wrappers[event][i].evtObj == obj){
                    found = self._wrappers[event][i].wrapper;
                    break;
                }
            }
            if (found != false) {
                wrapper = found;
            }
            else {

                wrapper = function(evt){
                    evt = evt || window.event;
                    var foo = {};
                    for (var key in evt) {
                        foo[key] = evt[key];
                    }
                    foo['target'] = evt.target || evt.srcElement;
                    
                    var me = arguments.callee;
                    Broadcaster.broadcast(me.evtObj, me.event, [foo]);
                }
                wrapper.event = event;
                wrapper.evtObj = obj;
                
                self._wrappers[event].push({'wrapper':wrapper, 'evtObj':obj});
                //this is a DOM element that is being subscribed to.
                //we need to handle the different browser implementations
                if(obj.attachEvent){
                    obj.attachEvent(event, wrapper);
                }else if(obj.addEventListener){
                    obj.addEventListener(event, wrapper, true);
                }
            }
        }

        var hash = {'caster':obj, 'event':event, 'sub':sub, 'funct':funct, 'wrapper':wrapper};

        /*
         * Don't add a duplicate hash record. weird things happen
         */
        for(var key in self._subscribers[event]){
            obj = self._subscribers[event][key];
            if(obj.caster == hash.caster && obj.sub == hash.sub && obj.funct.toString() == hash.funct.toString()){
                return obj;
            }
        }
        if(!self._subscribers[event]) self._subscribers[event]=[];
        self._subscribers[event].push(hash);
        return  hash;
    },

    /**
    *   Removes a subscriber from a particular broadcast
    *   @param object id The subscription id to be removed.
    */
    unsubscribe:function(id)
    {
        if(!id.caster || !id.event) return;
        
        var self = Broadcaster;
        var ls = self._subscribers[id.event];
        
        for(var i =0; i< ls.length; i++){
            if( ls[i].caster == id.caster &&
                ls[i].event == id.event &&
                ls[i].sub == id.sub &&
                ls[i].funct == id.funct){
                self._destroy(ls, i);          
                break;
            }
        }
    },

    /**
    *   Removes a subscriber from all broadcasts
    *   @param object obj The object to unsubscribe from all broadcasts
    */
    unsubscribeAll:function(obj)
    {
        if(!obj) return;

        var self = Broadcaster;
        var arr = self._subscribers;
        for(var key in arr){
            var subs = arr[key];
            if (typeof(subs) == 'object') {
                for (var i = subs.length - 1; i > -1; i--) {
                    if (subs[i] && subs[i].sub == obj) {
                        self._destroy(subs, i);
                    }
                }
            }
        }
    }
}


/**
*   Encapsulates functinality for displaying an error message
*/
function ErrorMessage(el, str){
    this.initialize(el, str);
}
ErrorMessage.prototype = {
    /**
    *   @param string or object el Optional reference to an existing element in the document dom. 
    *   @param string str Optional default message to use if one will not be passed via the show method. 
    */
    initialize:function(el, str)
    {
        str = str || '';
        this.buildDOM(el, str);
    },
    /**
    *   creates the dom element for the class instance, or assigns the specified 
    *   element reference. If a element reference is not passed then the ErrorMessage
    *   instance's element must be manually inserted into the dom.
    *   @param string/object el Optional. If passed it should be either the 
    *   id of a DOM element or an object reference to that element. 
    *   @param string str Optional.  A starting string for the error message.  
    */
    buildDOM:function(el, str)
    {
        if(el){
            //try to resolve el to an element reference, or null if none is found.
            if(typeof(el) == 'string'){
                el = $(el) || null;
            } else if(el.nodeType && el.nodeType == 1){
                //pass. this is an element reference
            } else {
                el = null;
            }
        } 
        if(!el){
            this.el = Builder.node('span', [str]);
        } else {
            this.el = el;
        }
        Element.extend(this.el);
        this.el.addClassName('errmsg');
        this.reset();
    },
    /**
    *   makes the error message visible. 
    *   @param string str Optional message to display.  str should be passed if a default
    *   message was not set when instantiated. 
    */
    show:function(str)
    {
        if(str){
            this.el.update(str);
        }
        Effect.Appear(this.el,{queue: 'end', duration:0.5});
    },
    /**
    *   makes the message invisible.
    */
    hide:function()
    {
        Effect.Fade(this.el,{queue: 'front', duration:0.5, afterFinish:function(){alert('done')}});
    },
    
    /**
    *   immediately hides the error message
    */
    reset:function()
    {
        this.el.setStyle({'display':'none'});
    }
}
function imageToggle(id, image1, image2) {
    if ($(id).src == image1) {
        $(id).src = image2;
    } else {
        $(id).src = image1;
    }
}
/*Clear Variables for Omniture so we make sure nothing is counted twice added 3-21-2008 by James Duncan*/
//this is killing IE and Safari for Win because s isn't defined. commenting out for now --clint
function clearStats() {
    s.pageName=""
    s.server=""
    s.channel=""
    s.pageType=""
    s.prop1=""
    s.prop2=""
    s.prop3=""
    s.prop4=""
    s.prop5=""
    s.campaign=""
    s.state=""
    s.zip=""
    s.events=""
    s.products=""
    s.purchaseID=""
    s.eVar1=""
    s.eVar2=""
    s.eVar3=""
    s.eVar4=""
    s.eVar5=""
    s.hier1=""
}
function trackClick(newPageName) {
    clearStats();
    s.pageName=newPageName;
    void(s.t());
}

function select_all_radio(val) {
    var pg_events = $$(".page_pending_events .radio");
    for(i=0; i<pg_events.length; i++) {
       if(pg_events[i].value == val){
            pg_events[i].checked = "checked";
        }
    }
}

