from collections import defaultdict
from lib.stats.helpers import get_naming_convention

def docstrings(items):
    
    total_docstring_length = defaultdict(lambda :0)
    n_docstrings = defaultdict(lambda :0)
    n_objects = defaultdict(lambda :0)

    for item in items:
        if not item['type'] in ('function','class','file'):
            continue
        n_objects[item['type']]+=1
        if len(item['docstring']) > 2:
            n_docstrings[item['type']]+=1
            total_docstring_length[item['type']]+=len(item['docstring'])

    docstring_coverage = {}

    for key in n_objects:
        docstring_coverage[key] = float(n_docstrings[key])/float(n_objects[key])

    average_docstring_length = {}

    for key in n_docstrings:
        if n_docstrings[key] == 0:
            continue
        average_docstring_length[key] = float(total_docstring_length[key])/float(n_docstrings[key])

    return {
        'n_docstrings' : dict(n_docstrings),
        'n_objects' : dict(n_objects),
        'docstring_coverage' : docstring_coverage,
        'average_docstring_length' : average_docstring_length,
        'total_docstring_length' : dict(total_docstring_length),
    }

def functions(items):

    n = 0
    total_number_of_lines = 0
    total_cyclomatic_complexity = 0
    naming_conventions = defaultdict(lambda : 0)
    cyclomatic_complexity_distribution = defaultdict(lambda : 0)

    for item in items:
        if not item['type'] == 'function':
            continue
        n+=1
        total_number_of_lines+= item['end_line']-item['start_line']+1
        total_cyclomatic_complexity+= item['cyclomatic_complexity']

        cyclomatic_complexity_distribution[item['cyclomatic_complexity']]+=1

        naming_convention = get_naming_convention(item['name'])

        naming_conventions[naming_convention]+=1

    if n == 0:
        average_number_of_lines = 0
        average_cyclomatic_complexity = 0
    else:
        average_number_of_lines = total_number_of_lines/float(n)
        average_cyclomatic_complexity = total_cyclomatic_complexity/float(n)
        
    return {
        'n' : n,
        'average_cyclomatic_complexity' : average_cyclomatic_complexity,
        'total_cyclomatic_complexity' : total_cyclomatic_complexity,
        'cyclomatic_complexity_distribution' : dict(cyclomatic_complexity_distribution),
        'average_number_of_lines' : average_number_of_lines,
        'total_number_of_lines' : total_number_of_lines,
        'naming_conventions' : dict(naming_conventions),
        }

def variables(items):
    total_length = 0
    naming_conventions = defaultdict(lambda :0)
    n = 0
    for item in items:
        if not item['type'] == 'variable':
            continue
        n+=1
        total_length+= len(item['name'])
        naming_convention = get_naming_convention(item['name'])
        naming_conventions[naming_convention]+=1

    if n == 0:
        average_length = 0
    else:
        average_length = total_length/float(n)

    return {
        'average_length' : average_length,
        'naming_conventions' : dict(naming_conventions),
        'n' : n,
        }


def classes(items):

    n = 0
    occurences = {}
    number_of_lines = 0
    total_number_of_lines = 0
    total_number_of_functions = 0
    total_cyclomatic_complexity = 0
    naming_conventions = defaultdict(lambda : 0)
    cyclomatic_complexity_distribution = defaultdict(lambda : 0)

    for item in items:

        if not item['type'] == 'class':
            continue

        n += 1
        total_number_of_lines+= item['end_line']-item['start_line']+1
        total_number_of_functions += len(filter(lambda child:child['type'] == 'function',item['children']))
        total_cyclomatic_complexity+= item['cyclomatic_complexity']

        cyclomatic_complexity_distribution[item['cyclomatic_complexity']]+=1

        naming_convention = get_naming_convention(item['name'])
        naming_conventions[naming_convention] += 1

    if n == 0:
        average_number_of_lines = 0
        average_number_of_functions = 0
        average_cyclomatic_complexity = 0
    else:
        average_number_of_lines = total_number_of_lines/float(n)
        average_number_of_functions = total_number_of_functions/float(n)
        average_cyclomatic_complexity = total_cyclomatic_complexity/float(n)

    return {
        'n' : n,
        'average_cyclomatic_complexity' : average_cyclomatic_complexity,
        'total_cyclomatic_complexity' : total_cyclomatic_complexity,
        'cyclomatic_complexity_distribution' : dict(cyclomatic_complexity_distribution),
        'average_number_of_lines' : average_number_of_lines,
        'total_number_of_lines' : total_number_of_lines,
        'average_number_of_functions' : average_number_of_functions,
        'total_number_of_functions' : total_number_of_functions,
        'naming_conventions' : dict(naming_conventions)
        }

def reduce(self,key,items):
    from_imports = 0
    imports = 0 
    imported_names = {}
    imported_modules = []
    for item in items:
        if key == 'from_import':
            from_imports += 1
            imported_names[item[0]] = item[1]
        elif key == 'import':
            imports += 1
            imported_modules += item
    return {
        'imported_modules' : imported_modules,
        'imported_names' : imported_names,
    }
