=head1 LICENSE

  Copyright (c) 1999-2012 The European Bioinformatics Institute and
  Genome Research Limited.  All rights reserved.

  This software is distributed under a modified Apache license.
  For license details, please see

    http://www.ensembl.org/info/about/code_licence.html

=head1 CONTACT

  Please email comments or questions to the public Ensembl
  developers list at <dev@ensembl.org>.

  Questions may also be sent to the Ensembl help desk at
  <helpdesk@ensembl.org>.

=cut

=head1 NAME

Bio::EnsEMBL::DensityFeatureSet -
A feature representing a set of density features

=head1 SYNOPSIS

  use Bio::EnsEMBL::DensityFeatureSet;

  my $densitySet = Bio::EnsEMBL::DensityFeatureSet->new(
    -bin_array = \@out,
    -stretch   = 1,
  );

=head1 DESCRIPTION

A density feature set is a wrap around a array of density features with
additional information about the collective density feature set, such as
max_min_values and scale factors etc. a given region.

This module is part of the Ensembl project http://www.ensembl.org

=head1 METHODS

=cut


package Bio::EnsEMBL::DensityFeatureSet;

use strict;
use warnings;

use Bio::EnsEMBL::Utils::Argument qw(rearrange);
use Bio::EnsEMBL::Utils::Exception qw(throw);

=head2 new

  Description: Creates a new density feature set.
  Returntype : Bio::EnsEMBL::DensityFeatureSet
  Exceptions : throw if invalid density value type is provided
  Caller     : general
  Status     : Stable

=cut

sub new {
  my $class = shift;

  my $max_value = undef;
  my $min_value = undef;

  my($dfeats, $stretch, $scale_to_fit) =
      rearrange(['FEATURES', 'STRETCH', 'SCALE_TO_FIT'], @_);
  foreach (@$dfeats){
	  my $value = $_->density_value;
	  $max_value = $value if (!defined($max_value) || $value > $max_value); 
	  $min_value = $value if (!defined($min_value) || $value < $min_value);
  }

  return bless {'bin_array'    => $dfeats,
  	            'stretch'      => $stretch,
                'scale_to_fit' => $scale_to_fit,
                'min_value'    => $min_value,
                'max_value'    => $max_value}, $class;
}


=head2 stretch

 Title   : stretch
 Usage   : $obj->stretch($newval)
 Function: gets/sets a boolean for whether we should stretch the data over the
 range (i.e. from min to max rather than absolute numbers).
 Returns : value of _stretch
 Args    : newvalue (optional)
 Status  : Stable

=cut

sub stretch{
   my $self = shift;
   $self->{'stretch'} = shift if(@_);
   return $self->{'stretch'};
}


=head2 scale_to_fit

 Title   : scale_to_fit
 Usage   : $obj->scale_to_fit($newval)
 Function: gets/sets the number that the BinValues are to be scaled against -
 i.e. the greatest BinValue->value will be scaled to this number, and the rest
 scaled in proportion.
 Returns : scale_to_fit value
 Args    : newvalue (optional)
 Status  : Stable


=cut

sub scale_to_fit{
   my $self = shift;
   $self->{'scale_to_fit'} = shift if (@_);
   return $self->{'scale_to_fit'};

}

=head2 colour

 Title   : colour
 Usage   : $obj->colour($newval)
 Function: 
 Returns : value of colour
 Args    : newvalue (optional)
 Status  : Stable


=cut


sub colour{
   my $self = shift;
   $self->{'color'} = shift if(@_);
   return $self->{'color'};

}

=head2 label

 Title   : label
 Usage   : $obj->label($newval)
 Function: 
 Returns : String containing label
 Args    : newvalue (optional)
 Status  : Stable


=cut

sub label{
   my $self = shift;
   $self->{'label'} = shift if (@_);
   return $self->{'label'};

}


=head2 label2

 Title   : label2
 Usage   : $obj->label2($newval)
 Function: 
 Returns : String containing label2
 Args    : newvalue (optional)
 Status  : Stable


=cut

sub label2{
    my $self = shift;
   $self->{'label2'} = shift if (@_);
   return $self->{'label2'};
}



=head2 get_all_binvalues

  Arg [1]    : none
  Example    : @binvalues = @{$dfs->get_all_binvalues};
  Description: Scales all of the contained DensityFeatures by $scalefactor
               and returns them.
  Returntype : reference to a list of DensityFeatures
  Exceptions : none
  Caller     : general
  Status     : Stable

=cut

sub get_all_binvalues{
  my $self = shift;
  my $max_value = $self->max_value();
  my $min_value = $self->min_value();

 	return [] if(!@{$self->{'bin_array'}});

  my $width = $self->scale_to_fit();
  return [] unless defined($width);
  # throw("Cannot scale values - scale_to_fit has not been set");

  if ($self->stretch && ($max_value-$min_value) ){
    foreach my $bv (@{ $self->{'bin_array'}}){
      my $scaledval = (($bv->density_value - $min_value) /
                       ($max_value-$min_value) )* $width;
      $bv->scaledvalue($scaledval);
    }
  } elsif($max_value) {
    foreach my $bv (@{ $self->{'bin_array'}}){
      my $scaledval = ($bv->density_value / $max_value) * $width;
      $bv->scaledvalue($scaledval);
    }
  } else {
    foreach my $bv (@{ $self->{'bin_array'}}){
      $bv->scaledvalue(0);
    }
  }

  return $self->{'bin_array'};
}


=head2 max_value

  Arg [1]    : none
  Example    : my $max = $dfs->max_value();
  Description: Returns the maximum density feature value from the density
               feature set
  Returntype : int
  Exceptions : none
  Caller     : general
  Status     : Stable

=cut

sub max_value{ $_[0]->{'max_value'};}


=head2 min_value

  Arg [1]    : none
  Example    : my $min = $dfs->min_value();
  Description: Returns the minimum density feature value from the density
               feature set.
  Returntype : int
  Exceptions : none
  Caller     : general
  Status     : Stable

=cut

sub min_value{ $_[0]->{'min_value'};}



=head2 size

  Arg [1]    : none
  Example    : my $num_features = $dfs->size();
  Description: Returns the number of density features in this density feature
               set.
  Returntype : int
  Exceptions : none
  Caller     : general
  Status     : Stable

=cut

sub size {
    my $self = shift;
    return scalar @{$self->{'bin_array'}};
}

1;



