#
# This file is part of Jedi
#
# This software is copyright (c) 2013 by celogeek <me@celogeek.com>.
#
# This is free software; you can redistribute it and/or modify it under
# the same terms as the Perl 5 programming language system itself.
#
package Jedi::Role::App;

# ABSTRACT: imported role for Jedi::App

use Moo::Role;
our $VERSION = '1.008';    # VERSION
use Jedi::Helpers::Scalar;
use CHI;
use Carp qw/carp croak/;

# REQUIRED

requires 'jedi_app';

# INTERNAL ATTRIBUTES

has '_jedi_routes'  => ( is => 'ro', default => sub { {} } );
has '_jedi_missing' => ( is => 'ro', default => sub { [] } );
has '_jedi_routes_cache' => ( is => 'lazy', clearer => 1 );

sub _build__jedi_routes_cache {
    return CHI->new(
        driver    => 'RawMemory',
        datastore => {},
        max_size  => 10_000
    );
}

sub _jedi_routes_push {
    my ( $self, $which, $path, $sub ) = @_;
    croak "method invalid : only support GET/POST/PUT/DELETE !"
        if $which !~ /^(?:GET|POST|PUT|DELETE)/x;
    croak "path invalid !" if !defined $path;
    croak "sub invalid !"  if ref $sub ne 'CODE';
    $path = $path->full_path if ref $path ne 'Regexp';
    push @{ $self->_jedi_routes->{$which} }, [ $path, $sub ];
    $self->_clear_jedi_routes_cache;
    return;
}

# ATTRIBUTES

has 'jedi_config' => ( is => 'ro', default => sub { {} } );
has 'jedi_base_route' => ( is => 'ro' );
has 'jedi_host_ip'    => ( is => 'ro' );

# PUBLIC METHODS

sub get {
    my ( $self, $path, $sub ) = @_;
    return $self->_jedi_routes_push( 'GET', $path, $sub );
}

sub post {
    my ( $self, $path, $sub ) = @_;
    return $self->_jedi_routes_push( 'POST', $path, $sub );
}

sub put {
    my ( $self, $path, $sub ) = @_;
    return $self->_jedi_routes_push( 'PUT', $path, $sub );
}

sub del {
    my ( $self, $path, $sub ) = @_;
    return $self->_jedi_routes_push( 'DELETE', $path, $sub );
}

sub missing {
    my ( $self, $sub ) = @_;
    croak "sub invalid !" if ref $sub ne 'CODE';

    push( @{ $self->_jedi_missing }, $sub );
    $self->_clear_jedi_routes_cache;
    return;
}

sub response {
    my ( $self, $request, $response ) = @_;

    my $path = $request->path;

    my $request_method = $request->env->{REQUEST_METHOD};
    $request_method = 'GET' if $request_method eq 'HEAD';

    my $routes = $self->_jedi_routes->{$request_method};
    my $methods;

    my $cache_key = $request_method . ':' . $path;

    if ( my $cache_routes = $self->_jedi_routes_cache->get($cache_key) ) {
        $methods = $cache_routes;
    }
    else {
        $methods = [];
        if ( ref $routes eq 'ARRAY' ) {
            for my $route_def (@$routes) {
                my ( $route, $sub ) = @$route_def;
                if ( ref $route eq 'Regexp' ) {
                    push @$methods, $sub if $path =~ $route;
                }
                else {
                    push @$methods, $sub if $path eq $route->full_path;
                }
            }
        }

        @$methods = @{ $self->_jedi_missing } if !scalar @$methods;

        $self->_jedi_routes_cache->set( $cache_key => $methods );
    }

    for my $meth (@$methods) {
        last if !$self->$meth( $request, $response );
    }

    return $response;
}

1;

__END__
=pod

=head1 NAME

Jedi::Role::App - imported role for Jedi::App

=head1 VERSION

version 1.008

=head1 DESCRIPTION

Look the L<Jedi::App> for documentation.

=head1 BUGS

Please report any bugs or feature requests on the bugtracker website
https://github.com/celogeek/perl-jedi/issues

When submitting a bug or request, please include a test-file or a
patch to an existing test-file that illustrates the bug or desired
feature.

=head1 AUTHOR

celogeek <me@celogeek.com>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2013 by celogeek <me@celogeek.com>.

This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.

=cut