The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
# -*-CPerl-*-
# Last changed Time-stamp: <2017-06-10 19:02:34 michl>

package Bio::ViennaNGS::FeatureChain;

use Bio::ViennaNGS;
use Carp;
use Moose;
use Data::Dumper;
use version; our $VERSION = version->declare("$Bio::ViennaNGS::VERSION");

with 'MooseX::Clone';

has 'type' => (
	       is => 'rw',
	       isa => 'Str', # [exon,intron,SJ,promoter,TSS,...]
	      );

has 'chain' => (
		is => 'rw',
		traits => ['Array', 'Clone' => {to=>'ArrayRef'}],
		isa => 'ArrayRef[Bio::ViennaNGS::Feature]',
		default => sub { [] },
		predicate => 'has_chain',
		auto_deref => 1,
		handles => {
			    all    => 'elements',
			    count  => 'count',
			    add    => 'push',
			    pop    => 'pop',
			    shift_chain => 'shift',
			    sip    => 'sort_in_place',
			   },
	       );

has 'start' => (
		is => 'ro',
		isa => 'Int',
		predicate => 'has_start',
		);

has '_entries' => (
		   is => 'rw',
		   isa => 'Int',
		   predicate => 'nr_entries',
		   init_arg => undef, # make this unsettable via constructor
		   builder => 'count_entries',
		   lazy => 1,
		  );

#has 'foo' => (
#	      is => 'ro',
#	      isa => 'Str',
#	      default => "AAA",
#	     );

sub BUILD {
  my $self = shift;
  my $this_function = (caller(0))[3];
 # carp"INFO [$this_function]";
  confess "ERROR [$this_function] \$self->chain not available"
    unless ($self->has_chain);
  $self->count_entries();
}

sub count_entries {
  my $self = shift;
  my $cnt = scalar @{$self->chain};
  $self->_entries($cnt);
}

before 'as_bed12_line' => sub {
  my $self = shift;
  my $this_function = (caller(0))[3];
  $self->sip( sub { $_[0]->start <=> $_[1]->start} )
};

sub sort_chain_ascending {
  my $self = shift;
  my $this_function = (caller(0))[3];
  $self->sip( sub { $_[0]->start <=> $_[1]->start} )
}

sub as_bed12_line{
  my ($self,$name,$score,$strand) = @_;
  my ($i,$chr,$start,$end,$feat,$bed12,$bsizes,$bstarts);
  my $count=0;
  my @blockSizes = ();
  my @blockStarts = ();
  # TODO check whether all features have the same chromosome id
  $chr   = @{$self->chain}[0]->chromosome;
  $start = @{$self->chain}[0]->start;
  $end   = @{$self->chain}[$#{$self->chain}]->end;
  unless (defined $name){$name=@{$self->chain}[0]->name;}
  unless (defined $score){$score=@{$self->chain}[0]->score;}
  unless (defined $strand){$strand=@{$self->chain}[0]->strand;}

  # TODO populate blockSizes and blockStarts
  for ($i=0;$i<=$#{$self->chain};$i++){
    $count++;
    $feat = @{$self->chain}[$i];
    push @blockSizes, eval($feat->end - $feat->start);
    push @blockStarts, ($feat->start - $start);;
  }
  $bsizes = join (",",@blockSizes);
  $bstarts = join (",", @blockStarts);
  $bed12 = join ("\t",$chr,$start,$end,$name,$score,$strand,$start,$end,"0",$count,$bsizes,$bstarts);
  return $bed12;
}

sub as_bed6_array{
  my $self = shift;
  $self->count_entries();
  my @bed6array=();
  return 0 unless ($self->has_chain);
  for (my $i=0;$i<$self->_entries;$i++){
    push @bed6array, join ("\t", 
			   @{$self->chain}[$i]->chromosome,
			   @{$self->chain}[$i]->start,
			   @{$self->chain}[$i]->end,
			   @{$self->chain}[$i]->name,
			   @{$self->chain}[$i]->score,
			   @{$self->chain}[$i]->strand);
  }
  return \@bed6array;
}

#sub clone {
#  my ( $self, %params ) = @_;
#  $self->meta->clone_object($self, %params);
#  return $self;
#}

no Moose;

1;

__END__

=head1 NAME

Bio::ViennaNGS::FeatureChain - Generic Moose wrapper class for
combined/linked genomic intervals, eg BED12 elements

=head1 SYNOPSIS

  use Bio::ViennaNGS::Feature;
  use Bio::ViennaNGS::FeatureChain;

  # get some new sequence features as instances of Bio::ViennaNGS::Feature
  my $start1 = 1100; my $start2 = 2345; my $start3 = 2987;
  my $end1 = 1346; my $end2 = 2544; my $end3 = 3076;
  my $name1 = "feat1"; my $name2 = "feat2"; my $name3 = "feat3";
  my $strand = "+";
  my $chr = "chr1";
  my $feat1 = Bio::ViennaNGS::Feature->(chromosome => $chr,
                                        start => $start1,
                                        end => $end1,
                                        name => $name1,
                                        strand => $strand,
                                        );
   my $feat2 = Bio::ViennaNGS::Feature->(chromosome => $chr,
                                        start => $start2,
                                        end => $end2,
                                        name => $name2,
                                        strand => $strand,
                                        );
   my $feat3 = Bio::ViennaNGS::Feature->(chromosome => $chr,
                                        start => $start3,
                                        end => $end3,
                                        name => $name3,
                                        strand => $strand,
                                        );

  # initialize a FeatureChain for two of these intervals
  my $fc = Bio::ViennaNGS::FeatureChain->new(type => "exon",
                                             chain => [$feat1,$feat3],
                                            );

  # append a genomic intervald to the chain
  $fc->add($feat2);

  # sort the chain in ascending order by start coordinates 
  $fc->sort_chain_ascending();

  # get the number of elements in the chain
  $fc->count_entries();


=head1 DESCRIPTION


=head1 METHODS

=over

=item sort_chain_ascending

=item as_bed12_line

=item as_bed6_array

=back

=head1 DEPENDENCIES

=over

=item L<Carp>

=back

=head1 AUTHORS

Michael T. Wolfinger E<lt>michael@wolfinger.euE<gt>

=head1 COPYRIGHT AND LICENSE

Copyright (C) 2014-2017 Michael T. Wolfinger E<lt>michael@wolfinger.euE<gt>

This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.10.0 or,
at your option, any later version of Perl 5 you may have available.

This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.


=cut