'When replacing one block of lines with another, search the blocks
for *similar* lines; the best-matching pair (if any) is used as a synch
point, and intraline difference marking is done on the similar pair.
Lots of work, but often worth it.'

def replace(self, alo, ahi, blo, bhi):

    (alo, ahi, blo, bhi) = self.trim_identical_leading_lines(alo, ahi, blo, bhi)
    if ((alo == ahi) and (blo == bhi)):
        return
    if ((((ahi + bhi) - alo) - blo) > 100):
        return self.do_replace(alo, ahi, blo, bhi)
    (best_ratio, cutoff) = (0.74, 0.75)
    cruncher = SequenceMatcher()
    (eqi, eqj) = (None, None)
    (a, b) = (self.left_lines, self.right_lines)
    for j in xrange(blo, bhi):
        bj = b[j]
        cruncher.set_seq2(bj)
        for i in xrange(alo, ahi):
            ai = a[i]
            if (ai == bj):
                if (eqi is None):
                    (eqi, eqj) = (i, j)
                continue
            cruncher.set_seq1(ai)
            if ((cruncher.real_quick_ratio() > best_ratio) and (cruncher.quick_ratio() > best_ratio) and (cruncher.ratio() > best_ratio)):
                (best_ratio, best_i, best_j) = (cruncher.ratio(), i, j)
    if (best_ratio < cutoff):
        if (eqi is None):
            self.do_replace(alo, ahi, blo, bhi)
            return
        (best_i, best_j, best_ratio) = (eqi, eqj, 1.0)
    else:
        eqi = None
    self.replace_helper(alo, best_i, blo, best_j)
    if (eqi is None):
        self.do_replace(best_i, (best_i + 1), best_j, (best_j + 1))
    else:
        self.equal(best_i, (best_i + 1), best_j, (best_j + 1))
    self.replace_helper((best_i + 1), ahi, (best_j + 1), bhi)
