"""
Modification of anglicize to enfore preconditions

Our primary reason to use asserts is to enforce preconditions.
If a precondition is violated, we would like to know immediately,
rather than waiting until the error causes more damage elsewhere

Author: Walker M. White
Date:   September 6, 2017 (Python 3 Version)
"""


def anglicize(n):
    """
    Returns: English equivalent of n.
    
    Examples:
        3:      "three"
        45:     "forty five"
        100:    "one hundred"
        127:    "one hunded twenty seven"
        1001:   "one thousand one"
        990099: "nine hundred ninety thousand ninety nine
    
    Parameter: the integer to anglicize
    Precondition: 0 < n < 1,000,000
    """
    
    # Enforce precondition
    assert type(n) == int, 'Value '+repr(n)+' is not an int'
    assert 0 < n and n < 1000000, 'Value '+repr(n)+' is not in the range 1..999999'

    # Carry out rest of code
    if n < 1000:
        return anglicize1000(n)
    
    # n >= 1000
    prefix = anglicize1000(n/1000) + ' thousand'
    suffix = ''
    if n % 1000 != 0:
        suffix = ' '+anglicize1000(n % 1000)
    
    return prefix+suffix


def anglicize1000(n):
    """
    Returns: English equiv of n.
    
    Parameter: the integer to anglicize
    Precondition: n in 1..999
    """
    
    # Enforce precondition
    assert type(n) == int, 'Value '+repr(n)+' is not an int'
    assert 0 < n and n < 1000, 'Value '+repr(n)+' is not in the range 1..999'

    # Carry out rest of code
    if n < 20:
        return anglicize1to19(n)
    
    # n >= 20
    if n < 100:
        return anglicize20to99(n)
    
    # n >= 100
    return anglicize100to999(n)


def anglicize1to19(n):
    """
    Returns: English equiv of n.
    
    Parameter: the integer to anglicize
    Precondition: n in 1..19
    """
    
    # Enforce precondition
    assert type(n) == int, 'Value '+repr(n)+' is not an int'
    assert 0 < n and n < 20, 'Value '+repr(n)+' is not in the range 1..19'

    # Carry out rest of code
    if n == 1:
        return 'one'
    elif n == 2:
        return 'two'
    elif n == 3:
        return 'three'
    elif n == 4:
        return 'four'
    elif n == 5:
        return 'five'
    elif n == 6:
        return 'six'
    elif n == 7:
        return 'seven'
    elif n == 8:
        return 'eight'
    elif n == 9:
        return 'nine'
    elif n == 10:
        return 'ten'
    elif n == 11:
        return 'eleven'
    elif n == 12:
        return 'twelve'
    elif n == 13:
        return 'thirteen'
    elif n == 14:
        return 'fourteen'
    elif n == 15:
        return 'fifteen'
    elif n == 16:
        return 'sixteen'
    elif n == 17:
        return 'seventeen'
    elif n == 18:
        return 'eighteen'
    
    # n = 19
    return 'nineteen'


def anglicize20to99(n):
    """
    Returns: English equiv of n.
    
    Parameter: the integer to anglicize
    Precondition: n in 20..99
    """
    
    # Enforce precondition
    assert type(n) == int, 'Value '+repr(n)+' is not an int'
    assert 19 < n and n < 100, 'Value '+repr(n)+' is not in the range 20..99'

    # Carry out rest of code
    prefix = tens(n/10)
    suffix = ''
    if n % 10 != 0:
        suffix = ' '+anglicize1to19(n % 10)
    return prefix+suffix


def anglicize100to999(n):
    """
    Returns: English equiv of n.
    
    Parameter: the integer to anglicize
    Precondition: n in 100..999
    """
    
    # Enforce precondition
    assert type(n) == int, 'Value '+repr(n)+' is not an int'
    assert 99 < n and n < 1000, 'Value '+repr(n)+' is not in the range 100..999'

    prefix = anglicize1to19(n/100) + ' hundred'

    # Carry out rest of code
    # Anglicize the first three digits
    hundreds = n % 100
    suffix = ''
    if hundreds > 0 and hundreds < 20:
        suffix = ' '+anglicize1to19(hundreds)
    elif hundreds > 20:
        suffix = ' '+anglicize20to99(hundreds)
    
    return prefix + suffix


def tens(n):
    """
    Returns: tens-word for n
    
    Parameter: the integer to anglicize
    Precondition: n in 2..9
    """
    
    # Enforce precondition
    assert type(n) == int, 'Value '+repr(n)+' is not an int'
    assert 1 < n and n < 10, 'Value '+repr(n)+' is not in the range 2..9'

    # Carry out rest of code
    if n == 2:
        return 'twenty'
    elif n == 3:
        return 'thirty'
    elif n == 4:
        return 'forty'
    elif n == 5:
        return 'fifty'
    elif n == 6:
        return 'sixty'
    elif n == 7:
        return 'seventy'
    elif n == 8:
        return 'eighty'
    
    return 'ninety'
