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

package App::WWW::CPAN;

use 5.006;
use strict;
use warnings;

our $VERSION = '0.011';

use parent qw( Class::Accessor );

__PACKAGE__->mk_accessors(qw( cpan home cache ));

use WWW::CPAN ();
use Data::Dump::Streamer qw( Dump );
use Path::Class qw( dir file );
use Pod::Usage;

sub parse_args {
  my $self = shift;
  my @args = @_;
  my %hash;
  for ( @args ) {
    if ( /\A ([^=]+) = (.*) \z/x ) {
      $hash{$1} = $2;
    } else {
      # FIXME warn if @args > 1
      return $_;
    }
  }
  return \%hash; 
}

sub do_cmd {
  my $self = shift;
  my $cmd  = shift;
  my $args = shift;
  my $val  = $self->cpan->$cmd( $args );
  return defined $val ? Dump( $val )->Out() : undef;
}

sub _home {
  require File::HomeDir;
  my $h = dir( File::HomeDir->my_home, '.cpanq' );
  $h->mkpath( 0, 0744 ); # quiet, rwxr--r--
  return $h;
}

sub _cache {
  my $self = shift;
  require Cache::FileCache;
  return Cache::FileCache->new({
              default_expires_in => '10 minutes',
              cache_root => dir( $self->home, 'cache2' ),
  });
}

# save last arguments and answer
sub _store {
  my $self = shift;
  my $args = shift;
  my $answer = shift;

  my $k = "@{$args}";
  $self->cache->set( $k, $answer );

}

# retrieve last answer if args are the same
sub _retrieve {
  my $self = shift;
  my $args = shift;

  my $k = "@{$args}";
  return $self->cache->get( $k );

}

my %method_for = (
   'meta'     => 'fetch_distmeta',
   'distmeta' => 'fetch_distmeta',
   'query'    => 'search',
   'search'   => 'search'
);

sub run {
  my $self = shift;
  $self->home( _home );
  $self->cache( $self->_cache );
  $self->cpan( WWW::CPAN->new );

  if ( @_ == 0 ) {
    pod2usage(1);
  }

  if ( defined( my $c = $self->_retrieve( \@_ ) ) ) {
    #warn "cache hit\n";
    print $c;
    return;
  }
  my $cmd = shift;
  if ( exists $method_for{$cmd} ) {
    my $cmd_args = $self->parse_args(@_);
    my $ans = $self->do_cmd( $method_for{$cmd}, $cmd_args );
    if ( defined $ans ) {
      $self->_store( [ $cmd, @_ ], $ans );
      print $ans;
    }
  } else {
    die "unsupported command: $cmd\n";
  }
}

1;