The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package WWW::DuckDuckGo;
BEGIN {
  $WWW::DuckDuckGo::AUTHORITY = 'cpan:GETTY';
}
{
  $WWW::DuckDuckGo::VERSION = '0.013';
}
# ABSTRACT: Access to the DuckDuckGo APIs

use Moo;

use LWP::UserAgent;
use HTTP::Request;
use WWW::DuckDuckGo::ZeroClickInfo;
use JSON;
use URI;
use URI::QueryParam;

our $VERSION ||= '0.0development';

has _duckduckgo_api_url => (
	is => 'ro',
	lazy => 1,
	default => sub { 'http://api.duckduckgo.com/' },
);

has _duckduckgo_api_url_secure => (
	is => 'ro',
	lazy => 1,
	default => sub { 'https://api.duckduckgo.com/' },
);

has _zeroclickinfo_class => (
	is => 'ro',
	lazy => 1,
	default => sub { 'WWW::DuckDuckGo::ZeroClickInfo' },
);

has _http_agent => (
	is => 'ro',
	lazy => 1,
	default => sub {
		my $self = shift;
		my $ua = LWP::UserAgent->new;
		$ua->agent($self->http_agent_name);
		return $ua;
	},
);

has http_agent_name => (
	is => 'ro',
	lazy => 1,
	default => sub { __PACKAGE__.'/'.$VERSION },
);

has forcesecure => (
	is => 'ro',
	default => sub { 0 },
);

has safeoff => (
	is => 'ro',
	default => sub { 0 },
);

has html => (
	is => 'ro',
	default => sub { 0 },
);

sub zci { shift->zeroclickinfo(@_) }

sub _zeroclickinfo_request_base {
	my ( $self, $for_uri, @query_fields ) = @_;
	my $query = join(' ',@query_fields);
	my $uri = URI->new($for_uri);
	$uri->query_param( q => $query );
	$uri->query_param( o => 'json' );
	$uri->query_param( kp => -1 ) if $self->safeoff;
    $uri->query_param( no_redirect => 1 );
    $self->html ? 
        $uri->query_param( no_html => 0 ) : 
        $uri->query_param( no_html => 1 );
	return HTTP::Request->new(GET => $uri->as_string);
}

sub zeroclickinfo_request_secure {
	my ( $self, @query_fields ) = @_;
	return if !@query_fields;
	return $self->_zeroclickinfo_request_base($self->_duckduckgo_api_url_secure,@query_fields);
}

sub zeroclickinfo_request {
	my ( $self, @query_fields ) = @_;
	return if !@query_fields;
	return $self->_zeroclickinfo_request_base($self->_duckduckgo_api_url,@query_fields);
}

sub zeroclickinfo {
	my ( $self, @query_fields ) = @_;
	return if !@query_fields;
	my $query = join(' ',@query_fields);
	my $res;
	eval {
		$res = $self->_http_agent->request($self->zeroclickinfo_request_secure(@query_fields));
	};
	if (!$self->forcesecure and ( $@ or !$res or !$res->is_success ) ) {
		warn __PACKAGE__." HTTP request failed: ".$res->status_line if ($res and !$res->is_success);
		warn __PACKAGE__." Can't access ".$self->_duckduckgo_api_url_secure." falling back to: ".$self->_duckduckgo_api_url;
		$res = $self->_http_agent->request($self->zeroclickinfo_request(@query_fields));
	}
	return $self->zeroclickinfo_by_response($res);
}

sub zeroclickinfo_by_response {
	my ( $self, $response ) = @_;
	if ($response->is_success) {
		my $result = decode_json($response->content);
		return $self->_zeroclickinfo_class->by($result);
	} else {
		die __PACKAGE__.' HTTP request failed: '.$response->status_line, "\n";
	}	
}

1;


__END__
=pod

=head1 NAME

WWW::DuckDuckGo - Access to the DuckDuckGo APIs

=head1 VERSION

version 0.013

=head1 SYNOPSIS

  use WWW::DuckDuckGo;

  my $duck = WWW::DuckDuckGo->new;
  
  # request the Zero Click Info, you can also use ..->zci('duck duck go')
  my $zeroclickinfo = $duck->zeroclickinfo('duck duck go');

  # request the Zero Click Info of "duck duck go more stuff"
  my $other_zeroclickinfo = $duck->zeroclickinfo('duck duck go','more stuff');

=head1 DESCRIPTION

This distribution gives you an easy access to the DuckDuckGo Zero Click Info API. It tries to connect via https first and falls back to http if there is a failure.

=head1 ATTRIBUTES

=head2 forcesecure

Set to true will force the client to use https, so it will not fallback to http on failure.

=head2 http_agent_name

Set the http agent name which the webserver gets. Defaults to WWW::DuckDuckGo

=head2 safeoff

Set to true to disable safesearch.

=head2 html

Allow HTML in output. This is the default in DuckDuckGo, but not default here to maintain backwards compatibility.

=head1 METHODS

=head2 $obj->zeroclickinfo

Arguments: @query_fields

Return value: L<WWW::DuckDuckGo::ZeroClickInfo>

Returns the L<WWW::DuckDuckGo::ZeroClickInfo> of the query specified by the parameters. If you give several parameters they will get joined with an empty space.

=encoding utf8

=head1 ATTRIBUTES

=head1 METHODS

=head1 SUPPORT

IRC

  Join #duckduckgo on irc.freenode.net. Highlight Getty for fast reaction :).

Repository

  http://github.com/Getty/p5-www-duckduckgo
  Pull request and additional contributors are welcome

Issue Tracker

  http://github.com/Getty/p5-www-duckduckgo/issues

=head1 AUTHORS

=over 4

=item *

Torsten Raudssus <torsten@raudssus.de>

=item *

Michael Smith <crazedpsyc@duckduckgo.com>

=back

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011 by L<Raudssus Social Software|http://www.raudssus.de/>.

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

=cut