package main;

use strict;
use Smart::Comments;

{
	my @elements;
	
	@elements = (Element::PlainText->new(' *** Sample sites ***'), Element::URI->new('http://1.com/3rd'), Element::URI->new('http://3.com/2nd/'), Element::URI->new('http://2.com/1st/'));
	
	{
		### not sorted, not filtered:
		my $page = Page->new(@elements);
		print $page->out();
	}
	print "\n--------\n";
	
	{
		### sorted:
		my $page = Page->new(Element::Container::Sort->new(@elements));
		print $page->out();
	}
	print "\n--------\n";
	
	{
		### link list:
		my $page = Page->new(Element::Container::Filter->new(@elements));
		print $page->out();
	}
	print "\n--------\n";
	
	{
		### link list sorted by label:
		my $page = Page->new(Element::Container::Sort->new(Element::Container::Filter->new(@elements)));
		print $page->out();
	}
	print "\n--------\n";
}

package Page;

sub new
{
	my $class = shift;
	bless { element => [@_] }, $class;
}

sub elements
{
	my $self = shift;
	map { $_->elements() } @{$self->{element}};
}

sub out
{
	my $self = shift;
	join "\n", map { $_->out() } $self->elements();
}

sub string
{
	my $self = shift;
	join '', map { $_->string() } $self->elements();
}

package Element::Container::Sort;

sub new
{
	my $class = shift;
	bless { element => [@_] }, $class;
}

sub elements
{
	my $self = shift;
	my @r;
	foreach (@{$self->{element}}){
		push @r, $_->elements();
	}
	sort { $a->string() cmp $b->string() } @r;
}

sub out
{
	my $self = shift;
	map { $_->out() } $self->elements();
}

sub string
{
	my $self = shift;
	join '', map { $_->string() } $self->elements();
}

package Element::Container::Filter;

sub new
{
	my $class = shift;
	bless { element => [@_] }, $class;
}

sub elements
{
	my $self = shift;
	my @r;
	foreach (@{$self->{element}}){
		push @r, map {
			$_->fetch_by('label') =~ m%http://[^/]*/([^/]*)%;
			ref($_)->new($_->fetch_by('uri'), $1);
		}
		grep {
			$_->isa('Element::URI');
		} $_->elements();
	}
	
	@r;
}

sub out
{
	my $self = shift;
	map { $_->out() } $self->elements();
}

sub string
{
	my $self = shift;
	join '', map { $_->string() } $self->elements();
}

package Element::URI;

sub new
{
	my $class = shift;
	my($uri, $label) = @_;
	$label = $label ? $label : $uri;
	bless { uri => $uri, label => $label }, $class;
}

sub elements
{
	$_[0];
}

sub out
{
	my $self = shift;
	'<a href="'.$self->{uri}.'">'.$self->{label}.'</a>';
}

sub fetch_by
{
	my $self = shift;
	my($request) = @_;
	my $r;
	if ($request eq 'label'){
		$r = $self->_label();
	}
	elsif ($request eq 'uri'){
		$r = $self->_uri();
	}
	else {
		$r = $self->string();
	}
	$r;
}

sub string
{
	my $self = shift;
	$self->{label};
}

sub _uri
{
	my $self = shift;
	$self->{uri};
}

sub _label
{
	my $self = shift;
	$self->{label};
}

package Element::PlainText;

sub new
{
	my $class = shift;
	bless { text => $_[0] }, $class;
}

sub elements
{
	$_[0];
}

sub out
{
	$_[0]->{text};
}

sub fetch_by
{
	my $self = shift;
	$self->string();
}

sub string
{
	$_[0]->{text};
}

### not sorted, not filtered:
 *** Sample sites ***
<a href="http://1.com/3rd">http://1.com/3rd</a>
<a href="http://3.com/2nd/">http://3.com/2nd/</a>
<a href="http://2.com/1st/">http://2.com/1st/</a>
--------

### sorted:
 *** Sample sites ***
<a href="http://1.com/3rd">http://1.com/3rd</a>
<a href="http://2.com/1st/">http://2.com/1st/</a>
<a href="http://3.com/2nd/">http://3.com/2nd/</a>
--------

### link list:
<a href="http://1.com/3rd">3rd</a>
<a href="http://3.com/2nd/">2nd</a>
<a href="http://2.com/1st/">1st</a>
--------

### link list sorted by label:
<a href="http://2.com/1st/">1st</a>
<a href="http://3.com/2nd/">2nd</a>
<a href="http://1.com/3rd">3rd</a>
--------