Merge branch 'JABAWS_Release_2_5' into develop
[jabaws.git] / binaries / src / jpred / lib / BLC.pm
diff --git a/binaries/src/jpred/lib/BLC.pm b/binaries/src/jpred/lib/BLC.pm
new file mode 100755 (executable)
index 0000000..42bf0ee
--- /dev/null
@@ -0,0 +1,263 @@
+package BLC;
+
+use strict;
+use warnings;
+use Carp;
+
+use constant {
+  ID    => 0,
+  TITLE => 1,
+  SEQ   => 2
+};
+
+=head2 my $blc = new BLC;
+
+=cut
+
+sub new {
+  my $proto = shift;
+  my $class = ref($proto) || $proto;
+  my $self  = {
+    _itteration     => 0,
+    _max_itteration => 0,
+  };
+  return bless $self, $class;
+}
+
+=head2 my $blc->read_file($file)
+
+Read in a BLC file.
+
+=cut
+
+sub read_file {
+  my @seqs;
+  my $self = shift;
+  my ($fn) = @_;
+
+  open BLC, $fn or croak "$fn: $!\n";
+
+  while (<BLC>) {
+    chomp;
+    if (s/^>//) {
+      s/\s*$//g;
+      my ( $id, $title ) = split /\s+/, $_, 2;
+      $title = '' unless $title;
+      push @seqs, [ $id, $title ];
+    }
+
+    # This regex copes with odd variations in the start of
+    # the iterations line that marks the start of sequences
+    if (/^\s*\*\s*[Ii]teration:?\s*(\d+)\s*$/) {
+
+      # The start position of the sequences is the same
+      # as the offset of the asterix from the start of
+      # the line
+      my $start = index $_, '*', 0;
+      my $iter = $1;
+      croak "Iteration not greater than 0 in BLC file $fn" unless $iter > 0;
+
+      while (<BLC>) {
+        chomp;
+        last if /^\s{$start}\*\s*$/;
+        my $line = substr $_, $start, @seqs;
+
+        foreach ( 0 .. $#seqs ) {
+
+          # Not just $iter, as we need to
+          # leave room for the title
+          # and header
+          $seqs[$_]->[ SEQ + $iter - 1 ] .= substr( $line, $_, 1 );
+        }
+      }
+    }
+  }
+  close BLC;
+  croak "No sequences found in BLC file $fn" unless @seqs;
+
+  foreach (@seqs) {
+    my ( $id, $title, @seqs ) = @{$_};
+    $title = '' unless defined $title;
+    $id    = '' unless defined $id;
+    $self->set_sequence( $id, $title, @seqs );
+  }
+}
+
+=head2 $blc->set_sequence($id, $title, @seq)
+
+Add a BLC file to the object of $id, $title and @sequence, one sequence per iteration.
+
+=cut
+
+sub set_sequence {
+  my $self = shift;
+  my ( $id, $title, @data ) = @_;
+  push @{ $self->{_seqs} }, [ $id, $title, @data ];
+}
+
+=head2 $blc->get_sequence($number)
+
+Returns a list of the ($id, $title, @sequences) where each member of @sequences 
+is from the itterations, from first to final. Defaults to the first sequences.
+
+=cut
+
+sub get_sequence {
+  my ( $self, $number ) = @_;
+  if ( defined $number and $number > $self->get_num_seqs ) {
+    croak "You're trying to retrive a sequence past than the end of the BLC file in get_sequence($number)";
+  } elsif ( defined $number and $self->get_num_seqs + $number < 0 ) {
+    croak "You're trying to retrive a sequence before the begining of the BLC file in get_sequence($number)";
+  }
+  $number = 0 unless defined $number;
+
+  return @{ ${ $self->{_seqs} }[$number] };
+}
+
+=head2 $blc->get_num_seqs()
+
+Returns the number of sequences in the BLC file.
+
+=cut
+
+sub get_num_seqs {
+  my ($self) = @_;
+  return $#{ $self->{_seqs} };
+}
+
+=head2 $blc->get_sequences($iteration)
+
+Returns all of the sequences in a block file for a particular itteration, 
+in the same order as they occured in the block file. If left undefined, 
+it will return the sequences from the first itteration.
+
+=cut
+
+sub get_sequences {
+  my ( $self, $iteration ) = @_;
+  $iteration = 0 unless $iteration and $iteration > 0;
+  return map { $_->[ SEQ + $iteration ] } @{ $self->{_seqs} };
+}
+
+=head2 $blc->get_seq_ids($number)
+
+Returns the ID for the $number sequence to occur in the file, if left undefined it'll return all of the IDs.
+
+=cut
+
+sub get_seq_ids {
+  my ( $self, $number ) = @_;
+  if ( defined $number ) {
+    return ${ $self->{_seqs}[$number] }[ID];
+  } else {
+    return map { $_->[ID] } @{ $self->{_seqs} };
+  }
+}
+
+=head2 $blc->get_seq_titles($number)
+
+Returns the titles for the number sequence to occur in the file, if left undefined it'll return all of the titles.
+
+=cut
+
+sub get_seq_titles {
+  my ( $self, $number ) = @_;
+  if ( defined $number ) {
+    return ${ $self->{_seqs}[$number] }[TITLE];
+  } else {
+    return map { $_->[TITLE] } @{ $self->{_seqs} };
+  }
+}
+
+=head2 $blc->print_blc($fh);
+
+This will print the BLC file object to the filehandle if given, otherwise to STDOUT.
+
+=cut
+
+sub print_blc {
+  my ( $self, $fh ) = @_;
+
+  if   ($fh) { *OUT = $fh }
+  else       { *OUT = *STDOUT }
+
+  # Print the IDs
+  print OUT ">$_\n" foreach $self->get_seq_ids;
+
+  # Get the sequences
+  #my @sequences = $self->get_sequences
+  my $i = 0;
+  while (1) {
+    my @sequences = $self->get_sequences($i);
+    last unless defined $sequences[0];
+    print OUT "* iteration " . ( $i + 1 ) . "\n";
+    foreach my $j ( 0 .. length( $sequences[0] ) - 1 ) {
+      foreach (@sequences) {
+        print OUT substr $_, $j, 1;
+      }
+      print OUT "\n";
+    }
+    print OUT "*\n";
+    $i++;
+  }
+}
+
+=head2 $blc->print_fasta($fh)
+
+Prints the BLC file out in FASTA format, each sequence is 72 characters wide.
+
+=cut
+
+sub print_fasta {
+  my ( $self, $fh ) = @_;
+
+  if   ($fh) { *OUT = $fh }
+  else       { *OUT = *STDOUT }
+
+  my @ids       = $self->get_seq_ids;
+  my @sequences = $self->get_sequences;
+
+  croak "Different number of sequences and IDs\n" unless @ids == @sequences;
+  foreach ( 0 .. $#ids ) {
+    print OUT ">$ids[$_]\n";
+    $sequences[$_] =~ s/(.{72})/$1\n/g;
+    print OUT "$sequences[$_]\n";
+  }
+}
+
+=head2 $blc->next_itteration;
+
+=cut
+
+sub next_itteration {
+  my ($self) = @_;
+  $self->itteration( $self->itteration + 1 );
+}
+
+=head2 $blc->next_itteration;
+
+=cut
+
+sub max_itteration {
+  my ($self) = @_;
+  return $self->{_max_itteration};
+}
+
+=head2 $blc->itteration($number)
+
+If $number is defined, sets the itteration to $number, otherwise returns the number of itterations.
+
+=cut
+
+sub itteration {
+  my ( $self, $itteration ) = @_;
+  if ( defined $itteration ) {
+    if ( $itteration < 1 ) {
+      return undef;
+    }
+  } else {
+    return $self->{_itteration};
+  }
+}
+
+1;