import math
import sys

if sys.version_info >= (3, 0):
    from itertools import zip_longest
else:   # pragma    nocover
    from itertools import izip_longest as zip_longest, izip as zip

__all__ = ['grouper', 'num2eng', 'nice_number']


# Tokens from 1000 and up
_PRONOUNCE = ['', 'thousand', 'million', 'billion', 'trillion']

# Tokens up to 90
_SMALL = {
    '1': 'one',
    '2': 'two',
    '3': 'three',
    '4': 'four',
    '5': 'five',
    '6': 'six',
    '7': 'seven',
    '8': 'eight',
    '9': 'nine',
    '10': 'ten',
    '11': 'eleven',
    '12': 'twelve',
    '13': 'thirteen',
    '14': 'fourteen',
    '15': 'fifteen',
    '16': 'sixteen',
    '17': 'seventeen',
    '18': 'eighteen',
    '19': 'nineteen',
    '20': 'twenty',
    '30': 'thirty',
    '40': 'forty',
    '50': 'fifty',
    '60': 'sixty',
    '70': 'seventy',
    '80': 'eighty',
    '90': 'ninety'
}


def grouper(n, iterable, padvalue=None):
    '''grouper(3, 'abcdefg', 'x') -->
    ('a','b','c'), ('d','e','f'), ('g','x','x')
    '''
    return zip_longest(*[iter(iterable)]*n, fillvalue=padvalue)


def num2eng(num):
    '''English representation of a number up to a trillion.
    '''
    num = str(int(num))  # Convert to string, throw if bad number
    if (len(num) / 3 >= len(_PRONOUNCE)):  # Sanity check
        return num
    elif num == '0':  # Zero is a special case
        return 'zero'
    pron = []  # Result accumulator
    first = True
    for pr, bits in zip(_PRONOUNCE, grouper(3, reversed(num), '')):
        num = ''.join(reversed(bits))
        n = int(num)
        bits = []
        if n > 99:  # Got hundred
            bits.append('%s hundred' % _SMALL[num[0]])
            num = num[1:]
            n = int(num)
            num = str(n)
        if (n > 20) and (n != (n // 10 * 10)):
            bits.append('%s %s' % (_SMALL[num[0] + '0'], _SMALL[num[1]]))
        elif n:
            bits.append(_SMALL[num])
        if len(bits) == 2 and first:
            first = False
            p = ' and '.join(bits)
        else:
            p = ' '.join(bits)
        if p and pr:
            p = '%s %s' % (p, pr)
        pron.append(p)
    return ', '.join(reversed(pron))


def nice_number(number, name=None, plural=None):
    if not name:
        return num2eng(number)
    elif number == 1:
        return 'one %s' % name
    else:
        if not plural:
            plural = '%ss' % name
        return '%s %s' % (num2eng(number), plural)
