#!/usr/bin/env python
# Jacob Joseph
# June 19, 2007

import sys

class combined:
    """A greedy heuristic for combining all blast alignments
between a pair of sequences, to calculate a 'combined' coverage.  Add
an alignment only if it does not conflict with an already specified
alignment.  The caller is responsible for insertion order."""

    # List of available ranges
    seq_0_avail = None
    seq_1_avail = None
    coverage = None

    # keep blast score and ff_bool for convenience
    bit_score = None
    e_value = None
    ff_bool = None

    def __init__(self, bit_score=None, e_value=None, ff_bool=None):
        self.seq_0_avail = [ (1, sys.maxint) ]
        self.seq_1_avail = [ (1, sys.maxint) ]
        self.coverage = 0.0
        self.bit_score = bit_score
        self.e_value = e_value
        self.ff_bool = ff_bool

    def set_unavail( self, seq_0_position, seq_1_position,
                     seq_start_0, seq_end_0, seq_start_1, seq_end_1):
        self.seq_0_avail.remove( seq_0_position)
        (ss0, se0) = seq_0_position
        if ss0 != seq_start_0: self.seq_0_avail.append( (ss0, seq_start_0 - 1))
        if se0 != seq_end_0: self.seq_0_avail.append( (seq_end_0 + 1, se0))

        self.seq_1_avail.remove( seq_1_position)
        (ss1, se1) = seq_1_position
        if ss1 != seq_start_1: self.seq_1_avail.append( (ss1, seq_start_1 - 1))
        if se1 != seq_end_1: self.seq_1_avail.append( (seq_end_1 + 1, se1))
        return

    def add(self, seq_start_0, seq_end_0, seq_start_1, seq_end_1, coverage):
        self.coverage += coverage
        return

    def add_unless_conflict( self, seq_start_0, seq_end_0,
                             seq_start_1, seq_end_1, coverage):

        seq_0_position = None
        for (ss0, se0) in self.seq_0_avail:
            if seq_start_0 >= ss0 and seq_end_0 <= se0:
                seq_0_position = (ss0, se0)
        seq_1_position = None
        for (ss1, se1) in self.seq_1_avail:
            if seq_start_1 >= ss1 and seq_end_1 <= se1:
                seq_1_position = (ss1, se1)
        if seq_0_position and seq_1_position:
            self.set_unavail( seq_0_position, seq_1_position,
                              seq_start_0, seq_end_0, seq_start_1, seq_end_1)
            self.add(seq_start_0, seq_end_0, seq_start_0, seq_end_1, coverage)
        return
