'''
Created on 23 oct. 2012

@author: coissac
'''

from orgasm.tango import tango, \
                         matchtoseed, \
                         cutLowCoverage, \
                         scaffold, \
                         coverageEstimate, \
                         fillGaps, \
                         path2fasta, pairEndedConnected
from orgasm.indexer import Index
from orgasm.backtranslate.fasta import fasta
from orgasm.assembler import Assembler
from orgasm.samples import protChloroArabidopsis
import sys
import pickle

#p = fasta('../../samples/arabidopsis.chloro.prot.fasta')

prefix="Coespi"
gp = ['rbcL','matK','ndhA',
      'rpoA','atpA','atpH',
      'rpoA','atpB','psbN',
      'psbT','psbB','psbD',
      'psbE','psbF','psbA',
      'psbC','psbM','psbI',
      'psbH','psbK','psbJ',
      'psbL','psbZ']

p2=dict(x for x in protChloroArabidopsis.items() if x[0] in gp)

r = Index('../../samples/'+prefix)
m = r.lookForSeeds(p2)
pickle.dump(m,open(prefix+'.match.omx',"w"))
m = pickle.load(open(prefix+'.match.omx'))

common    = set(p2.keys()) & set(m.keys())
pcoverage = [len(m[i]) * r.getReadSize()  / len(p2[i]) / 3 for i in common]
pcoverage.sort()

print >>sys.stderr,pcoverage

coverage=pcoverage[len(pcoverage)/2]

s = matchtoseed(m,r)
asm = Assembler(r)
a = tango(asm,s,mincov=1,minread=10,minoverlap=40,maxjump=0,cycle=1)

asm.cleanDeadBranches(maxlength=10)

cutLowCoverage(asm,10,terminal=False)

score,length,coverage = coverageEstimate(asm)

cutLowCoverage(asm,int(coverage/3),terminal=False)

while fillGaps(asm,back=300,minread=10,maxjump=0,minoverlap=40,cmincov=0,gmincov=int(coverage/2)) > 0:
    score,length,coverage = coverageEstimate(asm)
    print >>sys.stderr,"coverage estimated : %d based on %d bp" %(length,coverage)

cg = asm.compactAssembling()
scaffold(asm,cg,minlink=4,back=400,addConnectedLink=False)

print >>open(prefix+'.clean.gml','w'),cg.gml()

fp = [4,6,-1,-2,-3,-6]
cg = asm.compactAssembling()
fa = path2fasta(asm,cg,fp,identifier=prefix,back=400,minlink=5)
print >>open(prefix+'.chloro.fasta','w'),fa


#################### cow mitochondrions ##################


from orgasm.tango import tango, \
                         matchtoseed, \
                         cutLowCoverage, \
                         scaffold, \
                         coverageEstimate, \
                         fillGaps, \
                         path2fasta
from orgasm.indexer import Index
from orgasm.backtranslate.fasta import fasta
from orgasm.assembler import Assembler
from orgasm.samples import protCox1Capra
import sys
import pickle
import glob


cows = [i.split('/')[-1].split('.')[0] for i in glob.glob("*.ogx")]

for prefix in cows:
    try:
        x = open(prefix+'.mito.fasta')
        done=True
    except IOError:
        done=False
    if not done:
        r = Index(prefix)
        m = r.lookForSeeds(protCox1Capra)
        pickle.dump(m,open(prefix+'.match.omx',"w"))
        s = matchtoseed(m,r)
        asm = Assembler(r)
        a = tango(asm,s,mincov=1,minread=4,minoverlap=27,maxjump=0,cycle=1)
        asm.cleanDeadBranches(maxlength=10)
        score,length,coverage = coverageEstimate(asm)    
        cutLowCoverage(asm,int(coverage/3),terminal=False)
        print >>sys.stderr
        print >>sys.stderr,"coverage estimated : %d based on %d bp" %(coverage,length)
        while fillGaps(asm,back=300,minread=30,maxjump=0,minoverlap=60,cmincov=0,gmincov=int(coverage/4)):
            score,length,coverage = coverageEstimate(asm)
            print >>sys.stderr,"coverage estimated : %d based on %d bp" %(coverage,length)
        cg = asm.compactAssembling()
        #scaffold(asm,cg,minlink=4,back=400,addConnectedLink=False)
        stems = [(i['length'],i['stemid']) for i in (cg.getEdgeAttr(*j) for j in cg.edgeIterator())]
        stems.sort(key=lambda i:i[0],reverse=True)
        fa = path2fasta(asm,cg,[stems[0][1]],identifier=prefix,back=400,minlink=5)
        print >>open(prefix+'.mito.fasta','w'),fa
        scaffold(asm,cg,minlink=4,back=400,addConnectedLink=False)
        print >>open(prefix+'.mito.gml','w'),cg.gml()
    else:
        print >>sys.stderr
        print >>sys.stderr,"%s already assembled" % prefix
    


for prefix in cows:
    try:
        x = open(prefix+'.mito.fasta')
        done=True
    except:
        done=False
    if not done:
        r = Index(prefix)
        m = r.lookForSeeds(protCox1Capra)
        s = matchtoseed(m,r)
        asm = Assembler(r)
        a = tango(asm,s,mincov=1,minread=10,minoverlap=50,maxjump=0,cycle=1)
        asm.cleanDeadBranches(maxlength=10)
        score,length,coverage = coverageEstimate(asm)    
        cutLowCoverage(asm,int(coverage/3),terminal=False)
        print >>sys.stderr
        print >>sys.stderr,"coverage estimated : %d based on %d bp" %(length,coverage)
        while fillGaps(asm,back=700,minread=10,maxjump=0,minoverlap=50,cmincov=0,gmincov=int(coverage/4)) > 0:
            score,length,coverage = coverageEstimate(asm)
            print >>sys.stderr,"coverage estimated : %d based on %d bp" %(length,coverage)
        cg = asm.compactAssembling()
        #scaffold(asm,cg,minlink=4,back=400,addConnectedLink=False)
        stems = [(i['length'],i['stemid']) for i in (cg.getEdgeAttr(*j) for j in cg.edgeIterator())]
        stems.sort(key=lambda i:i[0],reverse=True)
        fa = path2fasta(asm,cg,[stems[0][1]],identifier=prefix,back=400,minlink=5)
        print >>open(prefix+'.mito.fasta','w'),fa
        scaffold(asm,cg,minlink=4,back=400,addConnectedLink=False)
        print >>open(prefix+'.mito.gml','w'),cg.gml()
    else:
        print >>sys.stderr
        print >>sys.stderr,"%s already assembled" % prefix
        
        
        
from orgasm.tango import tango, \
                         matchtoseed, \
                         cutLowCoverage, \
                         scaffold, \
                         coverageEstimate, \
                         fillGaps, \
                         path2fasta
from orgasm.indexer import Index
from orgasm.backtranslate.fasta import fasta
from orgasm.assembler import Assembler
from orgasm.samples import protCox1Capra
import sys
import pickle
import glob

prefix="sartidia"
r = Index(prefix)
m = pickle.load(open(prefix+'.match.omx'))
s = matchtoseed(m,r)
asm = Assembler(r)
a = tango(asm,s,mincov=1,minread=10,minoverlap=50,maxjump=0,cycle=1)
asm.cleanDeadBranches(maxlength=10)
score,length,coverage = coverageEstimate(asm)    
cutLowCoverage(asm,int(coverage/3),terminal=False)
print >>sys.stderr
print >>sys.stderr,"coverage estimated : %d based on %d bp" %(coverage,length)
while fillGaps(asm,back=700,minread=10,maxjump=0,minoverlap=50,cmincov=0,gmincov=int(coverage/4)) > 0:
    score,length,coverage = coverageEstimate(asm)
    print >>sys.stderr,"coverage estimated : %d based on %d bp" %(coverage,length)
cg = asm.compactAssembling()

##################################################################################
#
#   LA DESSOUS C'EST MON BORDEL
#
##################################################################################
from orgasm.tango import tango, \
                         matchtoseed, \
                         cutLowCoverage, \
                         scaffold, \
                         coverageEstimate, \
                         fillGaps, \
                         path2fasta, \
                         unfoldAssembling, \
                         cutSNPs, \
                         selectGoodComponent, \
                         estimateDeadBrancheLength, pairEndedConstraints,\
    estimateFragmentLength
from orgasm.indexer import Index
from orgasm.backtranslate.fasta import fasta
from orgasm.assembler import Assembler
#from orgasm.multialign import multiAlignReads, \
#                              consensus                              
import sys
import pickle    

def estimateMinRead(index,minoverlap,coverage):
    MINREAD=10
    MINREADCOR=6
    MINOVERLAP=30
    minread =  (index.getReadSize() - minoverlap) * coverage / index.getReadSize()  / MINREADCOR
    if minread < MINREAD:
        minoverlap = index.getReadSize() - (MINREAD * MINREADCOR * index.getReadSize() / coverage)
        minread = MINREAD
    if  minoverlap< MINOVERLAP:
        minread =  (index.getReadSize() - MINOVERLAP) * coverage / index.getReadSize()  / MINREADCOR
        minoverlap = MINOVERLAP
    return minread,minoverlap


import orgasm.samples
import argparse
parser = argparse.ArgumentParser(description='Assembly program dedicated to organel genome reconstruction.')
args = parser.parse_args()

prefix="RSZAXPI001337-84:Valeriana_montana"
prefix="toto98"
r = Index(prefix)
p=orgasm.samples.protChloroArabidopsis
p=orgasm.samples.protMitoCapra
x = pickle.load(open(prefix+'.match.omx'))
common    = set(p.keys()) & set(x.keys())
pcoverage = [len(x[i]) * r.getReadSize()  / len(p[i]) / 3 for i in common]
coverage=max(pcoverage)

args.minoverlap=40
args.lowcomplexity=False
args.mincov=1
args.snp=True
args.minread=None
args.outputFilename="%s.test" % prefix
args.back=None
minread = estimateMinRead(r,args.minoverlap,coverage)
asm = Assembler(r)
s = matchtoseed(x,r)

minread,minoverlap = estimateMinRead(r,args.minoverlap,coverage)
print >>sys.stderr,"\nestimated coverage  : %d based on protein match (minread: %d)" % (coverage,minread)

a = tango(asm,s,mincov=args.mincov,
                minread=minread,
                minoverlap=minoverlap,
                lowfilter=not args.lowcomplexity,
                maxjump=0, 
                cycle=1,
                nodeLimit=10000)

# Clean small unsuccessful extensions
asm.cleanDeadBranches(maxlength=10)

# and too low covered assembling
cutLowCoverage(asm,int(coverage/4),terminal=True)
smallbranches = estimateDeadBrancheLength(asm)
print >>sys.stderr,"     Dead branche length setup to : %d bp" % smallbranches
asm.cleanDeadBranches(maxlength=smallbranches)
score,length,coverage = coverageEstimate(asm)    
minread,minoverlap = estimateMinRead(r,args.minoverlap,coverage)
print >>sys.stderr,"coverage estimated : %d based on %d bp (minread: %d)" %(coverage,length,minread)
s.extend(matchtoseed(x,r))
# Run the first assembling pass
a = tango(asm,s,mincov=args.mincov,
                minread=minread,
                minoverlap=minoverlap,
                lowfilter=not args.lowcomplexity,
                maxjump=0, 
                cycle=1)

# Clean small unsuccessful extensions
asm.cleanDeadBranches(maxlength=10)

# and too low covered assembling
cutLowCoverage(asm,int(coverage/4),terminal=True)
smallbranches = estimateDeadBrancheLength(asm)
print >>sys.stderr,"     Dead branche length setup to : %d bp" % smallbranches
asm.cleanDeadBranches(maxlength=smallbranches)


# reestimate coverage
score,length,coverage = coverageEstimate(asm)    
print >>sys.stderr,"coverage estimated : %d based on %d bp (minread: %d)" %(coverage,length,minread)

meanlength,sdlength = estimateFragmentLength(asm)
args.back = int(meanlength + 4 * sdlength)
print >>sys.stderr,"Fragment length estimated : %f pb (sd: %f)" % (meanlength,sdlength)
cg = asm.compactAssembling(verbose=False)
scaffold(asm,cg,minlink=5,back=args.back,addConnectedLink=False)
print >>open(args.outputFilename+'.intermediate.gml','w'),cg.gml()




constraints

def selectGoodComponent(cg):
    cc = list(cg.connectedComponentIterator())
    cclength = [[cg.getEdgeAttr(*i)['length'] 
                    for i in cg.edgeIterator(nodePredicate=lambda n: n in cc1) 
                    if 'stemid' in cg.getEdgeAttr(*i)
                ] for cc1 in cc]
                
    ccmlength=[sum(i)/float(len(i)) for i in cclength]
    
    m = mode(ccmlength)
     
    gcc = [c for c,mcc in map(None,cc,ccmlength) if mcc > m * 2]
    
    return gcc
 
 
        while fillGaps(asm,back=300,minread=30,maxjump=0,minoverlap=80,cmincov=0,gmincov=100,minlink=5):
            score,length,coverage = coverageEstimate(asm)
            print >>sys.stderr,"coverage estimated : %d based on %d bp" %(coverage,length)

    
[[(3, 14, 7), (3, 15, 82), (4, 14, 86), (4, 15, 8)],                #> ok
 [(-13, 8, 13), (-13, 9, 8), (-12, 8, 0), (-12, 9, 0)],
 [(-10, -13, 7), (-10, -21, 109), (-11, -13, 61), (-11, -21, 3)],   #> ok
 [(23, -9, 93), (23, -8, 15), (24, -9, 8), (24, -8, 99)],           #> ok
 [(25, -10, 43), (25, -11, 6), (26, -10, 6), (26, -11, 47)],        #> ok
 [(13, 10, 7), (13, 11, 61), (21, 10, 109), (21, 11, 3)],           #> ok
 [(-9, 12, 0), (-9, 13, 8), (-8, 12, 0), (-8, 13, 13)],
 [(-25, 3, 8), (-25, 4, 11), (-26, 3, 11), (-26, 4, 11)],
 [(14, 23, 5), (14, 24, 149), (15, 23, 125), (15, 24, 2)],          #> ok
 [(10, -25, 43), (10, -26, 6), (11, -25, 6), (11, -26, 47)],        #> ok
 [(8, -23, 15), (8, -24, 99), (9, -23, 93), (9, -24, 8)],           #> ok
 [(-23, -14, 5), (-23, -15, 125), (-24, -14, 149), (-24, -15, 2)],  #> ok
 [(-14, -3, 7), (-14, -4, 86), (-15, -3, 82), (-15, -4, 8)],        #> ok
 [(-3, 25, 8), (-3, 26, 11), (-4, 25, 11), (-4, 26, 11)]]   

def phaseSNP(asm,cg,threshold=5.):
    
    def nextStem(s):
        ns = cg.getEdgeAttr(*cg.edgeIterator(edgePredicate=lambda c: 
                                    c[0]==cg.edgeIterator(edgePredicate=lambda e:
                                                          cg.getEdgeAttr(*e)['stemid']==s
                                                          ).next()[1]
                                    ).next()
                  )['stemid']
        return ns

    
    fork = [cg.edgeIterator(edgePredicate=lambda e: e[1]==i).next() for i in cg 
            if len(list(cg.edgeIterator(edgePredicate=lambda e: e[0]==i))) == 2  
            and len(list(cg.edgeIterator(edgePredicate=lambda e: e[1]==i))) == 1] 
    bifork = [(list(cg.getEdgeAttr(*x)['stemid'] 
                    for x in cg.edgeIterator(edgePredicate=lambda e: e[1]==i[0])),
               list(cg.getEdgeAttr(*x)['stemid'] 
                    for x in cg.edgeIterator(edgePredicate=lambda e: e[0]==i[1]))) 
              for i in fork 
              if len(list(cg.edgeIterator(edgePredicate=lambda e: e[1]==i[0]))) == 2 ]
    
    links = [[((i[0][0],i[1][0]),
               (i[0][1],i[1][1])),
              ((i[0][1],i[1][0]),
               (i[0][0],i[1][1])),
              float(pairEndedConnected(asm,cg,i[0][0],i[1][0],500)+
                    pairEndedConnected(asm,cg,i[0][1],i[1][1],500))/
              float(pairEndedConnected(asm,cg,i[0][1],i[1][0],500)+
                    pairEndedConnected(asm,cg,i[0][0],i[1][1],500))] 
             for i in bifork]
    
    phasing = [(i[0],i[2]) if i[2] >= threshold else (i[1],1/i[2]) 
               for i in links 
               if  i[2] >= threshold or  i[2] <= 1/threshold
              ]
    
    constraints=dict([(j[0],j) 
                 for k in [((i[0][0][0],
                              nextStem(i[0][0][0]),
                              i[0][0][1]),
                            (i[0][1][0],
                              nextStem(i[0][1][0]),
                              i[0][1][1])) 
                           for i in phasing] 
                 for j in k])
    
    return constraints
    
    
x={'rpl14': [(2573766, 18, 2, 1, 0.0),
  (-3397517, 16, 3, -3, 0.0),
  (-9351610, 16, 2, -2, 0.0),
  (11206729, 16, 2, 1, 0.0),
  (-13075047, 16, 2, -2, 0.0),
  (14685869, 18, 2, 0, 0.0),
  (14999159, 17, 2, 0, 0.0)],
 'rpl16': [(-909221, 22, 3, -2, 0.0),
  (2094043, 17, 2, 2, 0.0),
  (-3759908, 19, 2, -2, 0.0),
  (-5946274, 17, 3, -3, 0.0),
  (8126977, 16, 2, 1, 0.0),
  (9588507, 21, 2, 1, 0.0),
  (10738816, 19, 3, 2, 0.0)],
 'rpl2': [(236866, 16, 2, 0, 0.0),
  (1928532, 16, 2, 0, 0.0),
  (5706417, 16, 10, 2, 0.0),
  (5782045, 16, 3, 1, 0.0),
  (8196126, 19, 2, 2, 0.0),
  (8244020, 19, 3, 2, 0.0),
  (-8296859, 19, 2, -2, 0.0),
  (-8298962, 18, 3, -2, 0.0),
  (-8535070, 19, 4, -3, 0.0),
  (8626832, 18, 3, 2, 0.0),
  (-9342483, 16, 2, -1, 0.0),
  (-9456051, 17, 2, -3, 0.0),
  (11173582, 16, 5, 2, 0.0),
  (-13132160, 19, 2, -2, 0.0),
  (-16455865, 17, 3, -3, 0.0),
  (16919446, 17, 2, 2, 0.0)],
 'rps12': [(862750, 18, 2, 1, 0.0),
  (-2207684, 17, 3, -2, 0.0),
  (-2745111, 18, 2, -1, 0.0),
  (4889605, 18, 2, 2, 0.0),
  (5064189, 16, 2, 2, 0.0),
  (5211803, 18, 2, 0, 0.0),
  (5254975, 17, 2, 2, 0.0),
  (-7094217, 20, 2, -3, 0.0),
  (7402069, 22, 2, 2, 0.09981524629190291),
  (-7464726, 17, 2, -3, 0.0),
  (-7881444, 17, 2, -3, 0.0),
  (7976243, 16, 3, 2, 0.0),
  (8431545, 19, 2, 1, 0.0),
  (8436186, 22, 4, 1, 0.09981524629190291),
  (10449608, 16, 5, 1, 0.0),
  (10524565, 17, 2, 0, 0.0),
  (-13424151, 18, 2, -2, 0.0),
  (-13495209, 16, 3, -1, 0.0),
  (15071790, 16, 2, 1, 0.0)],
 'rps2': [(62453, 16, 2, 2, 0.0),
  (160869, 16, 2, 1, 0.0),
  (412778, 18, 3, 1, 0.0),
  (-1151828, 18, 3, -1, 0.0),
  (1442154, 18, 4, 1, 0.0),
  (-2871339, 18, 3, -2, 0.0),
  (2918339, 18, 5, 2, 0.0),
  (3042383, 17, 4, 1, 0.0),
  (4342413, 18, 2, 0, 0.0),
  (-10087325, 16, 2, -2, 0.0),
  (-11357851, 18, 3, -2, 0.0),
  (11941870, 18, 4, 2, 0.0),
  (-13024299, 18, 2, -2, 0.0),
  (-13786786, 18, 4, -1, 0.0),
  (-14048126, 18, 2, -3, 0.0),
  (15505340, 18, 2, 2, 0.0),
  (16782797, 18, 2, 2, 0.0)],
 'rps4': [(564720, 17, 2, 1, 0.0),
  (-1176979, 19, 2, -1, 0.0),
  (-2960382, 17, 2, -2, 0.0),
  (7102274, 16, 2, 1, 0.0),
  (-8195121, 18, 2, -2, 0.0),
  (8371520, 16, 3, 1, 0.0),
  (-8517970, 17, 2, -2, 0.0),
  (-9898537, 17, 3, -3, 0.0),
  (11426723, 18, 3, 1, 0.0),
  (13103212, 19, 2, 2, 0.0),
  (-14729273, 16, 2, -2, 0.0)]}


def testIndex(r):
    from obitools import NucSequence
    from obitools.utils import progressBar as pb
    nbseq = len(r)
    rsize =  r.getReadSize()
    
    pb(1,nbseq,1)
    
    for i in xrange(1,nbseq+1):
        cseq = str(NucSequence('xxx',r.getRead(i,0,rsize)).complement()).upper()
        rseq = r.getRead(-i,0,rsize)
        pb(i,nbseq)
        if cseq!=rseq:
            print "problem with read : %d" %i
            print "   %s",cseq 
            print "   %s",rseq
            print
            
s=dict((r.getIds(y[0])[0],('rbcL',)) for y in x['rbcL'])
    
                  
    
     

def distPaired(x,p,index):
    dist = []
    lindex = len(index)
    i = p[x]
    pp = [index.getIds(index.getPairedRead(j))[0] for j in index.getIds(i)[2] if j <=lindex and j > 0]
    
    for j in pp:
        try:
            p1=p.index(j,x)
        except ValueError:
            p1=-1
            
        if p1 < 0:
            try:
                p1=p.index(-j,x)
            except ValueError:
                pass
        if p1 > 0:
            p1 = p1 - x   
            dist.append(p1) 
            
    return dist

p = cg.getEdgeAttr(27099517, 100005265, 0)['path']
d = reduce(lambda a,b:a+b,(distPaired(i,p,r) for i in range(len(p))))


def cutParallel(self,mincov):
    index = self.index
    stems = [x for x in self.stemIterator(alllink=False)]
    readSize = index.getReadSize()
    stemparallel ={}
    for first, last, lseq, sequence, path in stems:
        weight = sum(self.graph[x]['coverage'] for x in path if x in self.graph and 'coverage' in self.graph[x]) / float(len(path)) * readSize
        s = (first, last)
        ls = stemparallel.get(s,[])
        ls.append((first, last, lseq, sequence, path,weight))
        stemparallel[s]=ls
    spis = stemparallel.keys()
    for spi in spis:
        if len(stemparallel[spi]==1):
            del stemparallel[spi]
    return stemparallel
    
E4 : 11m18.971s -> Full Circle
E3 : 10m36.784s -> Not sequence (Mito)



def fillGaps(self,minlink=5,
                  back=200,
                  kmer=12,
                  smin=40,
                  delta=0,
                  cmincov=5,
                  minread=20,
                  minratio=0.1, 
                  emincov=1,
                  maxlength=None,
                  gmincov=1,
                  minoverlap=60,
                  lowfilter=True,
                  maxjump=0,
                  snp=False):
    '''
    
    :param minlink:
    :param back:
    :param kmer:
    :param smin:
    :param delta:
    :param cmincov:
    :param minread:
    :param minratio:
    :param emincov:
    :param maxlength:
    :param gmincov:
    :param minoverlap:
    :param lowfilter:
    :param maxjump:
    :param snp: If set to True (default value is False) erase SNP variation
                by conserving the most abundant version
    '''
    def isInitial(n):
        return len(list(assgraph.parentIterator(n[0],edgePredicate=lambda e: 'stemid' in assgraph.getEdgeAttr(*e))))==0 
    def isTerminal(n):
        return len(list(assgraph.neighbourIterator(n[1],edgePredicate=lambda e: 'stemid' in assgraph.getEdgeAttr(*e))))==0

    assgraph = self.compactAssembling(verbose=False)
    
    index = self.index
    
    ei = [i for i in assgraph.edgeIterator(edgePredicate=isInitial)]
    et = [i for i in assgraph.edgeIterator(edgePredicate=isTerminal)]
    
    eiid = [assgraph.getEdgeAttr(*i)['stemid'] for i in ei]
    etid = [assgraph.getEdgeAttr(*i)['stemid'] for i in et]

    exi = [getPairedRead(self,assgraph,i,back,end=False) for i in eiid]
    ext = [getPairedRead(self,assgraph,i,back,end=True) for i in etid]
    
    nei = len(ei)
    net = len(et)
    s=[]
    maxcycle=max(self.graph.getNodeAttr(i)['cycle'] for i in self.graph)
    lassemb = len(self)
    cycle = maxcycle
    linked=set()
    
    for e1 in xrange(net):
        free=True
        for e2 in xrange(nei):
            connected = et[e1][1]==ei[e2][0]
            if not connected:
                linkedby  = pairEndedConnected(self,assgraph,etid[e1],eiid[e2],back)
            
                if linkedby >= minlink and etid[e1] <= eiid[e2]:
                    free=False
                    if (etid[e1],eiid[e2]) not in linked:
                        linked.add((-eiid[e2],-etid[e1]))
                        print >>sys.stderr,"\n\nLinking Stems %d -> %d" % (etid[e1],eiid[e2])
                        ex = ext[e1] | exi[e2]
                        ingraph = sum(i in self.graph for i in ex)
                        nreads = len(ex)
                        if ingraph < nreads:
                            print >>sys.stderr,"--> %d | %d = %d reads to align" % (len(ext[e1]),len(exi[e2]),nreads)
                            if nreads > 10:
                                ali= multiAlignReads(ex,index,kmer,smin,delta)
                                print >>sys.stderr 
            
                                goodali = [i for i in ali if len(i) >= nreads/4]
                                print >>sys.stderr,"--> %d consensus to add" % len(goodali)
                                for a in goodali:
                                    cycle+=1
                                    c = consensus(a,index,cmincov)
                                    s = insertFragment(self,c,cycle=cycle)
                                    print >>sys.stderr,"     %d bp (%d reads) added on cycle %d" % (len(c),len(s),cycle)
                                    a = tango(self,s,mincov=emincov,
                                                     minread=minread,
                                                     minoverlap=minoverlap,
                                                     maxjump=maxjump,cycle=cycle)
                                    print >>sys.stderr 
            else:
                free=False
        if free:
            print >>sys.stderr,"\n\nExtending Stems %d" % (etid[e1])
            ex = ext[e1]
            nreads = len(ex)
            print >>sys.stderr,"--> %d reads to align" % (nreads)
            if nreads > 10:
                ali= multiAlignReads(ex,index,kmer,smin,delta)
                print >>sys.stderr 
                goodali = [i for i in ali if len(i) >= nreads/4]
                print >>sys.stderr,"--> %d consensus to add" % len(goodali)
                for a in goodali:
                    c = consensus(a,index,cmincov)
                    if c:
                        cycle+=1
                        s = insertFragment(self,c,cycle=cycle)
                        print >>sys.stderr,"     %d bp (%d reads) added on cycle %d" % (len(c),len(s),cycle)
                        a = tango(self,s,mincov=emincov,
                                         minread=minread,
                                         minoverlap=minoverlap,
                                         maxjump=maxjump,cycle=cycle)
                    print >>sys.stderr 

    self.cleanDeadBranches(maxlength=10)
    cutLowCoverage(self,gmincov,terminal=True)
    cutLowCoverage(self,int(gmincov/3),terminal=False)   
    
    if maxlength is not None:
        smallbranches = maxlength
    else:
        smallbranches = estimateDeadBrancheLength(self)
        print >>sys.stderr,"     Dead branche length setup to : %d bp" % smallbranches
    self.cleanDeadBranches(maxlength=smallbranches)

    if snp:
        cutSNPs(self)

    newnodes = len(self) - lassemb
    
    print >>sys.stderr
    print >>sys.stderr,"#######################################################"
    print >>sys.stderr,"#"
    print >>sys.stderr,"# Added : %d bp (total=%d bp)" % (newnodes/2,len(self)/2)
    print >>sys.stderr,"#"
    print >>sys.stderr,"#######################################################"
    print >>sys.stderr
    
    return newnodes

def getSeq(cg,stemid):
    s = cg.edgeIterator(edgePredicate=lambda e:'stemid' in cg.getEdgeAttr(*e) 
                                                 and cg.getEdgeAttr(*e)['stemid']==stemid).next()
    return cg.getEdgeAttr(*s)['sequence']

def normalizeId(r,id):
    aid,nid,ids=r.getIds(id)
    if id not in ids:
        aid=-aid
    return aid

from orgasm.utils.dna import reverseComplement

pl = {}
stems = [cg.getEdgeAttr(*e)['stemid'] for e in cg.edgeIterator()]

for m in stems:
    for n in stems:
        ba = set(reduce(lambda k,l:k+l,[r.normalizedPairedEndsReads(j)[1] for j in reduce(lambda a,b:a+b,[[i[1][0] for i in r.getExtensions(getSeq(cg,m)[-400:][x:x+20]).values()] for x in range(380)])]))
        da = set(reduce(lambda a,b:a+b,[[normalizeId(r,-i[1][0]) for i in r.getExtensions(reverseComplement(getSeq(cg,n)[0:400][x:x+20])).values()] for x in range(380)]))
        cp = len(ba & da)
        if cp:         
            pl[(m,n)]=cp
        


def matchHash(h1,h2, shift):
    '''
    Compare two hash tables as build by the hashSeq function.

    :param h1: the first hash table
    :type h1: a dict instance indexed by bytes and containing list of int
    :param h2: the second hash table
    :type h2: a dict instance indexed by bytes and containing list of int
    :param delta: delta around the main diagonal considered to compute the score
    :type delta: int
    :return: the shift corresponding to the main diagonal and the corresponding score
    :rtype: a tuple of two int 
    '''
    
    
    k1 = set(h1.keys())
    k2 = set(h2.keys())
    kc = k1 & k2
    stat = []
    for k in kc:
        p1 = h1[k]
        p2 = h2[k]
        for i in p1:
            for j in p2:
                if i-j == shift:
                    stat.append((i,j))
                    
    stat.sort(key=lambda x: x[0])
    
    segments=[]
    p = iter(stat)
    
    try:
        p1=p.next()
        p2=p.next()
        while(1):
            b1 = p1
            while p2[0] - p1[0] ==1 and p2[1] - p1[1] ==1:
                p1=p2
                p2=p.next()
            segments.append(((b1[0],p1[0]),(b1[1],p1[1])))
            p1=p2
            p2=p.next()
            
    except StopIteration:
        pass
    return segments

def rotateIR(seq,kmer=12):
    cseq = reverseComplement(seq)
    hs = hashSeq(seq,kmer=kmer)
    hsc= hashSeq(cseq+cseq,kmer=kmer)
    
    delta,score = cmpHash(hs,hsc)
    print delta,score
    segments = matchHash(hs,hsc,delta)
    print segments
    
    IR1 = segments[-1][0]
        
    rseq = seq[IR1[0]:]+ seq[:IR1[0]]
       
    IR1 =  (0,IR1[1]+11-IR1[0])
    IR1s = rseq[IR1[0]:(IR1[1]+1)]
    IR1sc= reverseComplement(IR1s)
    p2 = rseq.index(IR1sc)
    IR2 = (p2,p2+IR1[1])
    
    return (rseq,IR1,IR2)


e = [j if abs(j[0]) < abs(j[1]) 
       else  (-j[1],-j[0])
     for j in [(cg.getEdgeAttr(*i)['stemid'],cg.getEdgeAttr(i[1],i[0],i[2])['stemid']) for i in cg.edgeIterator(edgePredicate=lambda j: cg.hasEdge(j[1],j[0]))]


def ministatSimpleConstraints(self,cg):
    e = [i for i in cg.edgeIterator(edgePredicate=lambda j: j[0]==j[1])]
    constraints = {}
    for start,end,index in e:
        input = list(cg.edgeIterator(edgePredicate=lambda i: i[1]==start and i[0]!=end))
        output = list(cg.edgeIterator(edgePredicate=lambda i: i[0]==end and i[1]!=start))
        
        middle = (start,end,index)
    
        if len(input)==1 and len(output)==1:
            input   = input[0]
            output  = output[0]
            
            inputcov   = cg.getEdgeAttr(*input)['weight']     
            middlecov  = cg.getEdgeAttr(*middle)['weight']     
            outputcov  = cg.getEdgeAttr(*output)['weight']     
            
            r1 = round(middlecov/float(inputcov))            
            r2 = round(middlecov/float(outputcov))
            
            r = int(round((r1+r2)/2))
                    
            constraints[cg.getEdgeAttr(*input)['stemid']] = [[cg.getEdgeAttr(*middle)['stemid']] * r + \
                                                            [cg.getEdgeAttr(*output)['stemid']]]
    return constraints

print input,inputcov,middle,middlecov,output,outputcov,r



def unfoldAssembling(self,assgraph,constraints=None,seeds=None,threshold=5.,back=500, minlink=5, limitSize=0):

    def addStepToAPath(path,step,limitSize):
        nw = dict(path[0])
        np = list(path[2]) 
        iw = path[3]
        nl = path[4]
        
        np.append(step)
        nw[abs(step)]-=iw
        ns=sum((nw[x]* length[x])**2  for x in nw)
        nl+=length[abs(step)]
                
        if ns > path[1] or (limitSize > 0 and nl > limitSize):
            rep = path
            complete=True
        else:
            rep = [nw,ns,np,iw,nl]
            complete=False
            
        return complete,rep

    
    attrs = [assgraph.getEdgeAttr(*e) for e in assgraph.edgeIterator()]
    attrs = dict((i['stemid'],(i['length'],i['weight'])) for i in attrs if 'stemid' in i and i['stemid'] > 0)
    
    if seeds is None:
        si = set(attrs.keys())
    else:
        si = set(assgraph.getEdgeAttr(*e)['stemid'] for e in seeds)
     
    if constraints is None:
        constraints = pathConstraints(self,assgraph,threshold=5.,back=500, minlink=5)
        
    weight=dict((k,attrs[k][1]) for k in si)
    length=dict((k,attrs[k][0]) for k in si)
    stems  = dict((assgraph.getEdgeAttr(*e)['stemid'],e) for e in assgraph.edgeIterator())

                
    # paths if the collection of on construction path
    #     each path is constituted of five elements :
    #              - [0] the weigth directory
    #              - [1] the score of the path which have to be minimized
    #              - [2] the actual path as a seauence of stem ids
    #              - [3] the weight of the first stem in the path
    #              - [4] the total length of the path

    paths = [[dict(weight),0,(i,),0,0] for i in si]       

    for p in paths:
        p[3] = p[0][abs(p[2][0])]
        p[0][abs(p[2][0])]=0
        p[1]=sum((p[0][x]*length[x])**2  for x in p[0])
        p[4]=length[abs(p[2][0])]
            
    completePath=[]

    while paths:

        # I try to extend paths with constrains

        newpath=[]
        
        for p in paths:
            last = p[2][-1]
            complete=False
            if last in constraints:
                for steps in constraints[last]:
                    lp = p
                    for step in steps:
                        complete,lp=addStepToAPath(lp,step,limitSize)
                        if complete:
                            completePath.append(lp)
                            break
                    if not complete:
                        newpath.append(lp)
                    
        paths = newpath
        newpath=[]
        
        print len(paths)
        
    cp={}    
    for p in completePath:
        first = stems[p[2][0]][0]
        end   = stems[p[2][-1]][1]
        closed = first==end
        if not closed:
            
            # We try to close the graph
            
#             c = assgraph.minpath(end,
#                                  [first],
#                                  edgePredicate=lambda e: 'stemid' in assgraph.getEdgeAttr(*e)
#                                 )
#             i = first
#             ep = [i]
#             while i != end and i in c[1]:
#                 i=c[1][i]
#                 ep.append(i)
            np = list(p[2])
#             for x in xrange(len(ep)-1,0,-1):
#                 s = assgraph.getEdgeAttr(ep[x],ep[x-1],0)['stemid']
#                 p[0][abs(s)]-=p[3]
#                 np.append(s)
            np = tuple(np)
            ns = sum((p[0][x]* length[x])**2  for x in p[0]) 
            first = stems[np[0]][0]
            end   = stems[np[-1]][1]
            closed = first==end
        else:
            ns = p[1]
            np = p[2]
        cp[tuple(np)]=(p[0],ns,p[3],closed)
        
    cp = [(x,cp[x][1],cp[x][-1]) for x in cp]
    cp.sort(key=lambda x:x[1],reverse=True)
         
    return cp
        

    paths = set(constraints.keys()) &  