/*
  JavaScript port of John Gruber's TitleCase Perl script:
  http://daringfireball.net/projects/titlecase/TitleCase.pl

  This filter changes all words to Title Caps, and attempts to be clever
  about *un*capitalizing small words like a/an/the in the input.

  The list of "small words" which are not capped comes from
  the New York Times Manual of Style, plus 'vs' and 'v'.

  License: http://www.opensource.org/licenses/mit-license.php

  David Lindquist (http://www.stringify.com/)
  21 May 2008
*/

String.prototype.toTitleCase = function() {
    var small_words = 'a an and as at but by en for if in of on or the to v[.]? via vs[.]?'.split(/\s/);
    var punct = '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~';
    var small_re = small_words.join('|');

    function capitalize(s) {
        return s.charAt(0).toUpperCase() + s.substring(1);
    }

    var general_repl = [
        [/\b([A-Za-z][a-z.\']*)\b/g,
         function(str, word) {
             if (/[A-Za-z][.][A-Za-z]/.test(word))
                 return word;
             return capitalize(word);
         }
        ],
        [new RegExp('\\b(' + small_re + ')\\b', 'ig'),
         function(str, small) { return small.toLowerCase(); }
        ],
        [new RegExp('^([' + punct + ']*)(' + small_re + ')\\b', 'ig'),
         function(str, punct, small) { return punct + capitalize(small); }
        ],
        [new RegExp('\\b(' + small_re + ')([' + punct + ']*)$', 'ig'),
         function(str, small, punct) { return capitalize(small) + punct; }
        ]
    ];

    var special_repl = [
        [/ V(s?)\. /g,
         function(str, s) { return ' v' + s + '. '; }
        ],
        [/([\'\u2019])S\b/g,
         function(str, apos) { return apos + 's' }
        ],
        [/\b(AT&T|Q&A)\b/ig,
         function(str, s) { return s.toUpperCase(); }
        ]
    ];

    var split_re = /([:.;?!][ ]|(?:[ ]|^)[\"\u201c])/g;
    var tokens_in = []
    var tokens_out = [];
    var token, regex, repl, idx = 0, m;

    while ((m = split_re.exec(this)) != null) {
        tokens_in.push(this.substring(idx, m.index), m[1]);
        idx = split_re.lastIndex;
    }
    tokens_in.push(this.substring(idx));

    for (var i = 0; i < tokens_in.length; i++) {
        token = tokens_in[i];
        for (var j = 0; j < general_repl.length; j++) {
            regex = general_repl[j][0];
            repl  = general_repl[j][1];
            token = token.replace(regex, repl);
        }
        tokens_out.push(token);
    }
    var title = tokens_out.join('');
    for (var k = 0; k < special_repl.length; k++) {
        regex = special_repl[k][0];
        repl  = special_repl[k][1];
        title = title.replace(regex, repl);
    }

    return title;
}
