The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
=head1 NAME

Froody::SimpleClient

=head1 SYNOPSIS

=head1 DESCRIPTION

=cut

package Froody::SimpleClient;
use warnings;
use strict;
use base qw( Class::Accessor::Chained::Fast );
__PACKAGE__->mk_accessors(qw( endpoint ));

use LWP::UserAgent;
use JSON::XS qw( from_json );
use HTTP::Request::Common;
use Encode qw( encode_utf8 );

=head1 ATTRIBUTES

=over

=item endpoint

=back

=head1 METHODS

=over

=item new( endpoint, [ timeout => 30 ] )

We take an endpoint here. Optionally, we also take a timeout in seconds.

=cut

sub new {
  my $class = shift;
  my $endpoint = shift;
  my $self = $class->SUPER::new({ endpoint => $endpoint });
  $self->{ua} = LWP::UserAgent->new( @_ );
  return $self;
}

=item call( method, arg => value, arg => value, etc... )

=cut

sub call {
  my $self = shift;
  my $method = shift;
  my %args = ref $_[0] eq 'HASH' ? %{ $_[0] } : @_;

  # we want json
  $args{_type} = "json";

  my $response = $self->call_raw($method, %args);
  # parse as Frooy/JSON response
  my $data = eval { from_json( $response ) };
  unless (ref $data eq "HASH") {
    die "Error parsing ".$response.": $@";
  }
  unless ($data->{stat} eq 'ok') {
    my $error = $data->{data};
    Froody::Error->throw(delete $error->{code}, delete $error->{msg}, $error);
  }
  return $data->{data};
}

=item call_raw( method, args )

makes a raw call, returns the exact thing returned by the server.

=cut

sub call_raw {
  my $self = shift;
  my $method = shift;
  my %args = ref $_[0] eq 'HASH' ? %{ $_[0] } : @_;
  
  die "no endpoint set" unless $self->endpoint;
  die "no UA" unless $self->{ua};

  # fudge args so we can do the Right Thing with lists and uploads.
  my $hash_expansion;
  for (keys %args) {
    my $value = $args{$_};
    if (!defined $value) {
      delete $args{$_};
      next;
    }

    my $ref = ref($value);
    if ($ref eq 'ARRAY' and ref $value->[0] eq 'Froody::Upload') {
      # upload
      $args{$_} = [ $value->[0]->filename, $value->[0]->client_filename ];
      die "too many uploads" if $value->[1];

    } elsif ($ref eq 'ARRAY') {
      # just CSV
      $args{$_} = join(",", @$value );

    } elsif ($ref eq 'HASH') {
      die "too many arguments of type 'remaining'; previous was '$hash_expansion' and current is '$_'"
        if $hash_expansion;
      $hash_expansion = $_;
      my $blah = delete $args{$_};
      %args = ( %args, %$blah );

    } elsif ($ref) {
      die "can't handle type of argument '$_' (is a ".ref($args{$_}).")";
    }
  }
  
  my @args = %args;
  @args = map { ref($_) ? $_ : Encode::encode('utf-8', $_) } @args;
  %args = @args;

  # make the request
  my $request = POST( $self->endpoint,
    Content_Type => 'form-data',
    Content => [ method => $method, %args ] );

  my $response = $self->{ua}->request( $request );

  Froody::Error->throw('froody.invoke.remote', 'Bad response from server: '. $response->status_line)
    unless $response->is_success;

  return $response->content;
}

=back

=head1 AUTHOR

Copyright Fotango 2005.  All rights reserved.

Please see the main L<Froody> documentation for details of who has worked
on this project.

This module is free software; you can redistribute it and/or modify it under
the same terms as Perl itself.

=cut

1;