(function($)
{
    _R.STRING =
    {
        init: function()
        {
            String.prototype._rFormat = this.format;

            String.prototype._rTrim = function()
            {
                return this.replace(/^\s+|\s+$/g, '');
            };

            String.prototype._rDashToCamel = function()
            {
                return this.replace(/(\-[a-z])/g, function(str){return str.toUpperCase().replace('-','');});
            };

            String.prototype._rUnderscoreToCamel = function(){
                return this.replace(/(_[a-z])/g, function(str){return str.toUpperCase().replace('_','');});
            };

            String.prototype._rCamelToDash = function(){
                return this.replace(/([A-Z])/g, function(str){return "-"+str.toLowerCase();});
            };

            String.prototype._rCamelToUnderscore = function(){
                return this.replace(/([A-Z])/g, function(str){return "_"+str.toLowerCase();});
            };
        },

        /**
         * Takes a camelCased string and breaks it into it's word components.
         * Taken from http://4umi.com/web/javascript/camelcase.php
         * @param {String}
         * @return {String}
         */
        camelCaseSplit: function(str)
        {
            var s = str._rTrim();
            return ( /\S[A-Z]/.test( s ) ) ?
                s.replace(/(.)([A-Z])/g, function(t,a,b)
                { return a + ' ' + b.toLowerCase(); }) :
                s.replace(/( )([a-z])/g, function(t,a,b) { return b.toUpperCase(); });
        },

        /**
         * Break a camel cased string apart, separating each word with a space and capitalising each word
         * @param {String} str
         * @return {String}
         */
        camelCaseToTitleText: function(str)
        {
            var numbers, parts, result;

            /* There is a bug with the _R.UTIL.titleCaps which doesn't apply
             * capitalisation if a number is present. Therefore, we convert all
             * numbers to @ symbols, feed the string into the functions, then
             * replace the @ symbols with the original number values before
             * returning result.
             */

            // Replace numbers with @ symbol
            numbers = str.match(/\d+/g);
            str = str.replace(/\d+/g, '@');

            parts = this.camelCaseSplit(str);
            result = this.titleCaps(parts);

            // Replace @ symbols numbers
            if(numbers === null) { return result; }

            for(var i=0; i<numbers.length; i++)
            {
                result = result.replace(/@/, numbers[i]);
            }

            return result;
        },

        /**
         * Takes a string as the first argument with n arguments after with which to perform variable substitution
         * @param {String} String for formatting
         * @return {String}
         * @example _R.UTIL.format('My name is {1} {2}', 'Ryan', 'Blunden');
         */
        format: function()
        {
            var args = [].slice.call(arguments), pattern;
            if(this.toString() != '[object Object]') { args.unshift(this.toString()); }
            pattern = new RegExp('{([1-' + args.length + '])}','g');
            return String(args[0]).replace(pattern, function(match, index) { return args[index]; });
        }
    };

    /**
     * Title Caps
     *
     * Ported to JavaScript By John Resig - http://ejohn.org/ - 21 May 2008
     * Original by John Gruber - http://daringfireball.net/ - 10 May 2008
     * License: http://www.opensource.org/licenses/mit-license.php
     */
    (function()
    {
        var small = "(a|an|and|as|at|but|by|en|for|if|in|of|on|or|the|to|v[.]?|via|vs[.]?)";
        var punct = "([!\"#$%&'()*+,./:;<=>?@[\\\\\\]^_`{|}~-]*)";

        /**
         * Apply title caps to the supplied string
         * @param {String} title
         * @return {String}
         */
        _R.STRING.titleCaps = function(title)
        {
            var parts = [], split = /[:.;?!] |(?: |^)["Ò]/g, index = 0;

            while (true)
            {
                var m = split.exec(title);

                parts.push( title.substring(index, m ? m.index : title.length)
                    .replace(/\b([A-Za-z][a-z.'Õ]*)\b/g, function(all)
                    {
                        return /[A-Za-z]\.[A-Za-z]/.test(all) ? all : upper(all);
                    })
                    .replace(RegExp("\\b" + small + "\\b", "ig"), lower)
                    .replace(RegExp("^" + punct + small + "\\b", "ig"), function(all, punct, word)
                    {
                        return punct + upper(word);
                    })
                    .replace(RegExp("\\b" + small + punct + "$", "ig"), upper));

                index = split.lastIndex;

                if(m) parts.push(m[0]);
                else break;
            }

            return parts.join("").replace(/ V(s?)\. /ig, " v$1. ")
                .replace(/(['Õ])S\b/ig, "$1s")
                .replace(/\b(AT&T|Q&A)\b/ig, function(all){
                    return all.toUpperCase();
                });
        };

        function lower(word) { return word.toLowerCase(); }

        function upper(word) { return word.substr(0,1).toUpperCase() + word.substr(1); }
    })();

    _R.STRING.init();
})(jQuery);
