import subprocess
import os
import sys

NUM_PARTS = 7
NUM_PARTS_GRADED = 6
CHECKS_PER_PART = 10


def count_points(input):
    """Extract the CORRECT and INCORRECT occurances from the make run output.
    Then return the occurance count of CORRECT.
    """
    results = [res for res in input.split() if not res.isdigit() and './' not
               in res]

    return results.count('CORRECT')


def evaluate_part(path):
    """This method runs the 'make run' command in the path passed to it. It
    then calculates the number of correct checks and returns that.
    """
    output = None

    try:
        output = subprocess.check_output(['make clean && make run'],
                                         shell=True,
                                         cwd=os.getcwd() +
                                         '/' + path).decode('UTF-8')
    except subprocess.CalledProcessError:
        print('--- MAKEFILE ERROR ---')
        print('A Makefile error occurred in path {}!'.format(path))
        sys.exit(0)

    return count_points(output)


def print_results_grade(results):
    """This program performs a quick analysis of the results, printing the
    number of correct and incorrect checks per part as well as the final grade.
    Each part is worth (points for part / total parts count). As 7 is not
    necessary to get full marks, it counts as bonus points.
    """
    total = 0

    for i in range(1, NUM_PARTS + 1):
        points = 0

        try:
            points = results[i]
        except KeyError:
            print('Part {} not found!'.format(i))

            continue

        print('Part {}: {} correct and {} incorrect'.format(i, points,
              CHECKS_PER_PART - points))

        part_points = points / NUM_PARTS_GRADED
        total += part_points

        print('Earned {0}x{1:.2f} points. Adding {2:.2f} points to final '
              'grade.'.format(points, 10 / (CHECKS_PER_PART
                              * NUM_PARTS_GRADED), part_points))

    print('FINAL GRADE: {0:.2f}'.format(total))


def main():
    """Run through the parts, calculate the points per part and then analyse
    the results.
    """
    results = {}

    for i in range(1, NUM_PARTS + 1):
        path = './part{}'.format(i)

        if not os.path.isdir(path):
            continue

        points = evaluate_part(path)
        results[i] = points

    print_results_grade(results)


if __name__ == "__main__":
    main()
