=head1 NAME

Script::FlatFileToJson::FeatureStream::BioPerl - feature stream class
for working with BioPerl seqfeature objects

=cut

package Bio::JBrowse::FeatureStream::BioPerl;
use strict;
use warnings;
use base 'Bio::JBrowse::FeatureStream';

use List::MoreUtils 'uniq';

sub next_items {
    my ( $self ) = @_;
    return map $self->_bp_to_hashref( $_ ),
           $self->{stream}->();
}

# downconvert a bioperl feature object back to bare-hashref-format
sub _bp_to_hashref {
    my ( $self, $f ) = @_;
    no warnings 'uninitialized';

    my %h = (
        seq_id => scalar $f->seq_id,
        start  => scalar $f->start,
        end    => scalar $f->end,
        strand => scalar $f->strand,
        source => scalar $f->source_tag,
        phase  => {0=>0,1=>1,2=>2}->{$f->phase},
        type   => ( $f->primary_tag || undef )
    );

    if( $f->can('score') ) {
        $h{score} = $f->score;
    }
    for(qw( seq_id start end strand source type )) {
        if( $h{$_} eq '.' ) {
            delete $h{$_};
        }
    }
    for ( keys %h ) {
        if( ! defined $h{$_} ) {
            delete $h{$_};
        } else {
            $h{$_} = [ $h{$_} ];
        }
    }
    my @subfeatures = $f->get_SeqFeatures;
    if( @subfeatures ) {
        $h{subfeatures} = [[ map $self->_bp_to_hashref($_), @subfeatures ]];
    }

    for my $tag ( $f->get_all_tags ) {
        my $lctag = lc $tag;
        push @{ $h{ $lctag } ||= [] }, $f->get_tag_values($tag);
    }

    for ( keys %h ) {
        $h{$_} = [ uniq grep { defined && ($_ ne '.') } @{$h{$_}} ];
        unless( @{$h{$_}} ) {
            delete $h{$_};
        }
    }

    if( ! $h{name} and defined( my $label = $self->_label( $f ) )) {
        $h{name} = [ $label ];
    }

    return $self->_flatten_multivalues( \%h );
};

sub _label {
    my ( $self, $f ) = @_;
    if( $f->can('display_name') and defined( my $dn = $f->display_name )) {
        return $dn
    }
    elsif( $f->can('get_tag_values') ) {
        my $n = eval { ($f->get_tag_values('Name'))[0] };
        return $n if defined $n;

        my $a = eval { ($f->get_tag_values('Alias'))[0] };
        return $a if defined $a;
    }
    elsif( $f->can('attributes') ) {
	return $f->attributes('load_id') if defined $f->attributes('load_id');
	return $f->attributes('Name')    if defined $f->attributes('Name');
	return $f->attributes('Alias')   if defined $f->attributes('Alias');
    }
    return;
}

1;
