package WebService::Thumbalizr;

use 5.016003;
use strict;
use warnings;

use LWP::UserAgent;
use URI::Escape qw(uri_escape);
use Text::Trim;
use Digest::MD5 qw(md5_hex);

$ENV{PERL_LWP_SSL_VERIFY_HOSTNAME} = 0;
use IO::Socket::SSL;
IO::Socket::SSL::set_ctx_defaults( 
     SSL_verifycn_scheme => 'www', 
     SSL_verify_mode => 0,
     verify_mode => 0,
);

our $VERSION = '1.0.0';

=head1 NAME

WebService::Thumbalizr - Perl extension for Thumbalizr  (L<https://thumbalizr.com/>), a web service to create screenshots of web pages.

=head1 SYNOPSIS

  use WebService::Thumbalizr;
  
  my $thumbalizr = WebService::Thumbalizr->new(key => 'my_key', secret => 'my_secret');
  my $url = $thumbalizr->url('http://www.google.com/');
  my ($status, $image) = $thumbalizr->download($url);

=head1 DESCRIPTION

Thumbalizr (L<http://www.thumbalizr.com/>) is a web service to easily embed live screenshots of any URL in your website. Thumbalizr has full support for Flash, JavaScript, CSS, & HTML5.

The latest API version is detailed at L<https://www.thumbalizr.com/api/documentation>.

The source code is available on github at L<https://github.com/juliensobrier/thumbalizr-perl>.


=head1 METHODS

=over 4

=head2 new()

  my $thumbalizr = WebService::Thumbalizr->new((secret => 'my_secret', key => 'my_embed_key', debug => 1]);

Create a new WebService::Thumbalizr object. You must pass your API secret (login to your Thumbalizr account to display your secret).

Arguments:

=over 4

=item key

Required. Embed API key.

=item secret

Required.  Thumbalizr secret.

=item base

 Optional. Base URL for all API requests. You should use the default base provided by the library. Be careful if you decide to use HTTP instead of HTTPS as your API key could be sniffed and your account could be used without your consent.

=item debug

Optional. Set to 1 to print debug output to the standard output. 0 (disabled) by default.

=item timeout

Optional. Set the request timeout - in seconds - against the API. Defaults to 90s.

=back

C<last_error> contains the last error message, it is NEVER reset, i.e last_error may not be empty after a successful API call if an earlier call failed.

=cut

sub new {
  my ($self, %args) = @_;

	my $ua = LWP::UserAgent->new();
	$ua->timeout($args{'timeout'} || 90);
	$ua->env_proxy;
	$ua->agent("WebService::Thumbalizr $VERSION");
	$ua->ssl_opts( verify_hostnames => 0 );

  my $thumbalizr = {
		_key		=> trim $args{key}		|| '',
		_secret	=> trim $args{secret}	|| '',
		_base		=> $args{base}				|| 'https://api.thumbalizr.com/api/v1/',
		_debug	=> $args{debug}				|| 0,

		_retry			=> 2,
		last_error	=> '',

		_ua		=> $ua,
	};

  return bless($thumbalizr, $self);
}


=head2 url()

  my $thumbalizr = WebService::Thumbalizr->url($url, size => 'page, bwidth => 1280, bheight => 1024);

Return the Thumbalizr URL to retrieve the screenshot. See L<https://thumbalizr.com/api/documentation> for the full list of options

Arguments:

=over 4

=item url

Required. URL of the website to create a screenshot of.

=back

=cut
sub url {
	my ($self, $url, %args) = @_;
	
	my $api_key = uri_escape($self->{_key}, 1);
		
	my $query = 'url=' . uri_escape($url);

	foreach my $option (keys %args)  { 
		$query .= '&' . uri_escape(trim($option)) . '=' . uri_escape(trim $args{$option}); 
	}
	
	my $token = md5_hex($query . $self->{_secret});
	
	return $self->{_base} . "embed/$api_key/$token/?$query";
}

=head2 download()

	my ($status, $image) = $thumbalizr->download($url);

Download a screenshot. Optionally, you can save the image directly to a file.

Return the status of the screenshot (OK, FAILED or QUEUED), and the image data or image file name. In case the screenshto is not finished, the image data will be empty.

Arguments:

=over 4

=item

Required. Thumbalizr Embed URL generated by $tumbalizr->url

=item

Optional  A local file name to save the image to.

=back

=cut
sub download {
	my ($self, $url, $file) = @_;

	my $res;
	my $try = 0;

	do {
		$self->info("Try $try");
		eval {
			$res = $self->{_ua}->get($url);
		};
		$self->error($@) if ($@);
		$try++;
	}
	until($try < $self->{_retry} && defined $@);

	if (! $res->is_success) {
		$self->error("Server sent back an error: " . $res->code);
		return ('FAILED', '');
	}
	
	my $status = $res->header('X-Thumbalizr-Status') || 'FAILED';
	if ($status eq 'FAILED') {
		$self->error($res->header('X-Thumbalizr-Error'));
	}
	
	if (defined($file) && $file ne '') {
		if ($status ne 'OK') {
			return ($status, '');
		}
		
		open TARGET, "> $file" or $self->error("Cannot open $file for writing: $!");
		binmode TARGET;
		print TARGET $res->decoded_content;
		close TARGET;
	
		return ($status, $file);
	}
	
	return ($status, $res->decoded_content);
}



=head2 download_wait()

	my ($status, $image) = $thumbalizr->download_wait($url);

Download a screenshot. Optionally, you can save the image directly to a file. Unlike the  C<download()> function, C<download_wait()> will attempt to retrieve the screenshot until it is either finished (OK) or failed 
(FAILED).

Return the status of the screenshot (OK, FAILED ), and the image data or image file name. In case the screenshot is not finished, the image data will be empty.

Arguments:

=over 4

=item

Required. Thumbalizr Embed URL generated by $tumbalizr->url

=item

Optional  A local file name to save the image to.


=item

Optional  The number of seconds to wait between 2 tries. 10 by default.

=back

=cut
sub download_wait {
	my ($self, $url, $file, $wait) = @_;
	$wait ||= 10;
	
	$self->info("Wait $wait s");
	
	my ($status, $result) = $self->download($url, $file);
	while ($status eq 'QUEUED') {
		$self->info("Status: $status");
		sleep $wait;
		($status, $result) = $self->download($url, $file);
	}
	
	return ($status, $result);
}


sub info {
	my ($self, $message) = @_;

	if ($self->{_debug}) {
	  print "Error: $message\n";
	}

	return '';
}

sub error {
	my ($self, $message) = @_;

	$self->{last_error} = $message;

	if ($self->{_debug}) {
		print $message, "\n";
	}

	return '';
}

1;
__END__

=back

=back

=head1 SEE ALSO

See L<https://thumbalizr.com/api/documentation> for the API documentation.

Create a free account at L<https://thumbalizr.com/member> to get your free API key.

Go to L<https://thumbalizr.com/member> to find your API key and secret after you registered.

=head1 AUTHOR

Julien Sobrier, E<lt>julien@sobrier.netE<gt>

=head1 COPYRIGHT AND LICENSE

Copyright (C) 2019 by Julien Sobrier

This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.8.8 or,
at your option, any later version of Perl 5 you may have available.


=cut
