"""
    overlap_functions
    ~~~~~~~~~~~~~~~~~

    Contains functions used for computation of overlap.

    :author: Fahad Khalid
    :license: MIT, see LICENSE for more details.
"""


class OverlapAnalyzer:
    # Constructor
    def __init__(self, repToGiantDict, repertoires):
        # Copy of dict: key=repertoire, value=giant
        self.repToGiantDict = repToGiantDict

        # List of available repertoires
        self.repertoires = repertoires

    def getOverlapData(self):
        if len(self.repertoires) < 2:
            print("Overlap computation triggered with only one repertoire!")
            print("Overlap can only be calculated with 2 or more repertoires.")

            return None, None

        # Overlap dict for all repertoires. Dict{rep : {seq : [target reps]}}
        allOverlap = {rep: {seq: [] \
                            for seq in self.repToGiantDict[rep].vs["sequences"]} \
                      for rep in self.repertoires}

        # Initialize the overlap matrix with zeros
        overlapMat = [[0 for x in range(len(self.repertoires))] \
                      for x in range(len(self.repertoires))]

        # For each repertoire,
        for i in range(len(self.repertoires) - 1):
            # Get giant for this repertoire
            giantI = self.repToGiantDict[self.repertoires[i]]

            # Get sequence list from giant
            seqsI = giantI.vs["sequences"]

            # For the rest of the repertoires,
            for j in range(i + 1, len(self.repertoires)):
                # Get giant for this repertoire
                giantJ = self.repToGiantDict[self.repertoires[j]]

                # Get sequence list from giant
                seqsJ = giantJ.vs["sequences"]

                # Get the list of sequences that are common to both repertoires
                overlapList = self.getOverlapList(seqsI, seqsJ)

                # Get the number of sequences that overlap between the
                # two repertoires, and set it in the matrix
                overlapMat[i][j] = overlapMat[j][i] = len(overlapList)

                # If there is at least one shared sequence,
                if len(overlapList) > 0:
                    # For each sequence in the list,
                    for sequence in overlapList:
                        # Append the target to the target list for this sequence
                        allOverlap[self.repertoires[i]][sequence].append(self.repertoires[j])
                        allOverlap[self.repertoires[j]][sequence].append(self.repertoires[i])

        return overlapMat, self.repertoires, allOverlap

    # Returns a list of sequences that are common to the two input sequence
    # lists
    def getOverlapList(self, seqs1, seqs2):
        return list(set(seqs1) & set(seqs2))
