package TheHTTP;
use strict;
use HTML::Entities;
1;

sub new {
    my $class = shift;
    my($name) = @_;
    return bless {
        'output' => undef,
        'name' => $name,
        'doneHeaders' => 0,
    }, $class;
}

sub capture {
    my $self = shift;
    my($target) = @_;
    $self->{output} = $target;
}

sub print {
    my $self = shift;
    if (defined $self->{output}) {
        local $" = '';
        ${$self->{output}} .= "@_";
    } else {
        CORE::print(@_);
    }
}

sub error {
    my $self = shift;
    my($status, $message) = @_;
    $self->page('Error', $status);
    $self->print('<p>' . encode_entities($message) . '</p>');
}

sub redirect {
    my $self = shift;
    my($uri) = @_;
    $self->{doneHeaders} = 1;
    $self->print(<<eof);
Status: 303 See Other
Location: $uri
Content-Type: text/plain;charset=utf-8

See $uri
eof
}

sub addHeader {
    my $self = shift;
    my($header, $content) = @_;
    die 'too late to output an HTTP header' if $self->{doneHeaders};
    print "$header: $content\n";
}

sub page {
    my $self = shift;
    my($title, $status) = @_;
    my $name = encode_entities($self->{name});
    $title = encode_entities($title);
    $self->{doneHeaders} = 1;
    $self->print("Status: $status\n") if defined $status;
    $self->print("Content-Type: text/html;charset=utf-8\n\n");

    # read templates
    local *FILE;
    local $/ = undef; # entire file should be slurped as one line

    # top
    open(FILE, '<.template-top') or die "couldn't open template: $!";
    my $top = <FILE>;
    close(FILE);

    # bottom
    open(FILE, '<.template-bottom') or die "couldn't open template: $!";
    my $bottom = <FILE>;
    close(FILE);

    # process templates
    my $variables = {
        'name' => encode_entities($self->{name}),
        'title' => encode_entities($title),
    };
    $self->replaceVariables(\$top, $variables);
    $self->replaceVariables(\$bottom, $variables);

    $self->print($top);

    $self->{close} = sub {
        my $s = shift;
        if (defined $s) {
            $s->print($bottom);
        } else {
            CORE::print($bottom);
        }
    };
}

sub DESTROY {
    my $self = shift;
    if (defined $self->{close}) {
        &{$self->{close}};
    }
}

sub replaceVariables {
    my $self = shift;
    my($string, $variables) = @_;
    foreach (keys %$variables) {
        $$string =~ s/\$$_/$variables->{$_}/esg;
    }
}
