import numpy as np
from tabulate import tabulate


class Report(object):
    def __init__(self):
        self.__report = {}

    @classmethod
    def from_dict(cls, dic):
        report = cls()
        report._Report__report = dic
        return report

    def __add_scores(self, cate, precision, recall, fscore):
        if cate not in self.__report:
            self.__report[cate] = []
        self.__report[cate].append({
            'precision': precision,
            'recall': recall,
            'fscore': fscore,
        })

    def add_train_scores(self, precision, recall, fscore):

        self.__add_scores('train', precision, recall, fscore)

    def add_valid_scores(self, precision, recall, fscore):
        self.__add_scores('valid', precision, recall, fscore)

    def add_test_scores(self, precision, recall, fscore):
        self.__add_scores('test', precision, recall, fscore)

    def as_dict(self):
        return self.__report

    def get_average_precision_recall_fscore(self):
        def avg_prf(xs):
            p = np.mean([x['precision'] for x in xs]).round(2)
            r = np.mean([x['recall'] for x in xs]).round(2)
            f = np.mean([x['fscore'] for x in xs]).round(2)
            return [p, r, f]
        return avg_prf(self.__report['train'])\
            + avg_prf(self.__report['valid'])\
            + avg_prf(self.__report['test'])\



def table_report(reports, names):
    table = [
        ['', 'Train', 'Train', 'Train',
             'Valid', 'Valid', 'Valid',
             'Test', 'Test', 'Test'],
        ['', 'Precision', 'Recall', 'F Score',
             'Precision', 'Recall', 'F Score',
             'Precision', 'Recall', 'F Score']
    ]
    for report, name in zip(reports, names):
        table.append([name] + report.get_average_precision_recall_fscore())

    return tabulate(table)

import numpy as np
from tabulate import tabulate


class Report(object):
    def __init__(self):
        self.__report = {}

    @classmethod
    def from_dict(cls, dic):
        report = cls()
        report._Report__report = dic
        return report

    def __add_scores(self, cate, precision, recall, fscore):
        if cate not in self.__report:
            self.__report[cate] = []
        self.__report[cate].append({
            'precision': precision,
            'recall': recall,
            'fscore': fscore,
        })

    def add_train_scores(self, precision, recall, fscore):

        self.__add_scores('train', precision, recall, fscore)

    def add_valid_scores(self, precision, recall, fscore):
        self.__add_scores('valid', precision, recall, fscore)

    def add_test_scores(self, precision, recall, fscore):
        self.__add_scores('test', precision, recall, fscore)

    def as_dict(self):
        return self.__report

    def get_average_precision_recall_fscore(self):
        def avg_prf(xs):
            p = np.mean([x['precision'] for x in xs]).round(2)
            r = np.mean([x['recall'] for x in xs]).round(2)
            f = np.mean([x['fscore'] for x in xs]).round(2)
            return [p, r, f]
        return avg_prf(self.__report['train'])\
            + avg_prf(self.__report['valid'])\
            + avg_prf(self.__report['test'])\



def table_report(reports, names):
    table = [
        ['', 'Train', 'Train', 'Train',
             'Valid', 'Valid', 'Valid',
             'Test', 'Test', 'Test'],
        ['', 'Precision', 'Recall', 'F Score',
             'Precision', 'Recall', 'F Score',
             'Precision', 'Recall', 'F Score']
    ]
    for report, name in zip(reports, names):
        table.append([name] + report.get_average_precision_recall_fscore())

    return tabulate(table)
