# Copyright (C) 2005  Joshua Hoblitt
#
# $Id: PSFTP.pm,v 1.10 2005-10-15 00:57:32 jhoblitt Exp $

package PS::IPP::PSFTP;

use strict;
use warnings FATAL => qw( all );

use vars qw( $VERSION );
$VERSION = '0.01';

use Carp qw( carp );
use Data::Validate::URI qw( is_uri );
use Digest::MD5::File qw( file_md5_hex );
use File::stat;
use LWP::UserAgent;
use Params::Validate qw( validate SCALAR UNDEF );
use POSIX;
use PS::IPP::PSFTP::Parser;
use Regexp::Common qw( number );

sub new
{
    my $class = shift;
    
    my %p = validate(@_,
        {
            base_url    => {
                type        => SCALAR,
                callbacks   => {
                    'is valid url' => sub { is_uri( $_[0] ) },
                },
            },
            recipient   => {
                type        => SCALAR,
                regex       => qr/\S+/, # string with atleast 1 non WS char
            },
        },
    );

    my $self = bless(\%p, ref ($class) || $class);

    return $self;
}

sub files_available
{
    my $self = shift;

    validate(@_, {});

    my $url = $self->{base_url}
              . "/files_available"
              . "?recipient="
              . $self->{recipient};

    my $ua = LWP::UserAgent->new;
    my $response = $ua->get( $url );

    if (! $response->is_success) {
        carp $response->status_line;
        return undef;
    }

    my $parser = PS::IPP::PSFTP::Parser->new;
    my $records = $parser->parse($response->content);

    return $records ? $records : undef;
}

sub file_received
{
    my $self = shift;

    my %p = validate(@_,
        {
            id          => {
                type        => SCALAR,
                regex       => qr/\S+/, # string with atleast 1 non WS char
            },
            discarded   => {
                type        => SCALAR,
                callbacks   => {
                    'is 0 or 1' => sub { $_[0] == 0 or $_[0] == 1 },
                },
            },
        },
    );

    my $url = $self->{base_url}
              . "/file_received"
              . "?recipient="
              . $self->{recipient}
              . "&id=" . $p{id}
              . "&discarded=" . $p{discarded};

    my $ua = LWP::UserAgent->new;
    my $response = $ua->get( $url );

    if (! $response->is_success) {
        carp $response->status_line;
        return undef;
    }

    return 1;
}

sub get_file_by_record
{
    my $self = shift;

    my %p = validate(@_,
        {
            record      => {
                isa         => 'PS::IPP::PSFTP::Record',
            },
            filename    => {
                type        => SCALAR,
                regex       => qr/\S+/, # string with atleast 1 non WS char
                callbacks   => {
                    'write access' => sub {
                        POSIX::access($_[0], &POSIX::W_OK);
                    },
                },
            },
        },
    );

    return $self->get_file(
        url         => $p{record}->url,
        size        => $p{record}->size,
        md5         => $p{record}->md5,
        filename    => $p{filename},
    );
}

sub get_file
{
    my $self = shift;

    my %p = validate(@_,
        {
            url         => {
                type        => SCALAR,
                callbacks   => {
                    'is valid url' => sub { is_uri( $_[0] ) },
                },
            },
            size        => {
                type        => SCALAR | UNDEF,
                callbacks   => {
                    'is int' => sub {
                        return 1 unless defined $_[0];
                        $_[0] =~ qr/^$RE{num}{int}$/;
                     },
                },
                optional    => 1,
            },
            md5         => {
                type        => SCALAR | UNDEF,
                callbacks   => {
                    'is hex' => sub {
                        return 1 unless defined $_[0];
                        $_[0] =~ qr/^$RE{num}{real}{-base => 16}$/;
                     },
                },
                optional    => 1,
            },
            filename    => {
                type        => SCALAR,
                regex       => qr/\S+/, # string with atleast 1 non WS char
                callbacks   => {
                    'write access' => sub {
                        POSIX::access($_[0], &POSIX::W_OK);
                    },
                },
            },
        },
    );

    my $ua = LWP::UserAgent->new;
    my $request = HTTP::Request->new(GET => $p{url});
    my $response = $ua->request($request, $p{filename});

    if (! $response->is_success) {
        carp $response->status_line;
        return undef;
    }

    if (defined $p{size}) {
        my $size = stat($p{filename})->size;
        if (! $p{size} == $size) {
            unlink $p{filename};
            carp "url: ", $p{url},
                 " - expected size: ", $p{size},
                 " got: ", $size;
            return undef;
        }
    }

    if (defined $p{md5}) {
        my $md5 = file_md5_hex($p{filename});
        if (! $p{md5} eq $md5) {
            unlink $p{filename};
            carp "url: ", $p{url},
                 " - expected md5: ", $p{md5},
                 " got: ", $md5;
            return undef;
        }
    }

    return 1;
}

1;

__END__
