(function($){

    $.extend({
        template: function(url) {
            var version = $.env('version');

            url = $.env('templates')+url;
            
            if (version == '@VERSION@') {
                return url+'?__='+(new Date().getTime());
            }
            
            return url+'?__='+encode64(version);
        },
        keys: function(obj) {
            var a = [];
            $.each(obj, function(k) {
                a.push(k);
            });
            return a;
        },
        add_filter: function(filter) {
            var filters = $.config('aop');
            filters.push( filter );
            $.boot();   //Causes claypool to pick up the new filter config
        },
        remove_filter: function(filter) {
            var filters = $.config('aop');
            var id = filter.id || filter;
            //unbind behavior
            Claypool.Application['claypool:AOP'].factory.aspectCache.find(id).unweave();
            //remove from aspectCache
            Claypool.Application['claypool:AOP'].factory.aspectCache.remove(id);
            //remove from the other cache
             Claypool.Application['claypool:AOP'].factory.remove(id);
            //Remove from config   
            $.each(filters, function(idx, test_filter) {
                if( test_filter.id == id ) {
                    filters.splice(idx,1);
                }
            });
            $.boot();
        },
        helpers: {
            format_number: function(num) {
                var tmp = $.stripChars(num);
                if (!tmp) {
                    return num;
                } else {
                    num = num.replace('%2B','+');
                    if (num.length > 13) {
                        return num;
                    } else if (num.length >= 10 && num.length < 13) {
                        num = num.length==10 ? '+1'+num : num;
                        num = num.length==11 ? '+'+num : num;
                        return '(' + num.slice(2, 5) + ') ' + num.slice(5,8) + '-' + num.slice(8, 12);
                    } else if (num.length == 7) {
                        return num.slice(0,3)+'-'+num.slice(3,7);
                    } else if (/^x/.test(num)) {
                        return num;
                    } else {
                        return 'x'+num
                    }
                }
            },
            dom_friendly_number: function(num) {
                return num.slice(2, 9);
            },
            format_mac_addr: function(mac_addr) {
                if (mac_addr) {
                    return mac_addr.slice(0,2) + ':'
                         + mac_addr.slice(2,4) + ':'
                         + mac_addr.slice(4,6) + ':'
                         + mac_addr.slice(6,8) + ':'
                         + mac_addr.slice(8,10) + ':'
                         + mac_addr.slice(10,12);
                } else {
                    return mac_addr;
                }
            },
            strip_mac_addr: function(mac_addr) {
                return mac_addr ? mac_addr.replace(/[^0-9a-fA-F]/g, '') : mac_addr;
            },
            generate_random_string: function(length) {
                length = length || 8;
                var chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
                var pass = '';
                for(var x=0;x<length;x++) {
                    var i = Math.floor(Math.random() * 62);
                    pass += chars.charAt(i);
                }
                return pass;
            },
            format_timestamp: function(timestamp) {
                var d = Date.parse(timestamp.slice(0,19),'yyyy-MM-dd HH:mm:ss');
                var timestamp_formatted = d ?d.toString('MMMM d, h:mm tt') : timestamp;
                return timestamp_formatted;
            },

            is_valid_extension: function(extension) {
                var b = $.helpers.between;
                var e = parseInt(extension); 
               
                if( /^0\d\d\d+/.test(extension)) {
                    return true;    //extensions beginning with 0 don't parse / range compare correctly, but are valid.
                }
                return !( b(e,899,999) || /^(911.*)/.test(extension) );
            },
            between: function(num, min, max) {
                return ( min <= num && num <= max );
            }
        },
        stripChars: function(str) {
            return str ? str.replace(/[^0-9]/g, '') : str;
        },
        typeOf: function(value) {
            var s = typeof value;
            if (s === 'object') {
                if (value) {
                    if (value instanceof Array) {
                        s = 'array';
                    }
                } else {
                    s = 'null';
                }
            }
            return s;
        },
        isEmpty: function(o) {
            var i, v;
            var t = $.typeOf(o);
            if (t === 'object') {
                for (i in o) {
                    v = o[i];
                    if (v !== undefined && $.typeOf(v) !== 'function') {
                        return false;
                    }
                }
            } else if (t === 'array' && o.length !== 0) {
                return false;
            }
            return true;
        },
        delegate: function(rules) {
            return function(e) {
                var target = $(e.target);
                for (var selector in rules) {
                    if (target.is(selector)) {
                        return rules[selector].apply(this, $.makeArray(arguments));
                    }
                }
            };
        },
        nl2br: function(str) {
            return (str + '').replace(/([^>]?)\n/g, '$1'+ '<br />' +'\n');
        }

    });
    
    $.fn.extend( {
        runcode : function(options) {
            var settings = $.extend( {}, $.fn.runcode.defaults, options);
            
            return this.each(function() {
                if ($.fn.jquery < '1.2.6') {
                    return;
                }
                var $t = $(this);
                var o = $.metadata ? $.extend( {}, settings, $t.metadata())
                        : settings;
                
                eval($t.text());
            });
        }
    });
    
    $.fn.runcode.defaults = {};
    
    $.fn.ellipsis = function(enableUpdating){
        var s = document.documentElement.style;
        if (!('textOverflow' in s || 'OTextOverflow' in s)) {
            return this.each(function(){
                var el = $(this);
                if(el.css("overflow") == "hidden"){
                    var originalText = el.html();
                    var w = el.width();
                    
                    var t = $(this.cloneNode(true)).hide().css({
                        'position': 'absolute',
                        'width': 'auto',
                        'overflow': 'visible',
                        'max-width': 'inherit'
                    });
                    el.after(t);
                    
                    var text = originalText;
                    while(text.length > 0 && t.width() > el.width()){
                        text = text.substr(0, text.length - 1);
                        t.html(text + "...");
                    }
                    el.html(t.html());
                    
                    t.remove();
                    
                    if(enableUpdating == true){
                        var oldW = el.width();
                        setInterval(function(){
                            if(el.width() != oldW){
                                oldW = el.width();
                                el.html(originalText);
                                el.ellipsis();
                            }
                        }, 200);
                    }
                }
            });
        } else return this;
    };

    Number.prototype.formatMoney = function(c, d, t) {
        var n = this,
            c = isNaN(c = Math.abs(c)) ? 2 : c,
            d = d == undefined ? "." : d,
            t = t == undefined ? "," : t,
            s = n < 0 ? "-" : "",
            i = parseInt(n = Math.abs(+n || 0).toFixed(c)) + "",
            j = (j = i.length) > 3 ? j % 3 : 0;
            
        return s + (j ? i.substr(0, j) + t : "") + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + t) + (c ? d + Math.abs(n - i).toFixed(c).slice(2) : "");
    };
    
    Number.prototype.penniesToDollars = function() {
        var n = this+'';
        return parseFloat(n.substring(0,n.length-2) + '.' + n.substring(n.length-2));
    }


})(jQuery);
