package My::TT;

use strict;

use Apache::Request;
use Apache::Constants qw/:common/;

use Template;
use Digest::MD5 qw/md5_base64/;

sub new {
  my $proto = shift;
  my $class = ref $proto || $proto;
  my $self = {@_};
  bless $self => $class;
  return $self;
}

sub handler ($$) {
  my ($class, $r) = @_;

  my $self = $class->new(__apr => Apache::Request->new(My::TT::apr_setup($r)));

  ## this is where work gets done, up and including setting headers
  my %data = $self->get_data;

  $self->apr->content_type($self->content_type);
  $self->apr->send_http_headers;

  $self->return_error if $self->error; 

  my $template = $self->get_template_filename;
  $self->return_error if $self->error;

  my $tt = My::TT::template($self->template_config)
    or $self->return_error(status => SERVER_ERROR, reason => 
$Template::error);

  $tt->process($template, \%data, $self->apr)
    or $self->return_error(status => SERVER_ERROR, reason => 
$tt->error);

  return OK;
}

## parameters for Apache::Request
sub apr_setup {
  my $r = shift;

  my @apr_setup = ($r);
  if (my $post_max = $r->dir_config('MaxUploadSize')) {
    push @apr_setup, POST_MAX => $post_max;
  }
  return @apr_setup;
}

## convinience method for accessing current request
sub apr { return shift->{__apr}; }

## allow subclasses to customize content type header
sub content_type {
  my $self = shift;

  $self->{__content_type} = shift if @_;
  return ($self->{__content_type} || 'text/html');
}

## override this for inherited classes
sub template_config { return {}; }

my $template_object_cache = {};

## get the right template object
sub My::TT::template {
  my ($config) = @_;

  return $template_object_cache->{md5_base64(%$config)} ||= 
Template->new($config);
}

## get the template filename
sub get_template_filename {
  my ($self) = @_;

  if (my $template_root = $self->apr->dir_config('TemplateRoot')) {
    $self->apr->document_root($template_root);
  }
  return (my $filename = ($self->path_info || 'index.html')) =~ s[^/][];
}

## override this to customize; this one just gets the request data
sub get_data {
  my ($self) = @_;

  return $self->apr->method eq 'POST' ? $self->apr->content : $self->apr->args;
}

sub throw_error {
  my $self = shift;

  my %err = %{@_};
  $self->{error}{reason} = ($err{reason} || 'Unknown server error');
  $self->{error}{status} = ($err{status} || SERVER_ERROR);
  return undef;
}

sub return_error {
  my $self = shift;

  my %err = %{@_};
  $self->apr_log_reason($err{reason} || $self->{error}{reason} || 'Unknown server error');
  return ($err{status} || $self->{error}{status} || SERVER_ERROR);
}

sub error { return exists shift->{error}; }

1;
