#!/usr/bin/perl -w
use strict;
use URI;
use LWP::Simple;
use Net::Amazon;
use XML::Simple;
use constant AMAZON_TOKEN => 'tutaj twj klucz';
use constant DEBUG => 0;

# pobieranie argumentw. Pierwszy to pobierany
# adres URL, drugi to dane wynikowe.
my $url = shift || die "$0 <url> [<output>]\n";
my $output = shift || '/www/htdocs/cloud.html';

# w kocu trzeba bdzie pobra XML z Alexy, i to 
# kilkukrotnie, wic tworzymy stosown procedur. Korzystajc
# z moduu URI moemy prawidowo zakodowa URL zapytania. 
# Tak naprawd wiksza cz funkcji jest temu wanie 
# zadaniu powicona, a pod sam koniec uywamy LWP::Simple 
# do pobrania i zwrcenia XML.
#####################################################
sub fetch_xml {
    my $url = shift;
    $url = "http://$url" unless $url =~ m[^http://];
    warn "Pobieranie danych z Alexa dla $url\n" if DEBUG;

    my @args = (
        cli => 10,     dat => 'snba',
        ver => '7.0',  url => $url,
    );

    my $base = 'http://data.alexa.com/data';
    my $uri = URI->new( $base );
    $uri->query_form( @args );
    $uri = $uri->as_string;

    return get( $uri );
}

# czysty kod XML nie jest dla nas optymalny, gdy chcemy
# pobiera poszczeglne elementy danych. Do przeksztacenia
# XML w struktury danych Perla uywamy XML::Simple, aby nie bawi
# si w obsugiwanie zdarze (byoby to konieczne w przypadku
# uycia XML::Parser lub XML::SAX); wiemy przy tym, e potrzebna
# jest nam niewielka cz danych. Potrzebna jest nam lista 
# powizanych witryn i lista powizanych produktw; pobieramy
# i zwracamy jedn i drug.
#####################################################
sub handle_xml {
    my $page = shift;
    my $xml = XMLin( $page );
    my @related = map {
        {
            asin => $_->{ASIN},
            title => $_->{TITLE},
            href => $xml->{RLS}{PREFIX}.$_->{HREF},
        }
    } @{ $xml->{RLS}{RL} };

    my @products;
    if (ref $xml->{SD}{AMZN}{PRODUCT} eq 'ARRAY') {
        @products = map { $_->{ASIN} } @{ $xml->{SD}{AMZN}{PRODUCT} };
    } else { @products = $xml->{SD}{AMZN}{PRODUCT}{ASIN}; }

    return ( \@related, \@products );
}

# Funkcje ju gotowe, teraz sam program:
warn "URL pocztkowy to $url\n" if DEBUG;
my @products; # zbieranie kolejnych numerw ASIN produktw

{
    my $page = fetch_xml( $url );
    my ($related, $new_products) = handle_xml( $page );
    @products = @$new_products; # bieca lista

    for (@$related) {
        my $xml = fetch_xml( $_->{href} );
        my ($related, $new_products) = handle_xml( $page );
        push @products, @$new_products;
    }
}

# Mamy teraz w @products list produktw, zatem 
# mona co z nimi robi dalej. Wyszukujemy je w Amazon
# i sprawdzamy ich tytuy.
my $amazon = Net::Amazon->new( token => AMAZON_TOKEN );
my %products = map { $_ => undef } @products;

for my $asin ( sort keys %products ) {
    warn "Szukanie $asin...\n" if DEBUG;
    my $response = $amazon->search( asin => $asin );
    my @products = $response->properties;
    die "Powtrzenie ASIN!?" unless @products == 1;
    my $product = $products[0];
    $products{$asin} = {
        name => $product->ProductName,
        price => $product->OurPrice,
        asin => $asin,
    };
}

# W porzdku. Mamy nazw, cen i ASIN. Wygenerujmy
# raport HTML:
{
    umask 022;
    warn "Zapis do $output\n" if DEBUG;
    open my $fh, '>', $output or die $!;
    print $fh "<html><head><title>Zbir zwizany z $url</title></head><body>";
    if (keys %products) {
        print $fh "<table>";
        for my $asin (sort keys %products) {
            my $data = $products{$asin};
            printf $fh "<tr><td>".
                       "<a href=\"http://amazon.com/exec/obidos/ASIN/%s\">".
                       "%s</a></td> <td>%s</td></tr>",
                       @{$data}{qw( asin name price )};
        }
        print $fh "</table>";
    }
    else { print $fh "Nie znaleziono produktw powizanych.\n"; }
    print $fh "</body></html>\n";
}

