#!/usr/bin/perl

use strict;

use File::Find;
use Getopt::Long;
use File::Path qw(make_path remove_tree);
use File::Spec;
use Term::ANSIColor;
use Cwd;

my $project_root_dir  = $ENV{'OUTTHENTIC_ROOT'} || getcwd();
my $purge_cache   = 0;
my $format        = 'default';
my $debug_mod     = 0;
my $dump_config   = 0;
my $nocolor       = 0;
my $task_name     = '';
my $story_path;
my $match_l = $ENV{'match_l'} || 200;
my $ini_file_path;
my $yaml_file_path;
my $json_file_path;
my @runtime_params;


GetOptions (

        "format=s"      => \$format,            # string
        "purge-cache"   => \$purge_cache,       # boolean
        "nocolor"       => \$nocolor,           # boolean
        "debug=i"       => \$debug_mod,         # numeric
        "match_l=i"     => \$match_l,           # numeric
        "root=s"        => \$project_root_dir,  # string
        "story=s"       => \$story_path,        # string
        "task=s"        => \$task_name,         # string
        "ini=s"         => \$ini_file_path,     # string
        "yaml=s"        => \$yaml_file_path,    # string
        "json=s"        => \$json_file_path,    # string
        "param=s"       => \@runtime_params,    # string
        "dump-config"   => \$dump_config,       # boolean


) or die("Error in command line arguments\n");


$nocolor ||= $ENV{SPARROW_NO_COLOR};

my $test_root_dir = $ENV{SPARROW_ROOT} ? "$ENV{SPARROW_ROOT}/tmp/".$$ : "$ENV{HOME}/.outthentic/tmp/".$$;

remove_tree($test_root_dir);
make_path($test_root_dir);

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

my %seen = ();

finddepth(\&wanted_downstreams, $project_root_dir."/modules" );

finddepth(\&wanted_upstreams, $project_root_dir );


sub wanted_upstreams {
    wanted($_,'upstream');
}

sub wanted_downstreams {
    wanted($_,'downstream');
}

sub wanted { 

    my $file = shift;

    my $story_type = shift;

    if ($file eq 'story.check' or $file eq 'meta.txt' ) {

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

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

        make_path("$test_root_dir/$story_dir");

        my $tfile = "$test_root_dir/$story_dir/sparrow.pl";

        open F, ">", $tfile or die $!;
    
        print F "package main;\n\n";
    
        print F "BEGIN { push \@INC, q{$project_root_dir/lib}; }\n";
    
        print F "use strict;\n";

        print F "use Outthentic;\n\n\n";
    
        print F "new_story();\n\n";
    
        print F "set_prop( project_root_dir => q{$project_root_dir} );\n";
        print F "set_prop( test_root_dir    => q{$test_root_dir} );\n";
        print F "set_prop( ini_file_path    => q{$ini_file_path} );\n"    if $ini_file_path;
        print F "set_prop( yaml_file_path   => q{$yaml_file_path} );\n"  if $yaml_file_path;
        print F "set_prop( json_file_path   => q{$json_file_path} );\n"  if $json_file_path;
    
        print F "set_prop( story => q{$File::Find::dir} );\n";
        print F "set_prop( story_dir => q{$File::Find::dir} );\n";
        print F "set_prop( story_check_file => q{$File::Find::dir/story.check} );\n";
        print F "set_prop( story_type => q{$story_type} );\n";
        print F "set_prop( format => q{$format} );\n";

        print F "set_prop( debug => $debug_mod );\n";
        print F "set_prop( nocolor => $nocolor );\n";
        print F "set_prop( match_l => $match_l );\n";
        print F "set_prop( runtime_params => q{".(join ':::', @runtime_params)."} );\n";
        print F "set_prop( task_name => '$task_name' );\n";

        print F "\nset_story();\n\n";
        print F "\npopulate_config();\n\n";

        if ($dump_config){
          print F "\ndump_config();\n\n";
          return
        }
    
        if ($story_type eq 'downstream') {
            print F "apply_story_vars();\n";
        }

        if ($file eq 'meta.txt'){
          print F "set_prop( is_meta => 1 );\n";
          print F "print_meta();\n\n" unless $format eq 'concise';
        }else{
          print F "set_prop( is_meta => 0 );\n";
        }

        if ( -e "$File::Find::dir/story.pm" ){
            print F "eval { do_perl_hook('$File::Find::dir/story.pm') }; our \$STATUS=0, die \"perl hook error: \$@\" if \$@ ;\n\n";
        }elsif ( -e "$File::Find::dir/hook.pl" ){
            print F "eval { do_perl_hook('$File::Find::dir/hook.pl') };  our \$STATUS=0, die \"perl hook error: \$@\" if \$@ ;\n\n";
        }elsif ( -e "$File::Find::dir/hook.rb" ){
            print F "eval { do_ruby_hook('$File::Find::dir/hook.rb') };  our \$STATUS=0, die \"ruby hook error: \$@\" if \$@ ;\n\n";
        }elsif ( -e "$File::Find::dir/hook.py" ){
            print F "eval { do_python_hook('$File::Find::dir/hook.py') };  our \$STATUS=0, die \"python hook error: \$@\" if \$@ ;\n\n";
        }elsif ( -e "$File::Find::dir/hook.bash" ){
            print F "eval { do_bash_hook('$File::Find::dir/hook.bash') }; our \$STATUS=0, die \"bash hook error: \$@\" if \$@ ;\n\n";
        }

        unless ($file eq 'meta.txt'){

          print F "eval { generate_asserts(q{$File::Find::dir/story.check}) }; die \"asserts error: \$@\" if \$@ ;\n\n";

        }

        print F 'end_of_story();',"\n\n";

        print F "1;\n\n";    

        close F;

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

   }

}

my $st;
my $exit_code;

if ($story_path){
    $st = (system("perl $test_root_dir$project_root_dir/$story_path/sparrow.pl")==0);
    $exit_code = sprintf "%d", $? >> 8;
}else{
    $st = ( system("perl $test_root_dir$project_root_dir/sparrow.pl") == 0);
    $exit_code = sprintf "%d", $? >> 8;
}

system("rm -rf $test_root_dir") if $purge_cache;

unless ( $dump_config ) { # do not check story status in case we only dump config data

  if ($st) {
    print $nocolor ? "STATUS\tSUCCEED\n" : colored(["green"],"STATUS\tSUCCEED\n")
      unless $format eq 'concise';
  }else{
    print $nocolor ? "STATUS\tFAILED ($exit_code)\n" :  colored(["red"],"STATUS\tFAILED ($exit_code)\n")
      unless $format eq 'concise';
    exit($exit_code);
  }
  
}
