var NumberToWords = (function () {
    var words = [['ноль', ['один', 'одна', 'одно'],
            ['два', 'две', 'два'], 'три', 'четыре', 'пять',
                'шесть', 'семь', 'восемь', 'девять', 'десять',
                'одиннадцать', 'двенадцать', 'тринадцать',
                'четырнадцать', 'пятнадцать', 'шестнадцать',
                'семнадцать', 'восемнадцать', 'девятнадцать'],
            [,,'двадцать', 'тридцать', 'сорок', 'пятьдесят',
                'шестьдесят', 'семьдесят', 'восемьдесят',
                'девяносто'],
            [,'сто', 'двести', 'триста', 'четыреста', 'пятьсот',
                'шестьсот', 'семьсот', 'восемьсот', 'девятьсот'],
            ['тысяча', 'тысячи', 'тысяч'],
            ['миллион', 'миллиона', 'миллионов']],
        gap = String.fromCharCode(32),
        overdo = 'слишком много';
    function Convert(aNum, aCase, aBool) {
        var p, a;
        aNum = parseInt(aNum, 10);
        if (aNum < 20) {
            return ((aBool && !aNum)
                    ? gap
                    : ((a = words[0][aNum]) instanceof Array)
                       ? a[aCase || 0]
                       : a);
        }
        if (aNum < 100) {
            p = parseInt(aNum / 10, 10);
            return Join(words[1][p],
                        Convert(aNum % 10, aCase, true));
        }
        if (aNum < 1000) {
            p = parseInt(aNum / 100, 10);
            return Join(words[2][p],
                        Convert(aNum % 100, aCase, true));
        }
        if (aNum < 1000000) {
            p = parseInt(aNum / 1000, 10);
            return Join(Convert(p, 1, true),
                        Proper(p, words[3]),
                        Convert(aNum % 1000, aCase, true));
        }
        p = parseInt(aNum / 1000000, 10);
        return Join(Convert(p, 0, true),
                    Proper(p, words[4]),
                    Convert(aNum % 1000000, aCase, true));
    
    };
    function Proper(aNum, aArr) {
        aNum = Simple(aNum);
        return ((aNum == 1) 
                ? aArr[0]
                : ((aNum < 5 && aNum)
                   ? aArr[1]
                   : aArr[2]));
    };
    function Simple(aNum) {
        return ((aNum < 20)
                ? aNum
                : (aNum < 100)
                  ? aNum % 10
                  : arguments.callee(aNum % 100));
    }
    function Join() {
        return Array.prototype.join.call(arguments, gap);
    };
    return (function (aNum, aArr, aCase) {
        var b = (aNum > 999999999),
            w = (b) ? overdo
                    : Convert(aNum, aCase),
            i = (aArr instanceof Array)
                ? Proper(b ? 5 : aNum, aArr)
                : gap;
        return Join(w, i).replace(/\s\s\s?/g, gap);
    });
})();
