(function($){
    var e164_regex = /(\+\d)?(\d{10})/;
    var num_strip_regex = /[^\d]*/g;

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

            url = $.env('templates')+url;
            
            if (version == '@VERSION@') {
                return url+'?__='+(new Date().getTime());
            }
            
            return url+'?__='+Base64.encode(version);
        },
        store_template: function (url) {
            var version = $.env('version');

            url = $.env('store_templates')+url;
            
            if (version == '@VERSION@') {
                return url+'?__='+(new Date().getTime());
            }
            
            return url+'?__='+Base64.encode(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: {
            lower_bounded_number: function(num, lower_bound, default_num) {
                lower_bound = lower_bound || 4;
                default_num = default_num || 30;
                if (num !== '') {
                    num = typeof(num) === 'string' ? parseInt(num) : num;
                    if (num === null || num === undefined || num < lower_bound) {
                        return default_num;
                    } else {
                        return num;
                    }
                } else {
                    return default_num;
                }
            },
            is_number: function(num) {
                return num.length >= 10;
            },
            format_number: function(num) {
                var tmp = $.stripChars(num);
                if (!tmp) {
                    return num;
                } else {
                    num = num.replace('%2B','+');
                    // split extension aliases
                    var parts = num.split(':');
                    if (parts.length > 1) {
                        num = parts[1];
                    }
                    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
                    }
                }
            },
            serialize_extension_alias: function(alias) {
                var pbxid = $.config('login').pbxid;
                return pbxid + ':' + alias;
            },
            dom_friendly_number: function(num) {
                return $.helpers.normalize_to_e164(num).substring(1);
            },
            clean_obj: function(obj) {
                var obj = $.extend(true, {}, obj);
                $.each(obj, function(k,v) {
                    if (!v) {
                        delete obj[k];
                    }
                });
                return obj;
            },
            make_username: function(user_part) {
                return user_part + '@' + $.config('login').domain;
            },
            normalize_to_e164: function (num) {
                var stripped_num = num.replace(num_strip_regex, '');
                var result;
                if (stripped_num.length < 10) {
                    throw new Error("Not enough information to convert to e164 format!");
                }

                if (stripped_num.length === 11) {
                    result = "+" + stripped_num;
                } else if (stripped_num.length === 10) {
                    result = "+1" + stripped_num;
                } else {
                    throw new Error("Cannot format " + num + " to e164 format!");
                }
            
                return result;
            },
            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, formatstring) {
                var d = Date.parse(timestamp.slice(0,19),'yyyy-MM-dd HH:mm:ss');
                var timestamp_formatted = d ?d.toString(formatstring ? formatstring : 'MMMM d, h:mm tt') : timestamp;
                return timestamp_formatted;
            },
            format_duration: function(seconds) {
                //formats as hh:mm:ss
                if (typeof(seconds)=='number'){
                    var h=0,m=0;
                    //s = Math.round(milliseconds/1000);
                    m = Math.floor(seconds/60);
                    seconds = seconds % 60;
                    h = Math.floor(m/60);
                    m = m % 60;
                    if (h < 10) h = "0"+h;
                    if (m < 10) m = "0"+m;
                    if (seconds < 10) seconds = "0"+seconds;
                    return h+":"+m+":"+seconds;
                }
                else return "error";
            },

            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)
                          || /^(211.*)/.test(extension) 
                          || /^(311.*)/.test(extension)
                          || /^(411.*)/.test(extension)
                          || /^(511.*)/.test(extension)
                          || /^(611.*)/.test(extension)
                          || /^(711.*)/.test(extension)
                          || /^(811.*)/.test(extension));
            },
            between: function(num, min, max) {
                return ( min <= num && num <= max );
            },
            map_customer_type: function(customer_type) {
                return (customer_type === 'pbod') ? customer_type : 'pb2';
            },
            map_softphone_customer_type: function(customer_type) {
                return $.helpers.map_customer_type(customer_type);
            },
            vm_url: function(user, msg, download) {
                return '/pb/voicemail/user/' + $.config('login').domain + '/' + user.extension + '/' + msg + '?sessionid=' + $.config('login').sessionid + (download ? '&download=true' : '');
            },
            // generates a confirmation dialog
            confirm: function (context,text, ok_callback, cancel_callback) {
                // wrapp the ok_callback to add a spinner while the callback executes
                var blocked_ok_callback = function(){
                    var block_options = {
                        message: '<img src="/pb/assets/images/spinner-circle-smooth.gif" />',
                        css: {
                            border: '0',
                            backgroundColor: 'transparent',
                            zIndex: '30000'
                        },
                        overlayCSS: {
                            backgroundColor: '#fff',
                            zIndex: '29999'
                        }
                    };
                    context.qtip("api").elements.contentWrapper.block(block_options);
                    ok_callback();
                    
                };
                var div = $('<div />', {className:"dialog"}),
                    message = $('<p />', { text: text }),
                    ok = $('<button />', { 
                        text: 'Ok',
                        click: blocked_ok_callback
                    }),
                    cancel = $('<button />', {
                        text: 'Cancel',
                        className: 'dialog_button',
                        click: cancel_callback
                    });
                context.qtip({
                    content: {
                        prerender: true,
                        text: div.append(message).append(ok).append(cancel),
                        title: "Confirm"
                    },
                    position: {
                        target: $(document.body),
                        corner: 'center'
                    },
                    show: {
                        ready: true,
                        solo: true
                    },
                    hide: false,
                    style: { 
                        //name: 'base',
                        border: { width: 3 },
                        //width: { min: 716,max:716 },
                        //height: "645px"
                        // overflow: "scroll"
                    },
                    api: {
                        onHide: function(event) {
                            context.qtip("destroy");
                        },
                        beforeShow: function() {
                            $('#modal-filters').show();
                        },
                        beforeHide: function() {
                            $('#modal-filters').hide();
                        }
                    }
                });
            }
        },
        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');
        },
        trackEvent: function(category, action, label, value) {
            _gaq = _gaq || [];
            if (value) {
                _gaq.push(['_trackEvent', category, action, label, value]);
            } else {
                _gaq.push(['_trackEvent', category, action, label]);
            }
        }

    });
    
    $.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));
    };
    
    Number.prototype.round = function(p) {
    	// rounds the number to the nearest decimal place noted by p
    	// ex. (253.4712).round(2) == 300
    	// ex. (253.4712).round(-2) == 253.47
    	// ex. (253.4712).round(0) == 253
    	var n = Math.pow(10,p);
    	return Math.round(this / n) * n;
    }
    
    Number.prototype.asPercent = function() {
    	return (this * 100).round(0) + '%';
    }
    
    String.prototype.contains = function(it) {
        return this.indexOf(it) != -1;
    };


})(jQuery);

