=head1 NAME

iPE::Model::Duration - The duration container class for iParameterEstimation.

=head1 DESCRIPTION

This class contains a composite duration distribution model of one or more submodels.  Each submodel is the distribution for a particular isochore level.  

=cut

package iPE::Model::Duration;

use iPE;
use iPE::Globals;
use iPE::Model;
use iPE::Util::Output;
use iPE::Model::DurationSubmodel;
use base ("iPE::Model");
use strict;

=head1 CONSTANTS

=over 8

=item DEFAULT_SMOOTHING (), DEFAULT_SMOOTHING_DATA ()

Default smoothing for duration distributions is kernel-gaussian and thus this is overridden in this class.

=back 

=cut

sub defaultSmoothing { "kernel" }
sub defaultSmoothingData { "2 5" }

=head1 FUNCTIONS 

=over 8

=item new(tag, attributes, data, element)

Creates a new duration.  This is subsequently filled out through parsing of the XML file that defines the submodels.

=cut
sub new {
    my $class = shift;
    my $this = $class->SUPER::new(@_);
    my ($tag, $m, $data, $element) = @_;

    $this->{region_} = $m->{region};
    $this->{ISO_} = new iPE::Model::ISO({ISOs => $m->{isochores}});
    die "No isochore for level 100 for duration region $this->{region_}.\n"
        if($this->{ISO_}->find_exact(100) == -1);
    $this->{submodels_} = {};

    $this->{lengthUnit_} = $m->{length_unit};

    $this->handle_submodels($element);
    $this->init;

    return $this;
}

=item region

Returns the name of the region this duration distribution implies

=cut
sub region { shift->{region_} }

=item ISO

Returns the isochore levels object.  See L<iPE::Model::ISO> for details.

=cut
sub ISO { shift->{ISO_} }

=item submodels

Returns the hash reference of submodels, keyed on the isochore levels.

=cut
sub submodels { shift->{submodels_} }

sub init {
    my ($this) = @_;

    for my $iso (keys %{$this->submodels}) {
        $this->submodels->{$iso}->init;
    }
}

sub outputPrepare {
    my ($this, $out, $mode) = @_;

    for my $iso (keys %{$this->submodels}) {
        $this->submodels->{$iso}->outputPrepare($out, $mode);
    }
}

sub outputZoe {
    my ($this, $out, $mode) = @_;

    $out->print ($out->indent.$this->region." ");
    if($this->ISO->nLevels > 1) {
        $out->print ("ISO ".$this->ISO->nLevels." levels\n");
        $out->increaseIndent;
        for my $iso (sort {$a <=> $b} keys %{$this->submodels}) {
            $out->print ($out->indent."ISO ".$iso." ");
            $this->submodels->{$iso}->outputZoe($out, $mode);
        }
        $out->decreaseIndent;
    }
    else {
        for my $iso (sort keys %{$this->submodels}) {
            $this->submodels->{$iso}->outputZoe($out, $mode);
        }
    }
}

sub countFeature {
    my ($this, $feature, $wt) = @_;

    my $submodel = $this->ISO->find($feature->gcLevel);
    my $level = $this->ISO->levels->[$submodel];
    $this->submodels->{$level}->countFeature($feature, $wt);
}

sub smooth {
    my ($this) = @_;

    for my $level (keys %{$this->submodels}) {
        $this->submodels->{$level}->smooth;
        msg("Duration $this->{region_} Total samples: ".
            $this->submodels->{$level}->totalSamples." Counted samples: ".
            $this->submodels->{$level}->countedSamples."\n");
    }
}

sub normalize {
    my ($this) = @_;

    for my $level (keys %{$this->submodels}) {
        $this->submodels->{$level}->normalize;
    }
}

sub score { 
    my ($this) = @_;

    for my $level (keys %{$this->submodels}) {
        $this->submodels->{$level}->score;
    }
}


#private functions

sub handle_submodel {
    my ($this) = shift;
    my ($tag, $att, $data, $element) = @_;

    if($tag eq "duration_submodel") {
        my $iso = $att->{isochore};
        my $level = $this->ISO->find_exact($iso);
        die "Cannot not match for isochore level ".$iso." for duration model ".
            $this->region."\n" if($level == -1);

        # pass the region name along to the submodel
        $att->{region} = $this->region;
        $this->submodels->{$iso} = new iPE::Model::DurationSubmodel(@_);
    }
    #shouldn't happen -- DTD should check for this.
    else { Warn("Unrecognized tag: $tag (expected duration_submodel) \n") }

}

=head1 SEE ALSO

L<iPE::Model> L<iPE::Model::ISO>

=head1 AUTHOR

Bob Zimmermann (rpz@cse.wustl.edu)

=cut

1;
