=head1 NAME

iPE::Model::Emission::WWAM - Windowed Weight Array Model.

=head1 DESCRIPTION

=head1 FUNCTION

=cut

package iPE::Model::Emission::WWAM;
use iPE;
use base("iPE::Model::Emission::WAM");
use strict;

sub init {
    my $this = shift;

    $this->SUPER::init(@_);

    unless($this->hasSettings) {
        #XXX deprecated.  remove when moving to settings format
        my @data = split (' ', $this->{data_});
        $this->settings->{windowRadius} = $data[1];
    }

    $this->settings->{windowRadius} ||= "2";
    if($this->windowRadius =~ m/[^\d]/) {
        die "The windowRadius setting for WWAM must be an integer.  ".
            "Error found in ".$this->name.".\n";
    }
}

sub windowRadius { shift->settings->{windowRadius} }

sub countRegion     { 
    my ($this, $region) = @_;
    if($region->seq->loaded) { _count(@_, 0)            }
    else                     { _countUnloaded(@_, 0)    }
}
    
sub countNullRegion { 
    my ($this, $region) = @_;
    if($region->seq->loaded) { _count(@_, 1)            }
    else                     { _countUnloaded(@_, 1)    }
}

sub _count {
    my ($this, $region, $null) = @_;

    my $buck;
    if($null)   { $buck = $this->nullCounts }
    else        { $buck = $this->posCounts  }

    my $start = $region->start;
    my $weight = $region->weight;
    my $context = $region->context;
    my $order = $this->order;
    my $strRef = $region->strRef;
    my $length = $this->length - $region->context;
    my $wr = $this->windowRadius;

    for my $pos (-$wr .. -1) {
        my $nmer = substr($$strRef, $start+$pos-$order, $order+1);

        $buck->[0]->{$nmer} += $weight;
    }

    for my $pos (0 .. $length-1) {
        my $nmer = substr($$strRef, $start+$pos-$order, $order+1);

        for my $winpos (0 .. $wr-1) {
            $buck->[$pos+$winpos+$context]->{$nmer} += $weight;
        }
    }

    for my $pos ($length .. $length+$wr-1) {
        my $nmer = substr($$strRef, $start+$pos-$order, $order+1);

        $buck->[$length]->{$nmer} += $weight;
    }
}

sub _countUnloaded {
    my ($this, $region, $null) = @_;

    my $buck;
    if($null)   { $buck = $this->nullCounts }
    else        { $buck = $this->posCounts  }

    my $start = $region->start;
    my $weight = $region->weight;
    my $context = $region->context;
    my $order = $this->order;
    my $targetOrder = $this->targetOrder;
    my $strRef = $region->strRef;
    my $length = $this->length - $region->context;
    my $wr = $this->windowRadius;

    my $strand = $region->strand;
    my $seq = $region->seq;
    my $nmer;
    for my $pos (-$wr .. -1) {
        $nmer = $seq->getContext($strand, $start+$pos, $order, $targetOrder);
        $buck->[0]->{$nmer} += $weight;
    }

    for my $pos (0 .. $length-1) {
        $nmer = $seq->getContext($strand, $start+$pos, $order, $targetOrder);

        for my $winpos (0 .. $wr-1) {
            $buck->[$pos+$winpos+$context]->{$nmer} += $weight;
        }
    }

    for my $pos ($length .. $length+$wr-1) {
        $nmer = $seq->getContext($strand, $start+$pos, $order, $targetOrder);
        $buck->[$length]->{$nmer} += $weight;
    }
}

=head1 SEE ALSO

L<iPE::Model::Emission::WAM> L<iPE::Model::Emission> 

=head1 AUTHOR

Bob Zimmermann (rpz@cse.wustl.edu)

=cut

1;
