package P2P::Transmission::Torrent;

=head1 NAME

P2P::Transmission::Torrent - Transmission Torrent object

=head1 DESCRIPTION

C<P2P::Transmission::Torrent> objects are generated by the
C<lookup()> and C<torrents()> methods of the parent class 
C<P2P::Transmission>. With the exception of the C<start>,
C<stop>, and C<remove> methods, this subclass is a read-only
representation of a currently active torrent.

The two types of read-only methods implemented by this class
are B<info> methods which relate to information contained
in the .torrent file and B<status> methods which relate
to information about the download itself.

Unless otherwise noted, the read-only accessors return a
scalar value on success or undef on failure.

=cut

use Carp;
use strict;

our $VERSION = '0.02';
our $AUTOLOAD;
our @SIMPLE  = qw/remove start stop/;
our %TYPES   = (
    # attributes that can be fetched using 'get-info'
    hash     => 'info',
    name     => 'info',
    path     => 'info',
    saved    => 'info',
    private  => 'info',
    comment  => 'info',
    creator  => 'info',
    date     => 'info',
    size     => 'info',
    files    => 'info',
    # attributes that can be fetched using 'get-status'
    completed         => 'status',
    download_speed    => 'status',
    download_total    => 'status',
    error             => 'status',
    error_message     => 'status',
    eta               => 'status',
    peers_downloading => 'status',
    peers_from        => 'status',
    peers_total       => 'status',
    peers_uploading   => 'status',
    running           => 'status',
    state             => 'status',
    swarm_speed       => 'status',
    tracker           => 'status',
    scrape_completed  => 'status',
    scrape_leechers   => 'status',
    scrape_seeders    => 'status',
    upload_speed      => 'status',
    upload_total      => 'status'
);

sub new {
    my ($class, %data) = @_;
    my $self = bless(\%data, $class);
    return $self;
}

# we have to handle the 'trackers' info message without using the
# AUTOLOAD code since it's the one edge case where bdecode gives
# us a data structure that's unnecissarily deep.
sub trackers {
    my $self   = shift;
    my $parent = $self->{parent};
    
    # perform the fetch
    $parent->_send( ["get-info", {   id => [ $self->{info}->{id} ], 
                                     type => [ 'trackers' ] }, 1 ] );
    my $r = $parent->_recv;
    
    if ($r->[0] eq 'info') {
        # return the first subarray of the result
        return $r->[1][0]->{trackers}->[0];
    } else {
        return undef;
    }
}

sub _action {
    my ($self, $action) = @_;
    my $parent = $self->{parent};

    $parent->_send([$action, [ $self->{info}->{id} ], 1]);
    return ($parent->_recv->[0] eq 'succeeded') ? 1 : undef
}

sub _attrib {
    my ($self, $attrib) = @_;
    my $parent = $self->{parent};
    
    # get attribute type
    my $type = $TYPES{$attrib};

    # convert underscores to dashes
    $attrib =~ s/_/-/;

    # perform the fetch
    $parent->_send( ["get-$type", {   id => [ $self->{info}->{id} ], 
                                       type => [ $attrib ] }, 1 ] );
    my $r = $parent->_recv;
    
    if ($r->[0] eq $type) {
        return $r->[1][0]->{$attrib};
    } else {
        return undef;
    }
}

# AUTOLOAD routes methods to either the _action handler
# or the _attrib handler depending on the method called
sub AUTOLOAD {
    # get bare method name
    my ($method) = ($AUTOLOAD) =~ /^.*::(\w+)$/;
    my $self = shift;

    # keys in %TYPES are read-only attributes
    if (exists $TYPES{$method})
    {
        return $self->_attrib($method);
    }
    
    # members in @SIMPLE are write-only actions
    if (grep $_ eq $method, @SIMPLE)
    {
        return $self->_action($method);
    }
    
    # unknown methods get an emulated perl error
    croak("Can't locate object method \"$method\" via package ".__PACKAGE__);
}

sub DESTROY { }

1;

__END__

=head1 METHODS

=over 4

=item C<remove>

Unload this torrent from Transmission.

=item C<start>

Activate this torrent

  Note: has no effect if torrent is running
  
=item C<stop>

Deactivates this torrent

  Note: has no effect if torrent isn't running

=back

=head1 INFO METHODS

  descriptions taken from transmission/doc/ipcproto.txt

=over 4

=item C<comment>

string, comment from torrent file

=item C<creator>

string, creator of torrent file

=item C<date>

integer, date of torrent creation (unix time_t format)

=item C<files>

array of hashes, keyed by C<name> and C<size>

=item C<hash>

string, SHA-1 info hash in hex (unique identifier)

=item C<name>

string, torrent name

=item C<path>

string, path to .torrent file

=item C<private>

boolean, true if the torrent is private

=item C<saved>

boolean, true if a copy of this torrent was saved

=item C<size>

integer, total size of all files in bytes

=item C<trackers>

array of hashes, keyed by C<announce>, C<address>, C<port>, and C<scrape>

  Note: this method represents the available trackers

=back

=head1 STATUS METHODS

=over 4

=item C<completed>

integer, bytes of data downloaded and verified

=item C<download_speed>

integer, download speed in bytes per second

=item C<download_total>

integer, total bytes downloaded so far

=item C<error>

string, see ipcproto.txt for more info

=item C<error_message>

string, printable error message

=item C<eta>

integer, estimated seconds until downloading is finished

=item C<peers_downloading>

integer, peers downloading from us

=item C<peers_from>

hash, keyed by C<tracker>, C<incoming>, C<pex>, and C<cache>

=item C<peers_total>

integer, total connected peers

=item C<peers_uploading>

integer, peers uploading to us

=item C<running>

boolean, false if torrent is stopped or stopping

=item C<scrape_completed>

integer, total completed peers as reported by tracker

=item C<scrape_leechers>

integer, current leechers as reported by tracker

=item C<scrape_seeders>

integer, current, seeders as reported by tracker

=item C<state>

string, see ipcinfo.txt for more info

=item C<swarm_speed>

integer, swarm speed in bytes per second

=item C<tracker>

hash, keyed by C<announce>, C<address>, C<port>, and C<scrape>

 Note: this method represents the active tracker

=item C<upload_speed>

integer, upload speed in bytes per second

=item C<upload_total>

integer, total bytes uploaded so far

=back

=head1 SEE ALSO

L<P2P::Transmission>

=head1 AUTHOR

Brandon Gilmore, E<lt>brandon@mg2.orgE<gt>

=head1 COPYRIGHT AND LICENSE

Copyright (C) 2007 Brandon Gilmore

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

=cut
