package mis_dep ;

use Exporter ();
@ISA = qw(Exporter);
@EXPORT = qw(mis_dep mis_catalog_dep traverse_tree);

use Cwd ;
use File::Basename ;
use strict ;
use Cwd 'abs_path';
use trick_print ;
use gte ;

my @mis_inc_paths ;
my %processed_files ;
my %mis_depends_tree ;

# Get TRICK_CFLAGS and parse out -I include paths
sub mis_dep ($@) {

    my $file ;
    my %all_depend_trees ;
    my ($k , $a) ;
    my ($sim_ref , @fileList) = @_;

    @mis_inc_paths = $ENV{"TRICK_CFLAGS"} =~ /-I\s*(\S+)/g ;
    push @mis_inc_paths , "../include" ;
    @mis_inc_paths = grep !/trick_source/, @mis_inc_paths ;
    push @mis_inc_paths , "$ENV{TRICK_HOME}/trick_source" ;
    my @valid_inc_paths ;
    foreach (@mis_inc_paths) {
            push @valid_inc_paths , $_ if ( -e $_ ) ;
    }
    @mis_inc_paths = @valid_inc_paths ;

    @fileList = grep !/\.h$|\.H$|\.hh$|\.h\+\+$/ , @fileList ;

    foreach $file ( @fileList ) {
        if ( $file ne "" ) {
            undef %mis_depends_tree ;
            $file = abs_path(dirname($file)) . "/" . basename($file) ;
            trick_print($$sim_ref{fh},  "Getting dependencies for $file\n" , "normal_cyan" , $$sim_ref{args}{v}) ;
            get_depends($file, $sim_ref);
            %{$all_depend_trees{$file}} = %mis_depends_tree ;
            $all_depend_trees{$file}{last_look} = time ;
        }
    }

    return \%all_depend_trees ;
}

sub traverse_tree {
    my ($file, $level, %curr_tree) = @_ ;
    my $a ;

    print "   " x $level , $file , "\n";
    foreach $a ( @{$curr_tree{$file}} ) {
        if ( $a ne $file ) {
            traverse_tree($a, $level+1, %curr_tree) ;
        }
    }
}

# Show Depends Recursive Algorithm
sub get_depends($$) {

    my $file ;
    my $sim_ref ;
    my @list_objects ;
    my @list_libs ;
    my $found_dep ;
    my @lib_list ;
    my $contents ;
    my $size ;
    my $libdep ;
    my $language ;
    my ( $full_path ) ;
    my ($rcs_file_name, $rcs_ver, $rcs_date, $rcs_owner ) ;

    ($file, $sim_ref) = @_;

    # If you have already seen this dependency, then don't process
    # Trim the tree ! And prevent infinite circular recursion !!! Yikes ...
    return if ( exists $processed_files{$file} ) ;

    # Add this file to processed list, if it is a full path
    $processed_files{$file} = 1 ;

    open FILE, $file or die "Could not process $file\n";
    seek FILE , 0 , 2 ;
    $size = tell FILE ;
    seek FILE , 0 , 0 ;
    read FILE , $contents , $size;
    close(FILE);

    while ( $contents =~ /LIBRARY(\s|_)DEPENDENC(Y|IES):[^(]*(.*?)\)([A-Z \t\n\r]+:|[ \t\n\r]*\*)/gsi ) {
        $libdep .= $3 ;
    }

    if ( $libdep =~ /#/ ) {
        (my $cc = gte("TRICK_CC")) =~ s/\n// ;
        my @defines = $ENV{"TRICK_CFLAGS"} =~ /(-D\S+)/g ;
        my $temp ;
        open FILE, "echo \"$libdep\" | cpp -P @defines |" ;
        while ( <FILE> ) {
            $temp .= $_ ;
        }
        $libdep = $temp ;
    }


    @lib_list = split /\)[ \t\n\r\*]*\(/ , $libdep ;
    foreach (@lib_list) {
        s/\(|\)|\s+//g ;
        s/\${(.+?)}/$ENV{$1}/eg ;
    }
    @list_objects = grep /\.o$/ , @lib_list ;
    @list_libs = grep /\.so$|\.a$/ , @lib_list ;

    # Always add self-dependency 
    push @{$mis_depends_tree{$file}} , $file ;

    # Now for each object, construct full path to object's src and find src file
    foreach my $o (@list_objects) {

        # look for object code with source
        $found_dep = find_depends_file($file,$o,$sim_ref) ;

        # Did not find dependency
        if ( $found_dep == 0 ) {
            $o =~ s/\.[\w\+]+$/\.o/ ;
            trick_print($$sim_ref{fh}, "ERROR: Dependency \"$o\" not found for \"$file\"\n", "title_red" , $$sim_ref{args}{v}) ;
            exit( -1 ) ;
        }
    }

    # Now for each lib, construct full path to lib's src and add to list
    foreach my $l ( @list_libs ) {

        my ($rel_path , $lib_name ) ;

        ($rel_path , $lib_name ) = $l =~ /(?:(.*)\/)?([^\/]+)/ ;

        if ($rel_path eq "") {
            $found_dep = 1 ;
            $lib_name =~ s,lib,,;
            $lib_name =~ s,\.so$|\.a$,,;
            $processed_files{"-l$lib_name"} = 1 ;
            push @{$mis_depends_tree{$file}} , "-l$lib_name" ;
            trick_print($$sim_ref{fh},  "  $lib_name\n" , "debug_white" , $$sim_ref{args}{v}) ;
        } else {

            $found_dep = 0 ;
            foreach my $ipath ( @mis_inc_paths ) {

                # Construct possible full paths to lib dir from include paths
                $full_path = $ipath . "/" . $rel_path;

                if ( -s $full_path ) {

                    $found_dep = 1;
                    $lib_name = $full_path ."/object_\${TRICK_HOST_CPU}/". $lib_name ;

                    # remove ../
                    while ( $lib_name =~ s,/[^/]+/\.\.,, ) {}

                    push @{$mis_depends_tree{$file}} , $lib_name ;
                    trick_print($$sim_ref{fh},  "  $lib_name\n" , "debug_white" , $$sim_ref{args}{v}) ;

                    $processed_files{$lib_name} = 1 ;
                    last;
                }
            }
        }

        # Did not find dependency
        if ( $found_dep == 0 ) {
            trick_print($$sim_ref{fh}, "ERROR: Dependency $l not found for $file\n", "title_red" , $$sim_ref{args}{v}) ;
            exit( -1 ) ;
        }
    }
}


sub find_depends_file($$$) {

    my ($file, $o , $sim_ref) ;
    my @list_languages ;
    my $lex_yacc ;
    my ( $full_path , $full_path1 , $full_path2 ) ;
    my ( $curr_path ) ;
    my ( $dep_to_search ) ;

    ($file , $dep_to_search, $sim_ref) = @_;

    $o = $dep_to_search ;

    $curr_path = dirname($file) ;
    # Decide how to search through languages
    opendir THISDIR, $curr_path or die "Could not open the directory of $curr_path" ;
    $lex_yacc = grep /\.[ly]$/ , readdir THISDIR ;

    if ( $lex_yacc ) {
        @list_languages = ("y", "l", "c", "cpp" , "cc" , "cxx" , "C" , "c\+\+");
    }
    else {
        @list_languages = ("c", "cpp" , "cc" , "cxx" , "C" , "c\+\+", "y", "l");
    }

    # Otherwise use TRICK_CFLAGS and find it
    if ( $dep_to_search !~ /\.o$/ ) {
        foreach my $ipath ( $curr_path , @mis_inc_paths ) {
            if ( -s "$ipath/$dep_to_search" ) {
                my $f = "$ipath/$dep_to_search" ;
                $full_path = abs_path(dirname($f)) . "/" . basename($f) ;
                push @{$mis_depends_tree{$file}} , $full_path ;
                trick_print($$sim_ref{fh},  "  $full_path\n" , "debug_white" , $$sim_ref{args}{v}) ;
                get_depends($full_path , $sim_ref);
                return(1) ;
            }
        }
    } else {
        foreach my $ipath ( $curr_path , @mis_inc_paths ) {
            foreach my $lang ( @list_languages ) {

                my $found_dep ;
                my ($file_name ) ;
                my ($dir_name ) ;
                my ($rspath , $rpath ) ;

                $o =~ s/\.[\w\+]+$/\.$lang/ ;

                #
                # Construct possible full paths to src from include paths
                #
                $file_name = basename($o) ;
                $dir_name = dirname($o) ;

                # if full path sepcified (possible, but not recommended)
                # don't prepend include path.
                if ( $dir_name =~ /^\// ) {
                    $full_path1 = "$dir_name/src/$file_name" ;
                    $full_path2 = "$dir_name/$file_name" ;
                }
                else {
                    $full_path1 = "$ipath/$dir_name/src/$file_name" ;
                    $full_path2 = "$ipath/$dir_name/$file_name" ;
                }

                $found_dep = 0;
                # Construct full path
                if ( -s $full_path1 ) {
                    $full_path = abs_path(dirname($full_path1)) . "/" . basename($full_path1) ;
                    $found_dep = 1;
                }
                elsif ( -s $full_path2 ) {
                    $full_path = abs_path(dirname($full_path2)) . "/" . basename($full_path2);
                    $found_dep = 1;
                }

                if ( $found_dep == 1 ) {
                    push @{$mis_depends_tree{$file}} , $full_path ;
                    trick_print($$sim_ref{fh},  "  $full_path\n" , "debug_white" , $$sim_ref{args}{v}) ;
                    if ( $lang eq "y" ) {
                        ($full_path1 = $full_path ) =~ s/\.y$/\.l/ ;
                        push @{$mis_depends_tree{$file}} , $full_path1 ;
                    }
                    get_depends($full_path , $sim_ref);
                    return(1);

                }

            }
        }
    }

    return(0) ;
}


sub mis_catalog_dep ($$) {
    return ;
}

1;
