#!/usr/bin/perl

use strict;
use warnings;

use Getopt::Long;
use Data::Dumper;
use Pod::Usage;

# getopt std supports --version
use Froody;
$main::VERSION = $Froody::VERSION;

use Froody::Dispatch;
use Froody::Response::Terse;
use Froody::Response::PerlDS;

# process command line options;
# darn! Neither GetOpt::Std or GetOpt::Long do what I want
my @modules;
my @urls;
my $yaml;
my $format;
my $dump;
my $n = 1;
my $bench;
my $quiet;
my $standalone;
while (defined($ARGV[0]) && $ARGV[0] =~ /^-/)
{
   my $arg = shift;

   if ($arg =~ /^-n(.*)$/)
   {
     $n = $1;
     die "-n requires argument. Try -h for help.\n" unless length $n;
     die "-n takes only a number. Try -h for help.\n" unless length $n =~ /^\d+$/;
     next;
   }

   if ($arg =~ /^-M(.*)$/)
   {
     die "-M requires argument. Try -h for help.\n" unless length $1;
     push @modules, $1;
     next;
   }
   
   if ($arg =~ /^-[lI]=?(.*)$/)
   {
     die "-l requires argument. Try -h for help.\n" unless length $1;
     push @INC, $1;
     next;
   }

   if ($arg =~ /^-u=?(.*)$/)
   {
     die "-u requires argument. Try -h for help.\n" unless length $1;
     push @urls, $1;
     next;
   }

   if ($arg =~ /^-p(.*)$/)
   {
     die "-p takes no arguments. Try -h for help.\n" if length $1;
     $format = "as_perlds";
     next;
   }

   if ($arg =~ /^-t(.*)$/)
   {
     die "-t takes no arguments. Try -h for help.\n" if length $1;
     $format = "as_terse";
     next;
   }

   if ($arg =~ /^-b(.*)$/)
   {
     die "-b takes no arguments. Try -h for help.\n" if length $1;
     $bench = 1;
     next;
   }

   if ($arg =~ /^-q(.*)$/)
   {
     die "-q takes no argument. Try -h for help.\n" if length $1;
     $quiet = 1;
     next;
   }
   
   
   if ($arg =~ /^-y(.*)$/)
   {
     die "-y takes no argument. Try -h for help.\n" if length $1;
     require YAML::Syck
       or die "Need YAML::Syck installed to use -y\n";
     $yaml = 1;
     next;
   }
   
   if ($arg =~ /^-d(.*)$/)
   {
     die "-d takes no argument. Try -h for help.\n" if length $1;
     $dump = 1;
     next;
   }
   
   if ($arg =~ /^-s(.*)$/)
   {
     $standalone = 4242;
     $standalone = $1 if $1;
     next;
   }
   
   if ($arg =~ /^(--?v(?:ersion)?)(.*)?$/)
   {
    die "$1 takes no argument. Try -h for help.\n" if length $2;
    print "Froody Version $main::VERSION\n";
    print "It's ".localtime()."...do you know where your towel is?\n";
    exit;
   }
   
   if ($arg =~ /^(--?h(?:elp)?|--?\?)(.*)?$/)
   {
    die "$1 takes no argument. Try -h for help.\n" if length $2;
    pod2usage({ -exitval => 0, -verbose => 1 });
   }

   print STDERR "Unknown arg '$arg'\n";   
   pod2usage({ -exitval => 0, -verbose => 0 });
}

# check we got something that's loading modules
# (unless we're looking at reflection, as then we don't have to bother
unless (@modules || @urls || $dump || $standalone || @ARGV && $ARGV[0] =~ m{\.reflection\.})
{ 
  print STDERR "You need to use either -u or -M\n";
  pod2usage({ -exitval => 1, -verbose => 0 });
}

my $client = Froody::Dispatch->config({
  urls => \@urls,
  modules => \@modules
});
$client->error_style('response');

if ($dump)
{
  foreach (sort map { $_->full_name } $client->repository->get_methods())
   { print "$_\n" }
  exit;
}

if ($standalone)
{
  use Froody::Server::Standalone;
  my $server = Froody::Server::Standalone->new();
  $server->port($standalone);
  $server->run;
}

my $method = shift @ARGV
  or die "Must provide a method name. Try -h for help.\n";

if (@ARGV % 2)
  { die "Odd number of parameters passed in. Try -h for help.\n" }


my $time;
$time = [Time::HiRes::gettimeofday()] if $bench;

foreach my $fish (1..$n)
{  
  # get the response
  my $response = $client->call($method, { @ARGV });
  
  if ($format)
  {
    $response = $response->$format;
    if ($yaml)
     { $_ = Dump($response->content) }
    else
     { $_ = Dumper($response->content) }
  }
  else
   { $_ = $response->render; }
   
  print unless $quiet;
}

print "Took ".Time::HiRes::tv_interval($time)." seconds to make $n calls to $method\n" if $bench;

=head1 NAME

froody - command line for Froody

=head1 SYNOPSIS

   bash$ froody -uhttp://foo.com/fe examples.myapi.greet who Mark

=head1 DESCRIPTION

Command line client for Froody.

=head1 OPTIONS

=over

=item  -uhttp://myurl.com
  
Loads the API via that URL's reflection service and allows you to
call methods against it.  You can specify this flag multiple times
for different URLs.

=item -Mmodulename
  
Loads the module.  If this is a subclass of Froody::Implementation
this allows you to call methods that this module implements.  You can
specify this flag multiple times for different modules.

=item -lpath or -Ipath
  
Add this path to @INC.

=item -t
  
Print out the data in the Terse data format rather than printing the XML
  
=item -p
  
Print out the data in the PerlDS data format rather than printing the XML
  
=item -y
  
Use YAML instead of Data::Dumper when printing data with C<-t> or C<-p>.
Prints an error if YAML isn't installed.

=item -b
  
Benchmark requests.  Prints out how long the request takes after all local
code has been loaded and remote reflection calls have been run.
  
=item -nnumber

Repeat the request a number of times.  Useful for crude benchmarking.

=item -q

Quiet mode.  Don't actually print out the output of the method.

=item -d
  
Dump out the names of all the loaded methods instead of running a method

=item -sportnum

Start a standalone server on the port passed.  Defaults to 4242 if
no port is specified

=item -imodulename

Print the specification for the given Froody::Method rather than running a
method

=item -v or --version
  
Shows the version of Froody installed on the system

=item -h or --help or -?
  
Shows this help message

=back


