import numpy as np

from mrjob.job import MRJob
from itertools import combinations, permutations
from math import sqrt
import mrjob

from scipy.stats.stats import pearsonr

class GameSimilarities(MRJob):

    def steps(self):
        thesteps = [
            self.mr(mapper=self.line_mapper, reducer=self.publications_items_collector),
            self.mr(mapper=self.pair_items_mapper, reducer=self.calc_sim_collector),
            self.mr(mapper=self.ranking_mapper, reducer=self.top_similar_collector)
        ]
        return thesteps

    def line_mapper(self,_,line):
    	print line
        publication_id,game_id,score,game_avg,publication_avg=line.split(',')
        yield publication_id, (game_id,score,game_avg,publication_avg)

    def publications_items_collector(self, publication_id, values):
        ratings=[]
        for game_id,score,game_avg,publication_avg in values:
            ratings.append((game_id,(score, publication_avg)))
        yield publication_id, ratings

    def pair_items_mapper(self, publication_id, values):
        ratings = values
        for game1tuple, game2tuple in combinations(ratings, 2):
            game1, game1r=game1tuple
            game2, game2r=game2tuple
            if game1 <= game2 :
                yield (game1, game2), (game1r, game2r)
            else:
                yield (game2, game1), (game2r, game1r)

    def calc_sim_collector(self, key, values):
        (game1, game2), common_ratings = key, values
        diff1=[]
        diff2=[]
        n_common=0

        for rt1, rt2 in common_ratings:
            diff1.append(float(rt1[0])-float(rt1[1]))
            diff2.append(float(rt2[0])-float(rt2[1]))
            n_common=n_common+1
        if n_common==0:
            rho=0.
        else:
            rho=pearsonr(diff1, diff2)[0]
            if np.isnan(rho):
                rho=0.
        yield (game1, game2), (rho, n_common)

    def ranking_mapper(self, games, values):
        sim, n_common = values
        game1, game2 = games
        if int(n_common) > 0:
            yield (game1), (sim, game2, n_common)

    def top_similar_collector(self, key, values):
        game1 = key
        for sim, game2, n_common in sorted(values, reverse=True):
            yield None, (game1, game2, sim, n_common)

#Below MUST be there for things to work!
if __name__ == '__main__':
    GameSimilarities.run()
