#!/usr/bin/python3

'''Report the three top performers of a given area of comparison'''

import re
#mport sys
import glob
#mport pprint
import functools
#mport collections

def get_last_line(file_):
    '''Get the last line of file_'''
    last = None
    for line in file_:
        last = line
    return last

@functools.total_ordering
class Number_Pattern_Key(object):
    '''Store a number pattern key'''
    # pylint: disable=too-few-public-methods
    def __init__(self, number_pattern):
        self.number_pattern = number_pattern

    def __hash__(self):
        return hash(self.number_pattern)

    def __str__(self):
        return self.number_pattern

    __repr__ = __str__

    def cmp(self, other):
        '''Compare two number pattern keys'''
        if self.number_pattern < other.number_pattern:
            return -1
        elif self.number_pattern > other.number_pattern:
            return 1
        else:
            return 0

    def __lt__(self, other):
        if self.cmp(other) == -1:
            return True
        else:
            return False

    def __eq__(self, other):
        if self.cmp(other) == 0:
            return True
        else:
            return False


@functools.total_ordering
class Size_Key(object):
    '''Store a size key'''
    # pylint: disable=too-few-public-methods
    def __init__(self, size):
        self.size = size

    def __hash__(self):
        return hash(self.size)

    def __str__(self):
        return str(self.size)

    __repr__ = __str__

    def cmp(self, other):
        '''Compare two size keys in order'''
        if self.size < other.size:
            return -1
        elif self.size > other.size:
            return 1
        else:
            return 0

    def __lt__(self, other):
        if self.cmp(other) == -1:
            return True
        else:
            return False

    def __eq__(self, other):
        if self.cmp(other) == 0:
            return True
        else:
            return False


@functools.total_ordering
class Interpreter_Key(object):
    '''A class to hold an interpreter key'''
    # pylint: disable=too-few-public-methods
    def __init__(self, interpreter):
        self.interpreter = interpreter

    def __hash__(self):
        return hash(self.interpreter)

    def __str__(self):
        return str(self.interpreter)

    __repr__ = __str__

    def cmp(self, other):
        '''Compare two interpreter names'''
        if self.interpreter < other.interpreter:
            return -1
        elif self.interpreter > other.interpreter:
            return 1
        else:
            return 0

    def __lt__(self, other):
        if self.cmp(other) == -1:
            return True
        else:
            return False

    def __eq__(self, other):
        if self.cmp(other) == 0:
            return True
        else:
            return False


@functools.total_ordering
class Percentages_Key(object):
    '''Store a percentages (get and set) key'''
    # pylint: disable=too-few-public-methods
    def __init__(self, get_percentage, set_percentage):
        self.get_percentage = get_percentage
        self.set_percentage = set_percentage

    def __hash__(self):
        return hash('{} - {}'.format(self.get_percentage, self.set_percentage))

    def __str__(self):
        return str('{}/{}'.format(self.get_percentage, self.set_percentage))

    __repr__ = __str__

    def cmp(self, other):
        '''Compare two percentages keys'''
        if self.get_percentage < other.get_percentage:
            return -1
        elif self.get_percentage > other.get_percentage:
            return 1
        else:
            if self.set_percentage < other.set_percentage:
                return -1
            elif self.set_percentage > other.set_percentage:
                return 1
            else:
                return 0

    def __lt__(self, other):
        if self.cmp(other) == -1:
            return True
        else:
            return False

    def __eq__(self, other):
        if self.cmp(other) == 0:
            return True
        else:
            return False


@functools.total_ordering
class Tree_Type_Key(object):
    '''Store a tree type key'''
    # pylint: disable=too-few-public-methods
    def __init__(self, tree_type):
        self.tree_type = tree_type

    def __hash__(self):
        return hash(self.tree_type)

    def __str__(self):
        return str(self.tree_type)

    __repr__ = __str__

    def cmp(self, other):
        '''Compare two Tree_Type_keys'''
        if self.tree_type < other.tree_type:
            return -1
        elif self.tree_type > other.tree_type:
            return 1
        else:
            return 0

    def __lt__(self, other):
        if self.cmp(other) == -1:
            return True
        else:
            return False

    def __eq__(self, other):
        if self.cmp(other) == 0:
            return True
        else:
            return False


@functools.total_ordering
class Performer(object):
    '''Class for holding a description of a top performing datastructure'''
    # pylint: disable=too-few-public-methods,too-many-return-statements
    def __init__(self, size, tree_type, duration):
        self.size = size
        self.tree_type = tree_type
        self.duration = duration

    def cmp(self, other):
        '''Compare two Top_Performer's'''
        # Compare size in reverse
        if self.size < other.size:
            return 1
        elif self.size > other.size:
            return -1
        else:
            # Compare duration forward
            if self.duration < other.duration:
                return -1
            elif self.duration > other.duration:
                return 1
            #else:
            #    if self.tree_type < other.tree_type:
            #        return -1
            #    elif self.tree_type > other.tree_type:
            #        return 1
            #    else:
            #        return 0
            else:
                return 0

    def __lt__(self, other):
        if self.cmp(other) == -1:
            return True
        else:
            return False

    def __eq__(self, other):
        if self.cmp(other) == 0:
            return True
        else:
            return False



def gen_performers(dict_):
    '''Generate the top performers'''

    for size_key in dict_:
        tree_type_dict = dict_[size_key]
        for tree_type_key in tree_type_dict:
            yield Performer(size_key, tree_type_key, tree_type_dict[tree_type_key])

def main():
    # pylint: disable=too-many-locals
    '''Main function'''
    dict_ = {}
    for filename in glob.glob('*.dat'):
        fields = filename.split('-')
        interpreter = '-'.join(fields[:2])
        number_pattern = fields[2]
        get_percentage = int(fields[3])
        set_percentage = int(fields[4])
        tree_type = re.sub(r'\.dat$', '', '-'.join(fields[5:7]))
        with open(filename, 'r') as file_:
            last_line = get_last_line(file_)
        size, duration = last_line.split()
        size = int(size)
        duration = round(float(duration), 1)
        number_pattern_key = Number_Pattern_Key(number_pattern)
        size_key = Size_Key(size)
        interpreter_key = Interpreter_Key(interpreter)
        percentages_key = Percentages_Key(get_percentage, set_percentage)
        tree_type_key = Tree_Type_Key(tree_type)

        if number_pattern_key not in dict_:
            dict_[number_pattern_key] = {}

        if interpreter_key not in dict_[number_pattern_key]:
            dict_[number_pattern_key][interpreter_key] = {}

        if percentages_key not in dict_[number_pattern_key][interpreter_key]:
            dict_[number_pattern_key][interpreter_key][percentages_key] = {}

        if size_key not in dict_[number_pattern_key][interpreter_key][percentages_key]:
            dict_[number_pattern_key][interpreter_key][percentages_key][size_key] = {}

        if tree_type_key not in dict_[number_pattern_key][interpreter_key][percentages_key][size_key]:
            dict_[number_pattern_key][interpreter_key][percentages_key][size_key][tree_type_key] = duration

    num_top_performers = 20

    for number_pattern in sorted(dict_):
        print('<li>{}</li>'.format(number_pattern))
        print('\t<ul>')
        for interpreter_key in sorted(dict_[number_pattern]):
            print('\t<li>{}</li>'.format(interpreter_key))
            print('\t\t<ul>')
            for percentages_key in sorted(dict_[number_pattern][interpreter_key]):
                print('\t\t<li>get: {}% / set: {}%</li>'.format(percentages_key.get_percentage, percentages_key.set_percentage))
                print('\t\t\t<ol>')
                performers_it = gen_performers(dict_[number_pattern][interpreter_key][percentages_key])
                performers = list(performers_it)
                performers.sort()
                for performer in performers[:num_top_performers]:
                    string = '\t\t\t<li>Size: {:>7}, duration: {:>5}, dictionary type: {}</li>'.format(
                        performer.size, performer.duration, performer.tree_type)
                    print(string.replace(' ', '&nbsp;'))
                print('\t\t\t</ol>')
            print('\t\t</ul>')
        print('\t</ul>')


main()