""" A sorting algorithm module.

The Module purpose is to choose the best result returned from the AcoustID
Web Service.

"""
from collections import defaultdict


class ResultParser(object):

    SCORE, DURATION, TITLE, ARTIST, DEVIATION = xrange(5)

    def __init__(self, results_gen, org_duration):
        """
        Set up all the variables needed to generate a grade for a result.

        track_name_counter, artist_counter = dictionaries that count
        recurrences in artist/track results, for statistical preference.

        add a 4th value to the result tuple ("time deviation") and
        returns a list of all parsed tuples ("self.results_list").

        time_deviation : delta time between original track length and result
        length (In Seconds).

        :param results_gen: a results generator returned from metacore module.
        :param org_duration: Original duration of the file (In Seconds).


        """
        self.results_gen = results_gen
        self.org_duration = org_duration
        self.artist_counter = defaultdict(int)
        self.track_name_counter = defaultdict(int)
        self.grade_dictionary = dict()
        self.results_list = list()
        for result in self.results_gen:
            self.artist_counter[result[self.ARTIST]] += 1
            self.track_name_counter[result[self.TITLE]] += 1
            self.time_deviation = abs(
                self.org_duration - result[self.DURATION])
            self.results_list.append(result + (self.time_deviation,))

    def grade_parser(self, result):
        """ Receive a deviation-added result tuple and generate a final grade.

        final grade = the factor which by the module choose the best match,
        generated by a collection of sub-grades:

            Score grade = a grade from AcoustID API, based on acoustic
            resemblance.

            Frequency grade = Counted repetition of Artist/ Track name results.

            Deviation grade = The time difference between the returned track
            length and the original (High deviation grade == Bad!)

        Final grade is user-transparent but "Good Match" should be in
        100-200 zone.

        :param result: parsed result tuple (added deviation stat).
        :return: (artist, track name ) tuple.


        """
        score_grade = int(result[self.SCORE] * 100)
        frequency_grade = self.track_name_counter[result[self.TITLE]] + \
            self.artist_counter[result[self.ARTIST]]
        frequency_grade *= 10
        deviation_grade = result[self.DEVIATION] * 10
        final_grade = score_grade + frequency_grade - deviation_grade
        self.grade_dictionary[final_grade] = result[self.ARTIST], \
                                             result[self.TITLE]

    def main(self):
        for result in self.results_list:
            self.grade_parser(result)
        self.best_match_key = max(self.grade_dictionary.keys())
        return self.grade_dictionary[self.best_match_key]
