=head1 NAME

iPE::Model::ISO - A simple container for ISO levels used in many of models.

=head1 DESCRIPTION

This class simply contains isochore levels which partition the parameter counting.  Any model can contain this class to refer to where a particular sequence should fit in, and how to allocate parameters.

=cut

package iPE::Model::ISO;
use Carp;

=head1 FUNCTIONS

=over 8

=item new(ISOs => levels)

Constructor.  ISOs must be a whitespace-delimited string containing the ISO levels.  For example, "35 39 100" would produce three ISO levels in the object.  (This is useful for parsing the attributes of an XML tag formatted as such.)

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

    die "Incomplete instantiation of class $class.\n".
        "Required fields are: ISOs.\n"
        unless exists   $m->{ISOs};

    $this->{ISOs_} = [ split(" ", $m->{ISOs}) ];
    $this->{ISOs_} = [ sort { $a <=> $b } @{$this->{ISOs_}} ];

    return $this;
}

=item levels

Returns a reference to an array of isochore levels

=cut
sub levels  { return shift->{ISOs_} }

=item nLevels

Returns the number of isochore levels used

=cut
sub nLevels { return scalar(@{shift->levels}) }

=item find (level)

Finds the next highest isochore level to level.  If none exists in this object, -1 is returned.

=cut
sub find {
    my($this, $level) = @_;

    croak "Level cannot be greater than 100 or less than 1" 
        if ($level > 100 || $level < 0);

    #if($level <= $this->levels->[0]) { return 0 }
    for(my $i = 0; $i < $this->nLevels; $i++) {
        if($level <= $this->levels->[$i]) { return $i }
    }

    return -1;
}

=item snap (level)

Snap a level to the next highest ISO level in this iso object.  If none exists in this object, -1 is returned.

=cut
sub snap {
    my($this, $level) = @_;

    croak "Level cannot be greater than 100 or less than 1" 
        if ($level > 100 || $level < 0);

    #if($level <= $this->levels->[0]) { return $this->levels->[0] }
    for(my $i = 0; $i < $this->nLevels; $i++) {
        if($level <= $this->levels->[$i]) { return $this->levels->[$i] }
    }

    return -1;
}


=item findExact(level)

Returns the position of the level which exactly matches the passed level.  If no such level is found, -1 is returned.

=cut
sub find_exact {
    my ($this, $level) = @_;
    my $result = -1;

    for(my $i = 0; $i < $this->nLevels; $i++) {
        if (${$this->levels}[$i] == $level) {
            $result = $i;
        }
    }

    return $result;
}

=back

=head1 SEE ALSO

=head1 AUTHOR

Bob Zimmermann (rpz@cse.wustl.edu)

=cut
1;
