{
@Override
public int compare(AlignedCodon ac1, AlignedCodon ac2)
{
if (ac1 == null || ac2 == null || ac1.equals(ac2))
{
return 0;
}
/**
*
* Case 1: if one starts before the other, and doesn't end after it, then it
* precedes. We ignore the middle base position here.
* A--GT
* -CT-G
*
*/
if (ac1.pos1 < ac2.pos1 && ac1.pos3 <= ac2.pos3)
{
return -1;
}
if (ac2.pos1 < ac1.pos1 && ac2.pos3 <= ac1.pos3)
{
return 1;
}
/**
*
* Case 2: if one ends after the other, and doesn't start before it, then it
* follows. We ignore the middle base position here.
* -TG-A
* G-TC
*
*/
if (ac1.pos3 > ac2.pos3 && ac1.pos1 >= ac2.pos1)
{
return 1;
}
if (ac2.pos3 > ac1.pos3 && ac2.pos1 >= ac1.pos1)
{
return -1;
}
/*
* Case 3: if start and end match, compare middle base positions.
*/
if (ac1.pos1 == ac2.pos1 && ac1.pos3 == ac2.pos3)
{
return Integer.compare(ac1.pos2, ac2.pos2);
}
/*
* That just leaves the 'enclosing' case - one codon starts after but ends
* before the other. If the middle bases don't match, use their comparison
* (majority vote).
*/
int compareMiddles = Integer.compare(ac1.pos2, ac2.pos2);
if (compareMiddles != 0)
{
return compareMiddles;
}
/**
*
* Finally just leaves overlap with matching middle base, e.g.
* -A-A-A
* G--GG
* In this case the choice is arbitrary whether to compare based on
* first or last base position. We pick the first. Note this preserves
* symmetricality of the comparison.
*
*/
return Integer.compare(ac1.pos1, ac2.pos1);
}
}