import datetime


def id_number_checksum(gd):
    """Calculates a Swedish ID number checksum, using the "Luhn"-algoritm."""
    n = s = 0
    for c in (gd['year'] + gd['month'] + gd['day'] + gd['serial']):
        # When validating interim ID numbers, the letter is considered
        # equivalent to 1. Source:
        # https://wiki.swami.se/display/Inkubator/norEduPersonNIN+och+Svenska+Personnummer
        if c.isalpha():
            c = 1

        tmp = ((n % 2) and 1 or 2) * int(c)

        if tmp > 9:
            tmp = sum([int(i) for i in str(tmp)])

        s += tmp
        n += 1

    if (s % 10) == 0:
        return 0

    return (((s // 10) + 1) * 10) - s


def validate_id_birthday(gd, fix_coordination_number_day=True):
    """
    Validates the birth_day and returns the datetime.date object for the birth_day.

    If the date is an invalid birth day, a ValueError will be raised.
    """
    today = datetime.date.today()

    day = int(gd['day'])
    if fix_coordination_number_day and day > 60:
        day -= 60

    if gd['century'] is None:

        # The century was not specified, and need to be calculated from todays date
        year = int(today.strftime('%Y')) - int(today.strftime('%y')) + int(gd['year'])

        if ('%s%s%02d' % (gd['year'], gd['month'], day)) > today.strftime('%y%m%d'):
            year -= 100

        # If the person is older than 100 years
        if gd['sign'] == '+':
            year -= 100
    else:
        year = int(gd['century'] + gd['year'])

        # Make sure the year is valid
        # There are no swedish personal identity numbers where year < 1800
        if year < 1800:
            raise ValueError

    # ValueError will be raise for invalid dates
    birth_day = datetime.date(year, int(gd['month']), day)

    # birth_day must not be in the future
    if birth_day > today:
        raise ValueError

    return birth_day


def format_personal_id_number(birth_day, gd):
    # birth_day.strftime cannot be used, since it does not support dates < 1900
    # If the ID number is an interim number, the letter in the serial part
    # should be normalized to upper case. Source:
    # https://wiki.swami.se/display/Inkubator/norEduPersonNIN+och+Svenska+Personnummer
    return str(birth_day.year) + gd['month'] + gd['day'] + gd['serial'].upper() + gd['checksum']


def format_organisation_number(gd):
    if gd['century'] is None:
        century = ''
    else:
        century = gd['century']

    return century + gd['year'] + gd['month'] + gd['day'] + gd['serial'] + gd['checksum']


def valid_organisation(gd):
    return gd['century'] in (None, 16) and \
        int(gd['month']) >= 20 and \
        gd['sign'] in (None, '-') and \
        gd['year'][0] in ('2', '5', '7', '8', '9')  # group identifier
