=head1 NAME

iPE::Model::Emission::JUMPLUT - Markov chain model (Look-Up Table) estimated by jumping not sliding

=head1 DESCRIPTION

=head1 FUNCTIONS

=cut

package iPE::Model::Emission::JUMPLUT;
use iPE;
use base("iPE::Model::Emission::LUT");
use strict;

sub init {
    my ($this) = @_;
    $this->{posCounts_}  = {};
    $this->{nullCounts_} = {};
    $this->{scores_}     = {};

    unless($this->hasSettings) {
        #XXX deprecated.  remove when moving to settings format
        my $orderstr;
        ($orderstr, $this->settings->{jumpLen}) = 
            split(' ', $this->{data_});

        if($orderstr =~ m/\//) {
            ($this->settings->{order}, $this->settings->{targetOrder}) = 
                split(/\//, $orderstr);
        }
        else {
            ($this->settings->{order}, $this->settings->{targetOrder}) = 
                ($orderstr, $orderstr);
        }

    }
    die("JUMPLUT requires an order setting in the data attribute.\n")
        if(!defined($this->order));


#!!!check for jumplen correctly formed.
    if(!defined($this->jumpLen)) {
        die "JUMPLUT requires a jump length in the data attribute";
    }

    $this->settings->{targetOrder} ||= $this->order;
    if($this->order =~ m/[^\d]/ || $this->targetOrder =~ m/[^\d]/) {
        die(__PACKAGE__.": The order and targetOrder settings for JUMPLUT\n".
            "must only contain digits.\n");
    }
}

sub jumpLen { shift->settings->{jumpLen} }

sub countRegion     { 
    my ($this, $region) = @_;
    if($region->seq->loaded) { _count(@_, 0)         }
    else                     { die "I don't do this.\n" ; } #!!!More specific.
}
sub countNullRegion { 
    my ($this, $region) = @_;
    if($region->seq->loaded) { _count(@_, 1)         }
    else                     { die "I don't do this.\n"; }
}

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

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

    #optimization
    my $order = $this->order;
    my $weight = $region->weight;
    my $end = $region->end;
    my $strRef = $region->strRef;
    my $jumplen = $this->jumpLen;

    my $str;
    for (my $pos = $region->start+$order; $pos <= $end; $pos += $jumplen) {
        $str = substr($$strRef, $pos-$order, $order+1);
        $buck->{$str} += $weight;
    }
}

# Cannot handle ambiguation yet
sub normalize {
    my ($this) = @_;
    
    my @nmers = $this->seqClass->getAllSequences($this->order+1,$this->ambiguate);
    #whether or not we have a null model.
    my $nullModel = $this->nullModel;
    my $wildCard = $this->seqClass->getWildCard();
    my @alphabet = @{$this->seqClass->getAlphabet};
    push @alphabet, $this->seqClass->getWildCard 
        if($this->ambiguate && $this->wildcard == iPE::Model::Emission::LITERAL());
    my $totCounts = 0;
    my $totNullCounts = 0;
    for my $nmer (@nmers) {
        $totCounts += $this->posCounts->{$nmer};
        $totNullCounts += $this->nullCounts->{$nmer} if($nullModel);
    }
    for my $nmer (@nmers) {
        $this->posCounts->{$nmer} /= $totCounts
            if($totCounts);
        $this->nullCounts->{$nmer} /= $totNullCounts 
            if($totNullCounts && $nullModel);
    }
}

=head1 SEE ALSO

L<iPE::Model::Emission::LUT>

=head1 AUTHOR

Manimozhiyan Arumugam (mozhiyan@cse.wustl.edu)

=cut

1;

