package Terse::App;
use strict;
use warnings;
use attributes ();
use base 'Terse::Controller';
use B 'svref_2object';
use Cwd qw(abs_path cwd);

sub start {
	my ($pkg, @args) = @_;
	my $self = $pkg->new(@args);
	$self->_build_controllers($pkg);
	return $self;
}

sub _build_controllers {
	my ($self, $pkg) =@_; 
	my $pkg_file = join('/', split("\:\:", ($pkg)));
	my $path = $0;
	$path =~ s/[^\/]+$//g;
	$path .= $pkg_file;
	my @controllers = map {
		(my $m = $_) =~ s/\.pm$//g;
		$m =~ s/\//::/g;
		[
			"${path}/Controller/${_}",
			"${pkg}::Controller::${m}"
		]
	} $self->_recurse_directory("${path}/Controller");
	$self->controllers = {};
	for my $controller (@controllers){
		eval {
			require $controller->[0];
		};
		warn $@ && next if $@;
		$controller = $controller->[1]->new();
		warn $@ && next if $@;
		my $namespace = $controller->namespace;
		$self->controllers->{$namespace} = $controller;
	}
	$self->build_controllers($pkg) if $self->can('build_controllers');
	return $self;
}

sub _recurse_directory {
	my ($self, $dir, $path, @files) = @_;
	return () unless -d $dir;
	opendir my $d, $dir or die "Cannot read controller directory: $!";
	for (readdir $d) {
		next if $_ =~ m/^\./;
	 	if (-d "$dir/$_") {
			$path .= "/$_" if $path;
			push @files, $self->_recurse_directory("$dir/$_", $path || $_);
		} elsif ($_ =~ m/\.pm/) {
			push @files, $path ? "$path/$_" : $_;
		}
	}
	closedir $d;
	return @files;
}

sub preprocess_req {
	my ($self, $req, $t) = @_;
	($req) = $t->request->uri->path =~ m/([^\/]+)$/ if ! $req;
	return $req;
}

sub dispatch {
	my ($self, $req, $t, @params) = @_;
	(my $path = $t->request->uri->path) =~ s/^\///g;
	if ($path && ! $self->controllers->{$path}) {
		$t->logError('Path not found - ' . $path, 500);
		return;
	}
	if ($req eq $t->{_auth} || $t->is_login || $t->is_logout) {
		my @response = $self->SUPER::dispatch($req, $t, @params);
		@response = $self->controllers->{$path}->dispatch($req, $t, @response)
			if $path && $self->{controllers}->{$path}->can($req);
		return @response;
	} elsif ($path) {
		return $self->controllers->{$path}->dispatch($req, $t, @params);
	}
	return $self->SUPER::dispatch($req, $t, @params);
}

1;

__END__;


=head1 NAME

Terse::App - Multiple controllers build an app.

=head1 VERSION

Version 0.100

=cut

=head1 SYNOPSIS

	.. My/App.pm

	package My::App;

	use base 'Terse::App';

	sub login :any {
		return 1;
	}

	sub auth_prevent :any(auth) {
		return 0;
	}

	sub auth :get :post {
		return 1;
	}

	... My/App/Controller/Hello.pm

	package My::App::Controller::Hello;

	use base 'Terse::Controller';

	sub hello :get {
		... #1
	}
	
	sub world :get {
		... #2
	}

	... My/App/Controller/Hello/World.pm

	package My::App::Controller::Hello::World;

	use base 'Terse::Controller';

	sub world :get {
		... #3
	}

	.... MyApp.psgi ...

	use Terse;
	use My::App;
	our $app = My::App->start();

	sub {
		my ($env) = (shift);
		Terse->run(
			plack_env => $env,
			application => $app,
		);
	};

	....

	plackup MyApp.psgi

	GET http://localhost:5000/hello?id=here&other=params #1
	GET http://localhost:5000/hello?req=world #2
	GET http://localhost:5000/hello/world #3

=cut

=head1 AUTHOR

LNATION, C<< <email at lnation.org> >>

=head1 LICENSE AND COPYRIGHT

L<Terse>.

=cut
