=head1 NAME

iPE::Annotation::NullDefinition - defines a region in a transcript where the null models are counted.

=head1 DESCRIPTION

A NullDefinition defines an area in the transcript where all null models are counted.  A NullDefinition is defined by a state name, a range of bases in the particular feature in the transcript, and the ordinality.

=head1 FUNCTIONS

=over 8

=cut

package iPE::Annotation::NullDefinition;
use iPE;
use iPE::Globals;
use iPE::Util::Interval;
use iPE::Annotation::NullRegion;
use strict;

use base ("iPE::XML::Object");

=item new (tag, members)

This object is automatically constructed by the containing Estimator object from the data in the XML file.

=cut
sub new {
    my $class = shift;
    my ($tag, $m, $data) = @_;
    my $this = $class->SUPER::new (@_);
    
    $this->{states_} = [];
    for my $name (split (' ', $m->{states})) {
        push @{$this->{stateNames_}}, $name;
    }

    $this->{regionInterval_} = new iPE::Util::Interval(
        {low => $m->{start}, high => $m->{end}, letter => "L"});
    $this->{featureInterval_} = new iPE::Util::Interval(
        {low => $m->{first_feature}, high => $m->{last_feature},
         letter => "N"});
    $this->{seqtype_} = $m->{seqtype};
    if(defined($m->{sampling_rate})) {
        $this->{samplingRate_} = $m->{sampling_rate};
    }
    else {
        $this->{samplingRate_} = 1;
    }
    
    return $this;
}

=item stateNames ()

Returns the state names in which the NullDefinition resides

=cut
sub stateNames     { shift->{stateNames_}           }

=item regionInterval ()

Returns the boundaries of the region in the form of an iPE::Util::Interval object.

=cut
sub regionInterval  { shift->{regionInterval_}  }

=item featureInterval ()

Returns the first and last feature in which this region may happen in the form of an iPE::Util::Interval object.

=cut
sub featureInterval { shift->{featureInterval_} }

=item seqtype ()

Returns the type of sequence that the null definition pertains to.  These will be used when estimating the null model.

=cut
sub seqtype { shift->{seqtype_} }

=item samplingRate ()

Returns the frequency with which a null region should be counted.

=cut
sub samplingRate { shift->{samplingRate_} }

=item matchesState ()

Returns 1 if the state is in the list of states to be included in the null region, 0 otherwise.

=cut
sub matchesState {
    my ($this, $targetState) = @_;

    for my $state (@{$this->stateNames}) {
        return 1 if ($state eq $targetState->name);
    }

    return 0;
}

=item addToTranscript (transcript)

Adds null regions to all eligible features in the transcript passed in.  The transcript is required to be finalized.

=cut
sub addToTranscript {
    my ($this, $transcript) = @_;

    #count the number of eligible features for this region
    my $numFeatures = 0;

    my $feature;
    for $feature (@{$transcript->features}) {
        $numFeatures++ if $this->matchesState($feature->state);
    }

    return if($numFeatures == 0);

    my $featureNo = 0;
    for $feature (@{$transcript->features}) {
        next if (!$this->matchesState($feature->state));
        if(includes($this->featureInterval->translate(0, $numFeatures-1), 
                $featureNo)) {
            # make sure the null region doesn't overstep the bounds of 
            # the feature.
            my ($start, $end) = intersection( 
                    $this->regionInterval->translate(
                    $feature->start, $feature->end), 
                    $feature->start, $feature->end);
            if(defined $start && defined $end) {
                if(rand() < $this->samplingRate) {
                $feature->addNullRegion(
                    new iPE::Annotation::NullRegion({
                        start   => $start, 
                        end     => $end, 
                        seqtype => $this->seqtype}));
                msg("Null region: ".$feature->state->name.
                    " (".$start.", ".$end.") ".($end-$start+1).
                    " from (".$feature->start.", ".$feature->end.")\n");
                }
                else {
                    msg("Skipping null region because of sampling rate");
                }
            }
        }
        $featureNo++;
    }
}



=back

=head1 SEE ALSO

L<iPE::Transcript>, L<iPE::Feature>, L<iPE::Util::Interval>

=head1 AUTHOR

Bob Zimmermann (rpz@cse.wustl.edu)

=cut

1;
