# -*- coding: utf-8 -*-
"""
Created on Wed Aug 19 02:05:33 2020

@author: andrei
"""

import os
import sys

import json
import re
from copy import deepcopy

import pymex
from pymex import mif

class Interaction(mif.Names, mif.Xref):
    """MIF Interaction representation."""
    
    physical = {"names": {
                 "shortLabel": "physical association",
                 "fullName": "physical association"
                 },
              "xref": {
                  "primaryRef": {
                     "db": "psi-mi",
                     "dbAc": "MI:0488",
                     "id": "MI:0915",
                     "refType": "identity",
                     "refTypeAc": "MI:0356"
                     } 
                 }
             } 
         
    direct = {"names": {
                 "shortLabel": "direct interaction",
                 "fullName": "direct interaction"
                 },
              "xref": {
                  "primaryRef": {
                     "db": "psi-mi",
                     "dbAc": "MI:0488",
                     "id": "MI:0407",
                     "refType": "identity",
                     "refTypeAc": "MI:0356"
                     } 
                 }
             }           
            
    
    def __init__( self, entry, n, interaction=None ): 
        self._entry = entry
        if n is not None:
            self._interaction = entry[ "interaction" ][ n ]
        else:
            self._interaction = interaction
            
        self._source = entry[ "source" ]
        self._experiment =  self._interaction["experiment"]
        self._participant = self._interaction["participant"]

        self._names = self._interaction["names"] if "names" in self._interaction else None 
        self._xref = self._interaction["xref"] if "xref" in self._interaction else None
        self._attribute = self._interaction["attribute"] if "attribute" in self._interaction else None

            
    def expand(self, mode="spoke"):
        """Returns a list of binary interactions generated by expansion
        of multi-molecular interaction according to spoke or marix model.""" 
        
        ret = []
      
        if len(self._participant) <=2:
                return ret
      
        bait = []
        prey = []
        part = []
        
        assType = False
        phyType = False
        dirType = False
        
        if "interactionType" in self._interaction:
            for it in self._interaction["interactionType"]:
                if it["names"]["shortLabel"]=="association":
                    assType = True
                if it["names"]["shortLabel"]=="physical association":
                    phyType = True
                if it["names"]["shortLabel"]=="direct interaction":
                    dirType = True   
                    
        for p in self._participant:
            skip = False
            if "experimentalRole" in p:
                for r in p["experimentalRole"]:
                    if r["names"]["shortLabel"] == "bait":
                        bait.append(p)
                    if r["names"]["shortLabel"] == "prey":
                        prey.append(p)
                    if r["names"]["shortLabel"] == "ancillary":
                        skip = True
            else:
                skip = True 
            if not skip:            
                part.append(p)            
                
        if assType and mode == "spoke":
            for p1 in bait:
                for p2 in prey:
                                      
                    binary = {}
                    for k in self._interaction.keys():
                        if k not in ["participant","interactionType"]:
                            binary[k] = self._interaction[k]
                  
                    itype = deepcopy( self.physical )
                    binary.setdefault("interactionType",[]).append( itype )
                    bprt =  binary.setdefault("participant",[])
                    bprt.append(p1)
                    bprt.append(p2)
                    
                    ret.append( Interaction( self._entry, None, binary ) )
                    
        if (phyType or dirType) and mode == "matrix":           
            for i in range(0,len(part)):
                for j in range(i+1,len(part)):
                    binary = {}
                        
                    for k in self._interaction.keys():
                        if k not in ["participant","interactionType"]:
                            binary[k] = self._interaction[k]

                    if  dirType:                
                        itype = deepcopy( self.direct )
                    else:
                        itype = deepcopy( self.physical )
                    binary.setdefault("interactionType",[]).append( itype )
                    bprt =  binary.setdefault("participant",[])
                    bprt.append(part[i])
                    bprt.append(part[j])
                    
                    ret.append( Interaction( self._entry, None, binary ) )
                    
        return ret
        
    @property
    def imexid(self):
        if "imexId" in self._interaction:
            return self._interaction["imexId"]
        return None
    
    @property
    def participants(self):
        ret = []        
        for i in self._participant: 
            ret.append( mif.Participant( i,  self._interaction ) )        
        return ret
        
    @property 
    def participantCount(self): 
        return len( self._participant )

    def getParticipant( self, n = 0 ):
        if n < len( self._participant ):            
            return mif.Participant( self._participant[ n ] ) 
        else:    
            return None
        
    @property
    def type(self):
        if "interactionType" in self._interaction:
            if isinstance(self._interaction["interactionType"], list):            
                return mif.CvTerm(self._interaction[ "interactionType" ][0])
            if isinstance(self._interaction["interactionType"], dict):            
                return mif.CvTerm(self._interaction[ "interactionType" ])
        return None
    
    @property
    def types(self):
        if "interactionType" in self._interaction:
            if isinstance(self._interaction["interactionType"], list):
                ret = []
                for t in self._interaction["interactionType"]:
                    ret.append( mif.CvTerm(t) )
                return ret
        return None

    @property
    def source(self):
        return mif.Source( self._source )

    @property
    def experiments(self):
        ret = []
        for i in self._experiment:
            ret.append( mif.Experiment( i ) )
        return ret
        
    @property
    def availability(self):
        if "availability" in self._interaction:
            return self._interaction["availability"]["value"]
        return None
    
    @property 
    def experimentCount(self): 
        return len( self._experiment )
      
    @property
    def experiment(self):
        if len( self._experiment ) == 1:
            return mif.Experiment( self._experiment[0] )
        else:
            return None
    
    def getExperiment( self, n = 0 ):
        if n < len( self._experiment ):            
            return mif.Experiment( self._experiment[ n ] ) 
        else:    
            return None
                
    @property
    def attribs(self):    
        if self._attribute is None:
            return None
        return mif.Attribs( self._attribute )

    @property
    def params(self):    
        if self._param is None:
            return None
        return mif.Params( self._param )
       
    @property
    def confidence(self):
        if "confidence" in  self._interaction:
            return bool(self._interaction["confidence"])
    
    @property
    def modelled(self):
        if "modelled" in  self._interaction:
            return bool(self._interaction["modelled"])
        return False

    @property
    def intramolecular(self):
        if "intramolecular" in  self._interaction:
            return bool(self._interaction["intramolecular"])
        return False
    
    @property
    def negative(self):
        if "negative" in  self._interaction:
            return bool(self._interaction["negative"])
        return False
    

class AbstInteraction(mif.Names, mif.Xref):
    """MIF AbstractInteraction representation."""
    def __init__( self, entry, n ):    
        self._entry = entry
        self._interaction = entry[ "abstractInteraction" ][ n ]
        self._source = entry[ "source" ]       
        self._participant = self._interaction["participant"]

        self._names = self._interaction["names"] if "names" in self._interaction else None
        self._xref = self._interaction["xref"] if "xref" in self._interaction else None
        self._attribute = self._interaction["attribute"] if "attribute" in self._interaction else None
       
    @property
    def participants(self):
        ret = []        
        for i in self._participant: 
            ret.append( mif.Participant( i,  self._interaction ) )        
        return ret
        
    @property 
    def participantCount(self): 
        return len( self._participant )

    def getParticipant( self, n = 0 ):
        if n < len( self._participant ):            
            return mif.Participant( self._participant[ n ] ) 
        else:    
            return None
        
    @property
    def type(self):
        if "interactionType" in self._interaction:            
            if isinstance(self._interaction["interactionType"], dict):            
                return mif.CvTerm(self._interaction[ "interactionType" ])
        return None

    @property
    def interactorType(self):
        if "interactorType" in self._interaction:            
            if isinstance(self._interaction["interactorType"], dict):            
                return mif.CvTerm(self._interaction[ "interactorType" ])
        return None
    
    @property
    def evidenceType(self):
        if "evidenceType" in self._interaction:            
            if isinstance(self._interaction["evidenceType"], dict):            
                return mif.CvTerm(self._interaction[ "evidenceType" ])
        return None

    @property
    def organism(self):
        if "organism" in self._interaction:                                  
            return mif.Host( self._interaction["organism"] )
        return None 

    @property
    def source(self):
        return mif.Source( self._source )

    @property
    def attribs(self):    
        if self._attribute is not None:
            return mif.Attribs( self._attribute )
        return None
    
    @property
    def params(self):    
        if self._param is None:
            return None
        return mif.Params( self._param )
       







        
        
        
        

