=head1 NAME

iPE::Sequence::Region - A region of any sequence.

=head1 DESCRIPTION

Generically defines a region of a sequence either in the forward or reverse strand of the sequence.  This is intended for passing a region to a model where observations will be counted.

All regions are initially defined by a series of positions within a feature where the counting gets the same weight.  These are further broken down into subregions where models are.  Due to the fact that the boundaries of the original regions may not fall on the same boundaries as the boundaries of the model, a "context" member variable is provided for information about where in the model to begin counting.  For example, if a model is a 10 base position specific model, and the model starts at 5, then  The region looks like this:

         0123456789
Model:   |--------|
Region:       |---|
Context: |---|

The context would be 5, and you would count the 5 last bases with the provided weight.

=head1 FUNCTIONS

=over 8

=cut

package iPE::Sequence::Region;
use iPE;
use iPE::Util::DNATools;
use iPE::Util::Interval;
use iPE::Annotation::Feature;
use Carp;
use strict;

=item new (memberHash)

Construct a new region.  This is generally done internally in iPE and passed up to the models.  The following keys must be defined in order to construct a new region:

=over 8

=item start, end

The beginning and end of the region.

=item parentStart, parentEnd

The beginning and end of the parent region of this region.  The parent region is the region of immediate relevance to the region.  Regions are either the same size of the parent region or smaller.  If they are smaller, it is because of a layering difference in the middle of the region.  If this is not supplied, it is assumed that the parent region is (start, end).

=item feature

The associated feature of the region.

=item seq

The sequence object to be used.

=item weight

The weight to give each count.  If no weight is supplied, this is set to 1.

=back

=cut
sub new {
    my ($class, $m) = @_;

    croak __PACKAGE__." requires a start, end, feature and sequence object defined.\n"
        if (!defined $m->{start}        || !defined $m->{end}       ||
            !defined $m->{feature}      || !defined $m->{seq}       );

    my $this = bless {}, $class;
    $this->{$_."_"} = $m->{$_} for(keys %$m);

    $this->{weight_} = 1 if(!defined($this->{weight_}));

    #prevent the region from going off the end of the sequence.
    ($this->{start_}, $this->{end_}) = 
        intersection(0, $this->{seq_}->length-1, $this->{start_}, $this->{end_});
    $this->{parentStart_} = $this->{start_} if(!defined($this->{parentStart_}));
    $this->{parentEnd_} = $this->{end_} if(!defined($this->{parentEnd_}));

    #prevent the region from going off the end of the sequence.
    ($this->{parentStart_}, $this->{parentEnd_}) = 
        intersection(0, $this->{seq_}->length-1, 
            $this->{parentStart_}, $this->{parentEnd_});

    $this->{type_} = $this->{seq_}->type;
    $this->{strand_} = $this->{feature_}->strand;
    if($this->{strand_} eq '-') { 
        $this->{strRef_} = $this->{seq_}->rcRef;
        $this->{frame_} = $this->{feature_}->endFrame;
    }
    else { 
        $this->{strRef_} = $this->{seq_}->seqRef;
        $this->{frame_} = $this->{feature_}->startFrame;
    }

    return $this;
}

=item clone ()

Create a copy of the region object. 

=cut
sub clone {
    my ($this) = @_;
    return bless { %$this }, ref($this);
}

=item subregion(parentStart, parentEnd)

Create a subregion of the current region with new parent coordinates (parentStart, parentEnd).  The new (start, end) coordinates will be the intersection of the current (start, end) coordinates and (parentStart, parentEnd).  If the intersection is the empty set, undef is returned.

=cut
sub subregion {
    my ($this, $parentStart, $parentEnd) = @_;
    my $sr = $this->clone;
    $sr->{parentStart_} = $parentStart;
    $sr->{parentEnd_}   = $parentEnd;
    my @i= intersection($sr->{parentStart_}, $sr->{parentEnd_}, 
                        $sr->{start_}, $sr->{end_});
    return undef if(scalar(@i) == 0);
    ($sr->{start_}, $sr->{end_}) = @i;
    return $sr;
}


=item strRef ()

The string object to count parameters with.  This is usually a reference to a Perl string, but in the case of multiple alignment sequences is different.

=item parentStart (), parentEnd ()

The start and end of the parent region in the string.

=item start (), end ()

The start and end region in the string.  

=item context ()

The distance between the beginning of the parent region and the beginning of this region.

=item feature ()

The assocated feature of this region.

=item seq ()

The actual iPE::Sequence that the parameters are being estimated on.

=item weight ()

The weight to give each count.

=cut
sub parentStart     { _getter_setter("parentStart_", @_) }
sub parentEnd       { _getter_setter("parentEnd_", @_)   }
sub start           { _getter_setter("start_", @_)       }
sub end             { _getter_setter("end_", @_)         }
sub context         { $_[0]->start - $_[0]->parentStart  } 
sub feature         { shift->{feature_}             }
sub seq             { shift->{seq_}                 }
sub strRef          { shift->{strRef_}              }
sub weight          { shift->{weight_}              }
sub frame           { shift->{frame_}               }
sub strand          { shift->{strand_}              }
sub length          { return ($_[0]->{end_}-$_[0]->{start_}+1) }

sub _getter_setter {
    my ($key, $this) = @_; shift; shift;
    scalar @_ and $this->{$key} = shift;
    $this->{$key};
}

=back

=head1 SEE ALSO

L<iPE::Sequence>

=head1 AUTHOR

Bob Zimmermann (rpz@cse.wustl.edu)

=cut
1;
