#!/usr/bin/env python

from sys import stdout, stderr, exit, maxint
from optparse import OptionParser
from itertools import product, combinations, izip
from os.path import basename, dirname, join, isfile
from random import shuffle
import logging
import csv
import re

MARKER_PAT = re.compile('^([^:]+):(\d+):(\d+)(\+$|-$|$)')

FONTSIZE_VIS = 20

LOG = logging.getLogger(__name__)
LOG.setLevel(logging.DEBUG)

def readMarkerSequences(data):

    res = list()
    
    isHeader = True
    for _, segid, gene, _, _, in csv.reader(data, delimiter='\t'):
        if isHeader:
            isHeader = False
            continue
        if int(segid) > len(res):
            res.append(set())
        res[-1].add(gene)

    return res

def readIadhoreConfig(data):

    res = list()
    for line in data:
        if not line.strip():
            continue
        if line.find('=') >= 0:
            k, v = line.split('=', 1)
            res.append((k.strip(), v.strip()))
        elif line.find(' ') >= 0 and len(res):
            if len(res[-1]) < 3:
                res[-1] = res[-1] + (list(), )
            k, v = line.split(' ', 1)
            res[-1][2].append((k.strip(), v.strip()))
        else:
            print >> stderr, ('Unable to parse line \"%s\" in i-AdHoRe ' + \
                    'config file. Exiting') %line.strip()
            exit(1)
    return res


def readBlastTable(data, gene2genome):
    res = dict()
    for g1i, g2k in csv.reader(data, delimiter='\t'):
        G1 = gene2genome[g1i]
        G2 = gene2genome[g2k]
        if not res.has_key((G1, G2)):
            res[(G1, G2)] = dict()
            res[(G2, G1)] = dict()
        if not res[(G1, G2)].has_key(g1i):
            res[(G1, G2)][g1i] = set()
        res[(G1, G2)][g1i].add(g2k)
        if not res[(G2, G1)].has_key(g2k):
            res[(G2, G1)][g2k] = set()
        res[(G2, G1)][g2k].add(g1i)
    return res


def readGenomes(iadhoreConfig, configPath):
    genomes = dict()
    gene2genome = dict()
    for x in iadhoreConfig:
        if len(x) != 3 or x[0] != 'genome':
            continue
        genomes[x[1]] = list() 
        for _, fPath in x[2]:
            f = join(configPath, fPath)
            for line in open(f):
                gx = line.strip()
                if gx[-1] not in ('+', '-'):
                    LOG.fatal(('Gene %s in file %s has unknown ' + \
                            'orientation.  Exiting') %(gx, f))
                    exit(1)
                genomes[x[1]].append(gx[:-1])
                gene2genome[gx[:-1]] = x[1]
    return genomes, gene2genome


def readSegments(data):

    isHeader = True
    
    res = dict()
    c = 0
    for line in csv.reader(data, delimiter='\t'):
        if isHeader:
            isHeader = False
            continue
        
        mid = int(line[1])
        if not res.has_key(mid):
            res[mid] = list()
        res[mid].append((c, line[2], line[4], line[5]))
        c += 1

    return res


def weightedScore(segments, marker_seqs, blastMap, onlyAll=False):
    res = list()

    if onlyAll:
        n = len(set(reduce(lambda x,y: x+y, blastMap.keys())))

    for mid in sorted(segments.keys()):
        if onlyAll and len(set(x for _, x, _, _ in segments[mid])) < n:
            continue
        c = 0.0
        s = 0
        for i in xrange(len(segments[mid])):
            sid1, G1, _, _ = segments[mid][i]
            s += len(marker_seqs[sid1])
            for g1x in marker_seqs[sid1]:
                hasHit = True
                j = 0
                while hasHit and j < len(segments[mid]):
                    j += 1
                    if i == j-1:
                        continue
                    sid2, G2, _, _ = segments[mid][j-1]
                    hasHit = blastMap.has_key((G1, G2)) and \
                            blastMap[(G1, G2)].has_key(g1x)
                    if not hasHit:
                        break
                    hasHit_i = False
                    for g2y in blastMap[(G1, G2)][g1x]:
                        hasHit_i = g2y in marker_seqs[sid2]
                        if hasHit_i:
                            break
                    hasHit = hasHit_i
                if hasHit:
                    c += 1
        res.append((mid, c/s))
    return res


def relaxedScore(segments, marker_seqs, blastMap, onlyAll=False):
    res = list()
    for mid in sorted(segments.keys()):
        if onlyAll and len(set(x for _, x, _, _ in segments[mid])) < n:
            continue