#!/usr/bin/env perl
use File::Basename;
use Cwd qw(realpath getcwd);
use Digest::MD5 qw(md5_hex);

$init_script="init-win.pl";

sub setup{
    $script_home=realpath(dirname  $0);
    $script_name=basename $0;

    $debug=0;
    $debug=1 if($script_name eq 'c-scriptd');
    $debug=2 if($script_name eq 'c-scriptddd');
#    $debug=3;


    if($debug){
	for(@ARGV){
	    if( -f $_){
		$in=$_;
		last;
	    }
	}
    }else{
	$in=realpath(shift @ARGV);
    }
    $in=~s/\\/\//g;


    $run_dir=dirname $in;
#    $home=$ENV{HOME}."/.c-script";
    $home=$script_home."/.c-script";

    for(glob $script_home."/*.h"){
#	$inc.=" ".realpath($1);
	print $1;
    }
    print $inc;
#    exit;

}

sub getlib{
    my $path=shift;
    my @g=glob($path);
    my $g=$g[0];
    if(! -f $g){
	return "";
    }else{
	$g=basename $g;
	$g=~ s/^lib//g;
	$g=~ s/\.so$//g;
	$g=~ s/\.a$//g;
	return "-l".$g."\n";
    }
}

sub eval_init{
    if(-e "$home/$init_script"){
	do "$home/$init_script";
    }else{
	do "$script_home/$init_script";
    }

    $normal_opt =~ s/\n/ /g;
    $debug_opt =~ s/\n/ /g;
    $opt =~ s/\n/ /g;
    $libs =~ s/\n/ /g;
    
    if($debug){
	$opt=$debug_opt.' '.$opt;
    }else{
	$opt=$normal_opt.' '.$opt;
    }
}

sub modtime{
    my $filepath=shift;
    my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,
	$size,$atime,$mtime,$ctime,$blksize,$blocks) = stat($filepath);
    return $mtime;
}


sub gen_exe{
    my ($in,$inc,$src)=@_;
    my ($s)=split ' ', md5_hex("$in$inc$src");
    my ($suffix)=($in =~ /(\.[^.]*$)/);
    my $h=$home."/cache";
    if( ! -d $home){
	mkdir "$home";
    }
    if( ! -d $h){
	mkdir "$h";
    }
    return ($h.'/'.$s.$debug,$suffix);
}

sub gen_exename{
    my ($exe,$suffix)=gen_exe $in,$inc,$src;
    
    if($debug){
	for(@ARGV){
	    if( -f $_){
		$_=$exe;
		last;
	    }
	}
    }

    return ($exe.$suffix,$exe);
}

sub gen_src{
    my ($in,$mod_in)=@_;
    my $line;
    open IN,"<$in";
    open OUT,">$mod_in";
    print OUT "#include <c-script.h>\n";
    print OUT "#line 1  \"$in\"\n";
    while(<IN>){
	if(/^#!.*/){
	    print OUT "\n";
	}elsif(/^#pragma\s+c-script.*$/){
	    print OUT "\n";
	}else{
	    print OUT $_;
	}
    }
    close OUT;
}

sub getparam{
    my $file=shift;
    local *IN;
    open IN,"<$file";
    while(<IN>){
	if(/^#pragma\s+c-script:src\s+(.*)/){
	    $src.=" ".realpath($1);
	}elsif(/^#pragma\s+c-script:opt\s+(.*)/){
	    $opt.=" ".$1;
	}elsif(/^#pragma\s+c-script:cc\s+(.*)/){
	    $cc=$1;
	}elsif(/^#pragma\s+c-script:libs\s+(.*)/){
	    $libs.=" ".$1;
	}elsif(/^#include\s+"([^"]+)/){
	    $inc.=" ".realpath($1);
	}
    }
    close IN;
}

local @dirs;

sub pushd{
    push @dirs,getcwd();
    chdir $_[0];
}
sub popd{
    chdir (pop @dirs);
}
sub chmodx{
    open(my $fh, "<", $_[0]);
    my $perm = (stat $fh)[2] & 07777;
    chmod($perm | 0100, $fh);
    close $fh;
}
sub compile{
#    print "cd $run_dir ;$cc $opt -o $exe $mod_in $src $libs";
    print $inc;
    pushd $run_dir;
#    my $cc=$script_home."/perl/c/bin/g++.exe";
    my $cmd="$cc $opt $output_opt$exe $mod_in $src $libs";
#    $cmd =~ s/\//\\/g;
    print $cmd,"\n";
    `$cmd`;
    my $exit_value = $? >> 8;
#    unlink "$mod_in";
    popd
    exit if($exit_value!=0);
    chmodx $exe;
}


sub run{
    if($debug == 1){
	exec 'gdb',@ARGV;
    }elsif($debug  == 2){
	exec 'ddd',@ARGV;
    }elsif($debug  == 3){
	$exe=~s/\//\\/g;
	print 'vcexpress','/debugexe',$exe,@ARGV;
	exec 'vcexpress','/debugexe',"${exe}.exe",@ARGV;
    }else{
	exec $exe,@ARGV;
    }
}

sub compilep{
    my ($exe,$in,$src,$inc)=@_;
    my $c=0;
    if(! -e $exe){
	$c=1;
    }else{
	my @files;
	my $t=modtime( $exe);
	push @files,$in;
	push @files,(split ' ',$src);
	push @files,(split ' ',$inc);
	
	for(@files){
	    if($t < modtime($_)){
		$c=1;
		last;
	    }
	}
    }
    return $c;
}

setup();

eval_init();

getparam($in);

($mod_in,$exe)=gen_exename();

gen_src($in,$mod_in);

compile() if compilep($exe,$in,$src,$inc);

run();

