=head1 NAME

iPE::State::AltSplice::MultiSite - Base class for multi 5' and multi 3' site alternative splice states.

=head1 DESCRIPTION

This class defines the common functions used in multi site alternate splice states.  This cannot be directly used on the user level, this is an internal class.

=head1 FUNCTIONS

=over 8

=cut

package iPE::State::AltSplice::MultiSite;
use iPE;
use base("iPE::State::AltSplice");
use strict;

=item getGroups (transcripts, seqLen)

Finds groups of overlapping exons in the passed transcripts and returns them.  This function requires that the innermost state (the smallest feature in the group) be the same as the origin state, and that the other states be contained in the list of alternate states.  Returns a reference to an array of arrays of objects, representing these groups.  The first element of every group array contains the group's smallest element.

=cut

sub getGroups {
    my ($this, $transcripts, $seqLen) = @_;

    my @feats_remain = ();
    my @groups = ();
    my $node = undef;

    for my $tx (@$transcripts) { push @feats_remain, @{$tx->features}; }
    @feats_remain = sort { $a->length <=> $b->length } @feats_remain;

    my @returned_groups;
    #while(scalar(@feats_remain)) {
        my @feats = @feats_remain;
        for my $feat (@feats) {
            next unless($this->validState($feat->state));
            my $featNode = new iPE::Util::Overlap::Node( 
                { low => $feat->start, high => $feat->end, 
                  letter => "L", object => $feat} );
            my $found = 0;
            for my $group (@groups) {
                if(defined($group->find_overlap($featNode))) {
                    $group->insert($featNode);
                    $found = 1;
                    last;
                }
            }
            
            # make a new group if this conflicts with other groups.
            unless($found) {
                my $newGroup = new iPE::Util::Overlap;
                $newGroup->insert($featNode);
                push @groups, $newGroup;
            }
        }

        @feats_remain = ();
        for my $group (@groups) {
            next unless (scalar(@{$group->nodes}) > 1);
            #find the smallest one
            my $smallestNode;
            for my $featNode (@{$group->nodes}) {
                if(!defined($smallestNode) ||
                        ($smallestNode->high-$smallestNode->low+1) >
                        ($featNode->high-$featNode->low+1)) {
                    $smallestNode = $featNode;
                }
            }

            #make a group of all the ones small that belong in the smallest one
            # removing the ones that fit from the group.
            my @returned_group = ($smallestNode->object);
            for my $featNode (@{$group->nodes}) {
                if($featNode->low->coord <= $smallestNode->low->coord &&
                   $featNode->high->coord >= $smallestNode->high->coord &&
                   $featNode->object->strand eq $smallestNode->object->strand) {
                    push @returned_group, $featNode->object;
                }
                else {
                    # just discard these oddballs which don't fit into the 
                    # splice heirarchy
                    #push @returned_groups, [$featNode->object];
                }
            }

            #NB: We separate groups where the smallest feature defines the 
            #    group and its contents.  However if this is not the correct
            #    altsplice state i.e. the state of the smallest feature
            #    is not the origin state, we don't return this group.
            #    It is still eliminated from further analysis because the true
            #    group cannot be defined with this altsplice state.
            push @returned_groups, \@returned_group
                if($smallestNode->object->state->name eq $this->originState);
        }
    #}

    return \@returned_groups;
}
=back

=head1 SEE ALSO

L<iPE::State>, L<iPE::State::AltSplice>, L<iPE::State::AltSplice::MultiThreePrime>, L<iPE::State::AltSplice::MultiFivePrime>

=head1 AUTHOR

Bob Zimmermann (rpz@cse.wustl.edu)

=cut

1;
