#!/usr/bin/perl -w

use strict;
use Opt;
use Sch;
use Data::Dumper;

my %disp; # hash of possible functions

my @cmdline_file; # file names on the command file

 # basename -> to full path,
 # list of available symbols, and source schematics
my %sym_avail;
my %src_avail;

 # theese four is sch file -> sumbols and src sch. found there
 # <symbol
my %file_sym;  # $comp{$file}{<symbol>} = count
my %file_src;  # $src{$file}{<subpage>} = count
my %file_pic;  # $src{$file}{picture file} = count. TODO add to dependancies

my %opt;

#############

sub deb($@) {
    my $fmt = shift;

    if ($opt{debug}) {
	printf( STDERR $fmt, @_);
    }
}

sub err($@) {
    my $fmt = shift;
    printf( STDERR $fmt, @_);
}

sub rdep($$);
sub rdep($$) {
    my $file = shift;
    my $dep  = shift;

    my $r;
    $r = $src_avail{$file};

    if (!defined($r)) {
	if ($file =~ m|^\./|) {
	    my $test = $file;
	    $test =~ s|^\./||;
	    $r = $src_avail{$test};
	}
    }
    if (!defined($r)) {
	err("ERR: <$file> not found\n");
	return;
    }

    my @path = @$r;

    if (@path < 1) {
	err("ERR: missing sch-file for <%s>\n", $file);
	return;
    } elsif (@path > 1) {
	err("ERR: mult. sch-files for <$file>:\n");
	for my $f (@path) {
	    err("  $f\n");
	}
    }
    my $path = $path[0];

    #print "\n#############\n";
    #print "rdep $file ", $path, "\n";
    my @sym_arr;
    my @src_arr;

    $r = $file_sym{$file} // $file_sym{$path};
    @sym_arr = sort keys %$r;
    #print "sym: ", join(" ", @sym_arr), "\n";

    $r = $file_src{$file} // $file_src{$path};
    @src_arr = sort keys %$r;
    #print "src: ", join(" ", @src_arr), "\n";

    for my $k (@sym_arr) {
	$$dep{$k}++;
	#print "rdep sym $file $k\n";

    }
    for my $k (@src_arr) {
	if (defined($$dep{$k})) {
	    # already done this one
	    next;
	}
	$$dep{$k}++;
	#print "rdep src $file $k ", $$dep{$k}, "\n";
	rdep($k, $dep);
    }
}

sub depend() {
    my @all;
    my $print_dep = "";

    deb("\n########################################\ndepend:\n\n");
    #my @file = sort keys %file_sym;
    for my $file (@cmdline_file) {
	my $ref = $file_sym{$file};
	#print Dumper($ref);
	my @sym_list;
	for my $k (sort keys %$ref) {
	    my $r = $sym_avail{$k};
	    if (defined($r)) {
		push @sym_list, $$r[0];
		deb("%s:\t%s\n", $k, join(" ", @$r) );
	    } else {
		err("ERR: <%s> not found\n", $k);
	    }
	}
	my $str_symbols = "\n";
	if (@sym_list) {
	    $str_symbols = " \\\n\t  " .join(" \\\n\t  ", @sym_list);
	}

	if ($str_symbols =~ m/(^| |\/)A([34])/) {
	    my $val = $2;
	    my $paper = "iso_A$val";
	    my $ps = $file . "_a$val.ps";
	    $print_dep .= "$ps:\t$file$str_symbols\n";
	    my $pdf = $file . "_a$val.pdf";
	    $print_dep .= "$pdf:\t$file$str_symbols\n";

	    push @all, $ps, $pdf;
	} else {
	    #printf("%s: missing paper frame\n", $file);
	}

	my %net_dep;
	rdep($file, \%net_dep);

	my @all_dep = sort keys %net_dep;
	my @src_arr = grep { m/\.sch$/ } @all_dep;
	my @sym_arr = grep { m/\.sym$/ } @all_dep;

	#print "$file src:\t ", join(" ", @src_arr), "\n";
	#print "$file sym:\t ", join(" ", @sym_arr), "\n";
	if (!$opt{quiet}) {
	    print "$file:\t";
	    for my $k (@src_arr) {
		my $v = $src_avail{$k};
		if ($v) {
		    print " \\\n\t  ", $$v[0];
		}
	    }
	    for my $k (@sym_arr) {
		my $v = $sym_avail{$k};
		if ($v) {
		    print " \\\n\t  ", $$v[0];
		}
	    }
	    print "\n\ttouch \$@\n\n"
	}
    }

    if (!$opt{quiet}) {
	if (@all) {
	    print "printable:\t", join(" ", @all), "\n\n";
	}
	print $print_dep;
    }

}
my $depend_doc = "find and write out (makefile) dependancies";
$disp{depend} = [ \&depend, $depend_doc ];

sub list() {
    my @file = sort keys %file_sym;
    for my $file (@file) {
	print "$file, subsheets:\n";
	for my $src (sort keys %{$file_src{$file}}) {
	    my $path = $src_avail{$src};
	    if (defined($path)) {
		if (!$opt{quiet}) {
		    printf("  %-20s %s\n", "$src:", join(" | ", @$path));
		}
	    } else {
		err("ERR: <%s> not found\n", $src);
	    }
	}

	print "$file, symbols:\n";
	for my $sym (sort keys %{$file_sym{$file}}) {
	    my $path = $sym_avail{$sym};
	    if (defined($path)) {
		if (!$opt{quiet}) {
		    printf("  %-20s %s\n", "$sym:", join(" | ", @$path));
		}
	    } else {
		err("ERR: <%s> not found\n", $sym);
	    }
	}
	print "\n";
    }
}
my $list_doc = "list found symbols and subsheets";
$disp{list} = [ \&list, $list_doc ];

sub get() {
    my @file = sort keys %file_sym;
    for my $file (@file) {
	#print "$file, subsheets:\n";
	for my $src (sort keys %{$file_src{$file}}) {
	    my $path = $src_avail{$src};
	    if (defined($path)) {
		if (! -e $src) {
		    if (!$opt{quiet}) {
			printf("  %-20s %s\n", "$src:", join(" | ", @$path));
		    }
		    print `cp $$path[0] .`;
		}
	    } else {
		err("ERR: <%s> not found\n", $src);
	    }
	}

	#print "$file, symbols:\n";
	for my $sym (sort keys %{$file_sym{$file}}) {
	    my $path = $sym_avail{$sym};
	    if (defined($path)) {
		if (! -e $sym) {
		    if (!$opt{quiet}) {
			printf("  %-20s %s\n", "$sym:", join(" | ", @$path));
		    }
		    print `cp $$path[0] .`;
		}
	    } else {
		err("ERR: <%s> not found\n", $sym);
	    }
	}
	#print "\n";
    }
}
my $get_doc = "copy found symbols and subsheets to current directory";
$disp{get} = [ \&get, $get_doc ];

sub missing() {
    my @file = sort keys %file_sym;
    for my $file (@file) {
	for my $src (sort keys %{$file_src{$file}}) {
	    my $path = $src_avail{$src};
	    if (defined($path)) {
		#printf("%s: %s available\n", $file, $src);
	    } else {
		printf("%s: %s missing\n", $file, $src);
	    }
	}

	for my $sym (sort keys %{$file_sym{$file}}) {
	    my $path = $sym_avail{$sym};
	    if (defined($path)) {
		#printf "%s: %s available\n", $file, $sym;
	    } else {
		printf "%s: %s missing\n", $file, $sym;
	    }
	}
    }
}
my $missing_doc = "list missing symbols and subsheets";
$disp{missing} = [ \&missing, $missing_doc ];

sub paper() {
    my @file = sort keys %file_sym;
    for my $file (@file) {
	my $ref = $file_sym{$file};
	my $str = join(" ", keys %$ref);
	if ($str =~ m/(^| |\/)A([34])/) {
	    my $val = $2;
	    printf( "%s:\tA%d\n", $file, $val);
	} else {
	    printf( "%s:\t--\n", $file);
	}
    }
}
my $paper_doc = "list paper size suggested by frame symbol";
$disp{paper} = [ \&paper, $paper_doc ];

sub misspaper() {
    my @file = sort keys %file_sym;
    for my $file (@file) {
	my $ref = $file_sym{$file};
	my $str = join(" ", keys %$ref);
	if ($str =~ m/(^| |\/)A([34])/) {
	} else {
	    printf("%s: missing paper frame\n", $file);
	}
    }
}
my $misspaper_doc = "notify about missing (known) frame symbols";
$disp{misspaper} = [ \&misspaper, $misspaper_doc ];

sub show_avail() {
    for my $key (sort keys %sym_avail) {
	my @file = @{$sym_avail{$key}};
	print "$key: ", join(" | ", @file), "\n";
    }
    for my $key (sort keys %src_avail) {
	my @file = @{$src_avail{$key}};
	print "$key: ", join(" | ", @file), "\n";
    }
}
my $show_avail_doc = "show found symbols and subsheets";
$disp{show_avail} = [ \&show_avail, $show_avail_doc ];

#############

sub per_file($);
sub per_file($) {
    my $file = shift;
    #print "per file: $file\n";

    if (defined($file_sym{$file}) || defined($file_src{$file})) {
	return;
    }
    $file_sym{$file} = {};
    $file_src{$file} = {};

    my $Tcnt = 0;
    my $Hcnt = 0;
    my $Gcnt = "";

    if (!open(FH, $file)) {
	err("ERR: open error on <file>\n");
	return;
    }

    deb("reading <$file>\n");
    while (<FH>) {
	chomp;

	my @fld = split;

	if ($Tcnt) {
	    $Tcnt--;
	    if (m/^source=(.*)$/) {
		my $src = $1;
		$file_src{$file}{$src}++;
		#print "  src: $src\n";
	    }
	} elsif ($Gcnt) {
	    if ($Gcnt eq "file") {
		$file_pic{$file}{$_}++;
		$Gcnt = "";
	    } else {
		if (m/^\.$/) {
		    $Gcnt = "";
		}
	    }
	} elsif ($Hcnt) {
	    $Hcnt--;
	} elsif (m/^(v|{|})/) {
	} elsif (m/^L/) {
	} elsif (m/^G/) {
	    if ($fld[7]) {
		$Gcnt = "embedded"; # .e. scan till single line with "."
	    } else {
		$Gcnt = "file"; # next line is the filename
	    }
	} elsif (m/^B/) {
	} elsif (m/^V/) {
	} elsif (m/^A/) {
	} elsif (m/^T/) {
	    $Tcnt = $fld[9];
	} elsif (m/^N/) {
	} elsif (m/^U/) {
	} elsif (m/^P/) {
	} elsif (m/^C/) {
	    my $sym = $fld[6];
	    $file_sym{$file}{$sym}++;
	    #print "  sym: $sym\n";
	} elsif (m/^H/) {
	    $Hcnt = $fld[13];
	} elsif (m/^F/) {
	} else {
	    err("ERR: warn fallthrough <%s>\n", $_);
	}
    }
    close(FH);

    #deb("sym: ", join(" ", sort keys %{$file_sym{$file}}), "\n");
    #deb("src: ", join(" ", sort keys %{$file_src{$file}}), "\n");

    for my $src (sort keys %{$file_src{$file}}) {
	if (!defined($file_src{$src})) {
	    if (defined($src_avail{$src})) {
		for my $path (@{$src_avail{$src}}) {
		    per_file($path);
		}
	    }
	}
    }
}

sub Usage($) {
    my $str = shift;

    if ($str) {
	print $str;
	print "\n";
    }
    my $PRG = Opt::prg();

    print
"Usage:
\t$PRG [ gafrc file ] <function> files...
";
    for my $k (sort keys %disp) {
	my $r = $disp{$k};
	my ($func, $doc) = @$r;
	printf "\t%-15s %s\n", "$k:", $doc;
    }
    print "\nThe files.., has to be lepton/geda schematic files\n";

    if ($str) {
	exit 1;
    }
    exit 0;
}

sub main() {
    @ARGV = Opt::opt(\%opt, 0, @ARGV);

    my $function = shift @ARGV;

    if (!defined($function)) {
	Usage("");
    }

    my $ref = $disp{$function};
    if (!defined($ref)) {
	Usage("ERR: Unknown function: <$function>\n");
    }
    my ($func,$doc) = @{$ref};
#    if (@ARGV == 0) {
#	Usage("ERR: Missing schematic files");
#    }

    my ($sym, $src, $sym_avail, $src_avail) = Sch::sch_init(\%opt);
    #my @sym = @$sym;
    #my @src = @$src;
    %sym_avail = %$sym_avail;
    %src_avail = %$src_avail;

    for my $file (@ARGV) {
	if (-f $file) {
	    push @cmdline_file, $file;
	    per_file($file);
	} else {
	    err("ERR: not a file <%s>", $file);
	}
    }

    &{$func}();
}

main();

__END__
