/*
 * Changes words into other kinds of words.
 *
 * NOTE: This script extends the jQuery JavaScript framework
 *       http://jquery.com/
 */

(function($) {
    // Replaces underscores with spaces
    $.fn.humanize = function(word) {
        return word.replace(/_/g, " ");
    }

    // See private function below for documentation
    $.fn.ordinalize = function(number) {
        return ordinalize(number);
    }

    /*
     * pluralize expects between 2 to 3 arguments:
     *     1. The count of items to pluralize
     *     2. The singular form of the item to pluralize
     *     3. The plural form of the item to pluralize (optional)
     *
     * See private function below for documentation
     */
    $.fn.pluralize = function() {
        var count    = arguments[0];
        var singular = arguments[1];
        var plural   = arguments[2];

        // Bail out (the good kind)
        if (arguments.length < 2) return "";
        if (isNaN(count))         return "";

        return count + " " + (1 == parseInt(count) ?
                singular :
                plural || pluralize(singular));
    }

    // See private function below for documentation
    $.fn.singularize = function(plural) {
        return singularize(plural);
    }

    // Capitalizes the first letter of every word
    $.fn.title_case = function(sentence) {
        return sentence.toLowerCase()
            .replace(/\b('?[a-z])/g, function(matches){
                // IE returns a string, if only 1 match
                if ("string" == typeof matches) {
                    return matches.toUpperCase();
                } else {
                    return matches[0].toUpperCase();
                }
            });
    }

    // Private stuff

    // Arrays reversed from order in ActiveSupport; this is a queue not a stack
    plural = [
        [/(quiz)$/i,               "$1zes"  ],
        [/^(ox)$/i,                "$1en"   ],
        [/([m|l])ouse$/i,          "$1ice"  ],
        [/(matr|vert|ind)ix|ex$/i, "$1ices" ],
        [/(x|ch|ss|sh)$/i,         "$1es"   ],
        [/([^aeiouy]|qu)y$/i,      "$1ies"  ],
        [/(hive)$/i,               "$1s"    ],
        [/(?:([^f])fe|([lr])f)$/i, "$1$2ves"],
        [/sis$/i,                  "ses"    ],
        [/([ti])um$/i,             "$1a"    ],
        [/(buffal|tomat)o$/i,      "$1oes"  ],
        [/(bu)s$/i,                "$1ses"  ],
        [/(alias|status)$/i,       "$1es"   ],
        [/(octop|vir)us$/i,        "$1i"    ],
        [/(ax|test)is$/i,          "$1es"   ],
        [/s$/i,                    "s"      ],
        [/$/,                      "s"      ]
    ];

    singular = [
        [/(quiz)zes$/i,                                                    "$1"     ],
        [/(matr)ices$/i,                                                   "$1ix"   ],
        [/(vert|ind)ices$/i,                                               "$1ex"   ],
        [/^(ox)en/i,                                                       "$1"     ],
        [/(alias|status)es$/i,                                             "$1"     ],
        [/(octop|vir)i$/i,                                                 "$1us"   ],
        [/(cris|ax|test)es$/i,                                             "$1is"   ],
        [/(shoe)s$/i,                                                      "$1"     ],
        [/(o)es$/i,                                                        "$1"     ],
        [/(bus)es$/i,                                                      "$1"     ],
        [/([m|l])ice$/i,                                                   "$1ouse" ],
        [/(x|ch|ss|sh)es$/i,                                               "$1"     ],
        [/(m)ovies$/i,                                                     "$1ovie" ],
        [/(s)eries$/i,                                                     "$1eries"],
        [/([^aeiouy]|qu)ies$/i,                                            "$1y"    ],
        [/([lr])ves$/i,                                                    "$1f"    ],
        [/(tive)s$/i,                                                      "$1"     ],
        [/(hive)s$/i,                                                      "$1"     ],
        [/([^f])ves$/i,                                                    "$1fe"   ],
        [/(^analy)ses$/i,                                                  "$1sis"  ],
        [/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i, "$1$2sis"],
        [/([ti])a$/i,                                                      "$1um"   ],
        [/(n)ews$/i,                                                       "$1ews"  ],
        [/s$/i,                                                            ""       ]
    ];

    irregular = [
        ['move',   'moves'   ],
        ['sex',    'sexes'   ],
        ['child',  'children'],
        ['man',    'men'     ],
        ['person', 'people'  ]
    ];

    uncountable = [
        "sheep",
        "fish",
        "series",
        "species",
        "money",
        "rice",
        "information",
        "equipment"
    ];

    // 1st, 2nd, 3rd, 4th, etc.
    function ordinalize(number) {
        if (11 <= parseInt(number) % 100 && parseInt(number) % 100 <= 13) {
            return number + "th";
        } else {
            switch (parseInt(number) % 10) {
                case  1: return number + "st";
                case  2: return number + "nd";
                case  3: return number + "rd";
                default: return number + "th";
            }
        }
    }

    // Takes a word and makes it plural
    function pluralize(word) {
        var i = 0;
        for (i = 0; i < this.uncountable.length; i++) {
            var uncountable = this.uncountable[i];
            if (word.toLowerCase() == uncountable) {
                return uncountable;
            }
        }
        for (i = 0; i < this.irregular.length; i++) {
            var singular = this.irregular[i][0];
            var plural   = this.irregular[i][1];
            if ((word.toLowerCase() == singular) || (word == plural)) {
                return plural;
            }
        }
        for (i = 0; i < this.plural.length; i++) {
            var regex          = this.plural[i][0];
            var replace_string = this.plural[i][1];
            if (regex.test(word)) {
                return word.replace(regex, replace_string);
            }
        }
        // Else, how did we get here?
        return word;
    }

    // Takes a word and makes it singular
    function singularize(word) {
        var i = 0;
        for (i = 0; i < this.uncountable.length; i++) {
            var uncountable = this.uncountable[i];
            if (word.toLowerCase() == uncountable) {
                return uncountable;
            }
        }
        for (i = 0; i < this.irregular.length; i++) {
            var singular = this.irregular[i][0];
            var plural   = this.irregular[i][1];
            if ((word.toLowerCase() == singular) || (word == plural)) {
                return singular;
            }
        }
        for (i = 0; i < this.singular.length; i++) {
            var regex          = this.singular[i][0];
            var replace_string = this.singular[i][1];
            if (regex.test(word)) {
                return word.replace(regex, replace_string);
            }
        }
        // Else, how did we get here?
        return word;
    }
})(jQuery);

// TODO: Is this the best place for these?

jQuery.extend(Number.prototype, {
    ordinalize: function() {
        return jQuery().ordinalize(this);
    }
});

jQuery.extend(String.prototype, {
    humanize: function() {
        return jQuery().humanize(this);
    },
    pluralize: function(count, singular) {
        return jQuery().pluralize(count, this, singular);
    },
    singularize: function() {
        return jQuery().singularize(this);
    },
    title_case: function() {
        return jQuery().title_case(this);
    }
});