#!/usr/bin/perl

use strict;

use File::Find;
use File::Spec;
use Getopt::Long;
use Cwd;

my $show_routes;
my $show_meta;
my $show_help;

GetOptions (
        "help"    => \$show_help,
        "routes"  => \$show_routes,
        "meta"    => \$show_meta,
) or die("Error in command line arguments\n");

if ($show_help){

    print <<HERE;

Usage: spek [args]

No args: rebuild spek application and run

Args:

--routes    show available http routes
--meta      show meta stories

HERE

    exit(0);
}

my $project_root_dir  = getcwd();

$project_root_dir =  File::Spec->rel2abs($project_root_dir);

my %seen = ();


unless ($show_routes or $show_meta) {

# reiniting spek app 

print "reiniting spek app ...\n";

open APP, ">", "$project_root_dir/speek.psgi" or die $!;

print APP <<HERE;

use parent 'Kelp';


HERE

if ( open INITFILE, "$project_root_dir/app.pm" ){

print "populate app.pm ...\n";

open APP, ">>", "$project_root_dir/speek.psgi" or die $!;

print APP "\n\n";

while (my $l =  <INITFILE>){
    print APP $l;
}

print APP "\n\n";

close APP;

close INITFILE;

}

}

finddepth(\&wanted, $project_root_dir );

my %routes;
    
sub wanted { 

    my $file = $_;

    if ($file =~ /^(get|post|update|delete|meta)\.txt$/) {

        my $http_method = $1;

        return if $seen{$File::Find::name};

        next if ! $show_meta and $http_method eq 'meta';

        my $resource_dir = $File::Find::dir;

        if ($show_routes){

            s{^$project_root_dir}[] for $resource_dir;

            print "$http_method $resource_dir \n";

        }elsif( $show_meta and $http_method eq 'meta' ){

            open META, "$resource_dir/meta.txt" or die $!;

            s{^$project_root_dir}[] for $resource_dir;

            print "\@meta $resource_dir:  \n";

            while(my $l =  <META>){
                print "\t$l";
            }
            close META;
        
        } elsif( open CODE, "$resource_dir/$http_method.pm" ){

            print "populate $http_method $resource_dir ...\n";
            my $r;

            s{^$project_root_dir}[] for $resource_dir;

            while (my $l =  <CODE>){
                chomp $l;
                push @{$routes{"$http_method $resource_dir"}}, $l ;
            }
            close CODE;
        }

        $seen{$File::Find::name} = 1;
   }

}

unless ($show_routes or $show_meta) {

open APP, ">>", "$project_root_dir/speek.psgi" or die $!;


print APP <<'HERE' if keys %routes;

sub build {

    my $self = shift;
    my $r = $self->routes;

HERE

my %hooks;

for my $k (keys %routes) {

    my ($m,$r) = split /\s+/, $k;

    my %handlers;

    if ( $r=~/\/id$/ or $r=~/\/id\// ) {
    
        if ( ! $hooks{$r} ) {

        print "generate hook for $r ... \n";

        for my $meth (qw{ get post delete update }){

            if (-f "$project_root_dir/$r/$meth.handler"){
                open HANDLER, "$project_root_dir/$r/$meth.handler" or die $!;
                while ( my $j = <HANDLER> ){
                    $handlers{$meth}.="\t$j";
                }
                close HANDLER;
            }
        }

        open HOOK, "> $project_root_dir/$r/hook.pm" or die $!;

        print HOOK <<'HERE2';

modify_resource(sub{
    my $r = shift;
    my $id = module_variable('id');
    s{/id}[/$id] for $r;
    $r;
});

HERE2
        for my $meth (keys %handlers) {

            print "inject response handler for $meth ...\n";
            print HOOK <<HERE3;

if (http_method() eq uc('$meth') ){
set_response_processor( sub { 

$handlers{$meth}

    });}
            
HERE3


        } # end for meth

        close HOOK;

        }

        $hooks{$r}=1;

        s{/id}[/:id]    for $r;
        s{/id/}[/:id/]  for $r;

    }

    my $code = join "\n\t", @{$routes{$k}};

    $m = uc($m);

    print APP <<HERE;
    \$r->add([ $m => '$r'  ] , sub {
        $code
    });

HERE


}

print APP "\n\n}\n\n" if keys %routes;

print APP <<'HERE';

my $app = __PACKAGE__->new;
$app->run;

HERE

close APP;


exec "plackup speek.psgi"

}

__END__

