#
# Perl Module for GFFPair
#
# Cared for by Tim Hubbard <th@sanger.ac.uk>
#
# Copyright Genome Research Limited (1997). Please see information on licensing in LICENSE

package GFFPair;

use vars qw($AUTOLOAD @ISA @EXPORT_OK);
use Exporter;
use Carp;
use strict;
use GeneFeature;
use GeneFeaturePair;

#
# Place functions/variables you want to *export*, ie be visible from the caller package into @EXPORT_OK
#

@EXPORT_OK = qw();

#
# @ISA has our inheritance.
#

@ISA = ( 'Exporter' );

my %fields = (
	      feature => undef, # going to be an array of GeneFeatures
	      filename => undef
	      );

#
# creates a new object
#

sub new {
    my $ref = shift;
    my $class = ref($ref) || $ref;
    
    my $self = {
	'_permitted' => \%fields,
	%fields, };

    $self->{'feature'} = []; # makes feature an anonymous array.
    bless $self, $class;
    return $self;
}

#
# Autoload up my field name set/get
#

sub AUTOLOAD {
    my $self = shift;
    my $type = ref($self) || carp "Ok, $self is not an object of mine!";
    my $name = $AUTOLOAD;

    # don't propagate DESTROY messages...

    $name =~ /::DESTROY/ && return;

    $name =~ s/.*://; #get only the bit we want
    unless (exists $self->{'_permitted'}->{$name} ) {
	carp "In type $type, can't access $name - probably passed a wrong variable into Sequence  ";
    }
    if (@_) {
	return $self->{$name} = shift;
    } else {
	return $self->{$name}
    }
}

#
# Method to add a reference to a GeneFeaturePair object to a GFFPair object
#

sub addGeneFeature {
    my $self = shift;
    my $gf = shift;
    my $function = shift;

    if(!$function || &$function($gf)){
	push( @{$self->{'feature'}}, $gf);
    }
}

# 
# Method to return an array of refs to the GeneFeatures in a GFFPair object
#

sub eachGeneFeature {
    my $self = shift;
    my @array;
    my $gf;

    foreach $gf ( @{$self->{'feature'}} ){
	push(@array,$gf);
    }
    return @array;
}

#
# Method to create GeneFeaturePair object for each line of a stream from a GFFPair format file
# and add references to them to the GFFPair object
#

sub read {
    my $self = shift;
    my $file = shift;
    my $function = shift;
    my ($gf,$count);

    $count = 0;

    if( !defined $file ) {
	carp("sorry - can't read a GFFPair with no file!");
	return 0;
    }

    # loop over file, make new gf objects and add them

    while( <$file> ) {
	chomp($_);

	/^#/ && next;
	$gf = &GeneFeaturePair::new_from_line($_);

	$self->addGeneFeature($gf,$function);
	
	$count++;
    }

    return $count;
}

#
# Method to dump out a GFFPair object, via method to dump out a GeneFeaturePair object.
#
    
sub dump {
    my $self = shift;
    my $file = shift;
    my $tab = shift;
    my $gf;
#    print "in GFFPair::dump\n";

    foreach $gf ( $self->eachGeneFeature() ) {
	$gf->dump($file,$tab);
    }
    
}

#
# Method to generate a new GFFPair object based on a filtered version of the object.
# Filtering is carried out by passing a reference to a subroutine, which is applied
# to each GeneFeaturePair object.
#

sub filter {
    my $self = shift;
    my $function = shift;
    my $gf;

    my $new = new GFFPair;
    
    foreach $gf ($self->eachGeneFeature()){
	$new->addGeneFeature($gf,$function);
    }
    $new;
}

#
# Method to count the number of GeneFeaturePair objects in a GFFPair object
#

sub count {
    my $self = shift;
    my $gf;
    my $count;

    $count=0;
    foreach $gf ($self->eachGeneFeature()){
	$count++;
    }
    $count;
}

#
# Method to generate a new GFFPair object which is a union of 2 GFFPair objects
#

sub union {
    my $self = shift;
    my $other = shift;

    my $new = new GFFPair;
    my $gf;

# first add everything in 1st object
    foreach $gf ($self->eachGeneFeature()){
	$new->addGeneFeature($gf);
    }

# second add everything in 2nd object but not in 1st object
    foreach $gf ($other->eachGeneFeature()){
	unless($self->member($gf)){
	    $new->addGeneFeature($gf);
	}
    }
    $new;
}

#
# Method to test if a GeneFeaturePair object is a member of an existing GFFPair object
# (note - comparison is by reference only - does not check if 2 GeneFeaturePair objects
#  contain the same data!)
#

sub member {
    my $self = shift;
    my $element = shift;
    my ($gf,$flag);
    $flag=0;
    foreach $gf ($self->eachGeneFeature()){
	if($gf == $element){
	   $flag=1;
	   last;
       }
    }
    $flag;
}

#
# Method to get scores for a set of GeneFeaturePair objects
#

sub score {
    my $self = shift;
    my $tolerance = shift;
    my $nep = shift;
    my $net = shift;

    my($no,$ne,$n5,$n3,$c,$gf);
    foreach $gf ($self->eachGeneFeature()){
	$no++;
	$c=0;
	if(abs($gf->e3)<=$tolerance){
	    $n3++;
	    $c++;
	}
	if(abs($gf->e5)<=$tolerance){
	    $n5++;
	    $c++;
	}
	if($c==2){
	    $ne++;
	}
    }
    $ne,$ne/$nep,$ne/$net,
    $no,$no/$nep,$no/$net,
    $n5,$n5/$nep,$n5/$net,
    $n3,$n3/$nep,$n3/$net;
}


1;  # says use was ok
__END__

=head1 NAME

GFFPair.pm

=head1 DESCRIPTION

B<GFFPair> is a Perl Object for Gene Finding Feature Pair format (see
http://www.sanger.ac.uk/Users/rd/gff.html for GFFPair specification).  A
GFFPair object is a set of GeneFeaturePair objects (see
GeneFeaturePair.pm).

=head1 AUTHOR

B<Tim Hubbard> Email th@sanger.ac.uk

=over

=item addGeneFeature

Method to add a reference to a GeneFeaturePair object to a GFFPair object

=item eachGeneFeature

Method to return an array of refs to the GeneFeaturesPair in a GFFPair object

=item read

Method to create GeneFeaturePair object for each line of a stream from a
GFFPair format file and add references to them to the GFFPair object

=item dump

Method to dump out a GFFPair object, via method to dump out a GeneFeaturePair object.

=item filter

Method to generate a new GFFPair object based on a filtered version of the
object.  Filtering is carried out by passing a reference to a
subroutine, which is applied to each GeneFeaturePair object.

=item count

Method to count the number of GeneFeaturePair objects in a GFFPair object

=item union

Method to generate a new GFFPair object which is a union of 2 GFFPair objects

=item member

Method to test if a GeneFeaturePair object is a member of an existing GFFPair
object (note - comparison is by reference only - does not check if 2
GeneFeaturePair objects contain the same data!)

=item score

No current documentation
