package Apache::MVC;
use base qw(Class::Accessor Class::Data::Inheritable);
use attributes ();
use Class::DBI::Loader;
use strict;
use warnings;

__PACKAGE__->mk_classdata(qw( _config init_done view_object ));
__PACKAGE__->mk_accessors ( qw( config ar params objects model_class args ));
__PACKAGE__->config({});
__PACKAGE__->init_done(0);

# This is really dirty.
sub config {
    my $self = shift;
    if (ref $self) { return $self->_config_accessor(@_) }
    return $self->_config(@_);
}

sub set_database {
    my ($calling_class, $dsn) = @_;
    $calling_class = ref $calling_class if ref $calling_class;
    $calling_class->config->{dsn} = $dsn;
    $calling_class->config->{loader} = Class::DBI::Loader->new(
        namespace => $calling_class,
        dsn => $dsn
    ); 
}

sub init {
    my $class = shift;
    my $config = $class->config;
    $config->{model} ||= "Apache::MVC::Model::CDBI";
    $config->{view}  ||= "Apache::MVC::View::TT";
    $config->{classes} = [ $class->config->{loader}->classes ];
    $config->{display_tables} ||= [ $class->config->{loader}->tables ];
    for my $class (@{$config->{classes}}) {
        no strict 'refs';
        push @{$class."::ISA"}, $class->config->{model};
    }
    $class->view_object($class->config->{view}->new);

}

sub class_of {
    my ($self, $table) = @_;
    return $self->config->{loader}->_table2class($table);
}

sub handler {
    # See Apache::MVC::Workflow before trying to understand this.
    my $class = (caller(0))[0];
    $class->init unless $class->init_done;
    my $r = bless { config => $class->config }, $class;
    $r->get_request();
    $r->parse_location();
    $r->model_class($r->class_of($r->{table}));
    my $status = $r->is_applicable;
    return $status unless $status == 200;
    $status = $r->call_authenticate;
    return $status unless $status == 200;
    $r->find_objects();
    $r->additional_data();
    $r->class->process($r);
}

sub get_request {
    my $self = shift;
    require Apache; require Apache::Request; 
    $self->{ar} = Apache::Request->new(Apache->request);
}

sub parse_location {
    my $self = shift;
    my @pi = split /\//, $self->{ar}->uri();
    shift @pi while @pi and !$pi[0];
    $self->{table} = shift @pi;
    $self->{action} = shift @pi;
    $self->{args} = \@pi;
}

sub is_applicable {
    my $self = shift;
    require Apache::Constants;
    Apache::Constants->import(":common");
    my $config = $self->config;
    my %ok = map {$_ => 1} @{$config->{displaying_tables}};
    return DECLINED() unless exists $ok{$self->{table}};

    # Does the action method exist?
    my $cv = $self->model_class->can($self->{action});
    return DECLINED() unless $cv;

    # Is it exported?
    my $attribs = join " ", attributes::get($cv);
    return DECLINED() unless $attribs =~ /\b(Exported|Class|Single|Multiple)\b/i;
    return OK();
}


sub authenticate { return 200 }

1;
