#!/usr/bin/env perl
use Data::Dumper;
use Getopt::Long qw(:config bundling no_ignore_case);
# URL parsing functions {{{

my $URL_RE = qr{
		(?:    (?<scheme> [^:\/?\#]+) : )?
		(?: // (?<host> [^/?#]*)        )?
		       (?<path> [^?#]*)
		(?: \? (?<query> [^#]*)         )?
		(?: \# (?<fragment> .*)         )?
	}x;

sub parse_url {
	my ($url) = @_;

	if ($url =~ $URL_RE) { return my %url = %+; }
}

sub unparse_url {
	my (%url) = @_;

	my $url = $url{scheme}."://".$url{host};
	$url .= $url{path}         if defined($url{path});
	$url .= "?".$url{query}    if defined($url{query});
	$url .= "#".$url{fragment} if defined($url{fragment});
	return $url;
}

sub url_decode {
	my ($url) = @_;

	for ($url) {
		s/\+/ /g;
		s/%([A-Fa-f0-9]{2})/pack('C', hex($1))/gse;
	}
	return $url;
}

sub parse_query {
	my ($query) = @_;

	map {
		my ($k, $v) = split(/=/, $_, 2);
		[$k => url_decode($v)];
	}
	split(/&/, $query);
}

# }}}

my @urls;

if (@ARGV) {
	@urls = @ARGV;
} else {
	@urls = grep {chomp; 1} <STDIN>;
}

sub parse_and_print {
	my ($url, $depth) = @_;
	my %url = parse_url($url);
	my $indent = "  "x($depth||0);
	
	for ("scheme", "host", "path", "query", "fragment") {
		if ($url{$_} eq "") {
			next;
		} elsif ($_ eq "query") {
			print "$indent$_: {\n";
			my @query = parse_query($url{$_});
			for (@query) {
				my ($key, $value) = @$_;
				print "    $indent'$key' => $value\n";
				if ($value =~ /^http/) {
					print "$indent    nested URL {\n";
					parse_and_print($value, $depth+2+2);
					print "$indent    }\n";
				}
			}
			print "$indent}\n";
		} elsif ($_ eq "fragment" && $url{$_} =~ m{^#?/}) {
			print "$indent$_: {\n";
			parse_and_print($url{$_}, $depth+2);
			print "$indent}\n";
		} else {
			print "$indent$_: $url{$_}\n";
		}
	}
}

for my $url (@urls) {
	parse_and_print($url);
}
