#!/usr/bin/env perl
# 
# Requires perl5
#
# Extract the examples from PETSc, including the description/help
# data and the concepts list, and forms a table
#
# Note that there are multiple Concept lines.  We want to do the following:
# 
# For each file, find the 
# static char help[] = "..."; (C) 
# or 
#   Description: ... \n\n  (Fortran, sometimes)
# line.
# For each concept line, look for
#  Concepts:name1[^name2]*;
# Sort by concept (top level first); organize as tables in the form
#  <h2>name1<h2>
#  <table>
#  <TR><TD><A HREF=filename>name2</A><TD>Description</TR>
#  </table>
# To create this, we do the following:
# First, create a mapping of concepts to filenames.  
# 
# 
# Output filename
# A good default output filename is $concept =~ s/ /_/; with .html added.
#
# A good plan is to create a separate file for each top-level concept;
# the regular help pages can then link to a page giving more detail
# about the examples for each concept

#
# There are command line options for debug, file_by_concept, and add_help
$debug = 0;
#
# I tried table output but decided that menu-based looks better
$table_output = 0;
# Set this to 1 to get separate files
$file_by_concept = 0;
$destdir="concepts/";
# Set to 1 to include help info, 0 to suppress (mostly for debugging)
$add_help = 1;
#
# Set to 1 to skip everything from "command line options" to the end in
# help text
$skip_cmdline = 1;
#
# subst string.  Use this to modify filenames for output in URLs
# Make sure that this is consistent with the destdir argument
$link_pattern  = "/.*/petsc/src";
$link_replacement = "../../../src";

#
$locdir = "";
#
# Initialize hashes
%Concepts = ();
%Help = ();
%Filename = ();

open( LOG, ">logfile.txt" );
#
# Here is the routine that does the actual processing
sub ProcessFile {
    $filename = $_[0];
    print "File $filename\n" if $debug;
    #print "$filename\n";
    #return 0;
    open(INFILE, "<$filename" ) || die "Could not open $filename\n";
    $top_file = "";
    $top_file_end = 0;
    while (<INFILE>) {
	# For Fortran files, save the top comment lines
	if (/\s*!(.*)$/) {
	    if (/\$Id:/) {
		;
	    } 
	    elsif ($top_file_end == 1) {
		;
	    }
	    elsif (/\/\*T/) {
		$top_file_end = 1;
	    }
	    elsif (/Concepts:/) {
		$top_file_end = 1;
	    }
	    elsif (/command line options/) {
		if ($skip_cmdline) {
		    $top_file_end = 1;
		}
	    }
	    else {
		$line = $1;
		$line =~ s/^\s*!//;
		$line =~ s/&/&amp;/g;
		$line =~ s/</\&lt\;/g;
		$line =~ s/>/\&gt\;/g;
		$top_file .= $line . "<BR>\n";
	    }
	}
	if (/Concepts:\s*([^^]*)(.*)\s*\n/) {
	    # We need a case-insensitive version of any name that
	    # we might make a filename of to keep windows happy.
	    $name1 = $1; # ucfirst(lc($1));
	    $name1 =~ s/\s*;$//g;   # Remove any trailing ;
	    $name2 = $2;
	    $name2 =~ s/\s*\^(.*)/$1/;
	    print "File $filename has concept $name1\n";
	    print "concepts $name1 : $name2\n" if $debug;
	    # Add the name as a list item
	    # The following doesn't work because hashes only hold scalars,
	    # not lists.
	    $Concepts{$name1} .= "^". $name2;
	    # We may have many files with the same concept name
	    $Filename{$name1.$name2} .= "^" . $filename;
	    print LOG "$filename:$name1:$name2\n";
	}
	elsif (/Description:/) {
	    # Keep looking until a (nearly) blank line
	}
	elsif (/static\s*char\s*help\[\]\s*=/) {
	    $line = "";
	    if (/static\s*char\s*help\[\]\s*=\s*\"(.*)/) {
		$_ = $1;
	    }
	    else {
		# If the line doesn't have a " yet, get the next line
		$_ = <INFILE>;
		s/^\s*\"//g;
	    }
	    # Eat all lines ending in a \
	    # If $skip_cmdline is 1, stop when 
	    # "command line options" is seen
	    do {{
		if (/command line options/) {
		    if ($skip_cmdline) { 
			$has_next = 0;
			last;	
		    }
		}
		$has_next = 0;
		if (/\\$/) {
		    $has_next = 1;
		}
		s/&/&amp;/g;
		s/</\&lt\;/g;
		s/>/\&gt\;/g;
		s/(\\n)*\\n/<BR>/;
		s/\\$//;
		$line .= $_;
		if ($has_next) {
		    $_ = <INFILE>;
		}
	    }}  while ($has_next) ;
	    $_ = $line;
	    s/(\\n)*\";$//;    
	    print "help line $_\n" if $debug;
	    $Help{$filename} = $_;
	}
    }
    if ($Help{$filename} eq "" && $top_file ne "") {
	$Help{$filename} = $top_file;
    }
    close( INFILE );
}

#
# Look for either
#   A directory, in which case descend into it, or
#   A makefile, in which case find EXAMPLESC, EXAMPLESF, and TUTORIALS,
#   and execute ProcessFile on each named file
sub ProcessDir 
{
    my $filename;
    my $dirname;
    local *DIR;
    $dirname = $_[0];
    opendir DIR,$dirname || die "Can't open directory $dirname\n";
    print "Opening $dirname\n" if $debug;
    while ($filename = readdir(DIR) ) {
	print "dir entry = $filename\n" if $debug;
	if ($filename eq "."  || $filename eq "..") { 
	    # Skip current and previous directory
	    next;
	}
	if ($filename eq "RCS") {
	    # Skip RCS directories
	    next;
	}
	if ($filename eq "contrib") {
	    # Skip the contrib directories
	    next;
	}
	$fullname = $dirname . "/" . $filename;
	print "Checking $fullname\n" if $debug;
	if ( -l $fullname ) {
	    # Ignore links (there are some circular links in Petsc)
	    next;
	}
	if ( -f $fullname ) {
	    if ($filename eq "makefile") {
		# We could put a filter here...
		open (FILELIST,
		      "make DIR=$dirname -f /home/gropp/petsc_work/maint/makefile.ex 2>/dev/null |" );
		while (<FILELIST>) {
		    # The input is a line; we need to break out the
		    # individual names
		    foreach $name (split(/ /,$_) )
		    {
			$fullname = $dirname . "/" . $name;
			if (-f $fullname) {
			    print "Processing $fullname\n" if $debug;
			    &ProcessFile( $fullname );
			}
		    }
		}
		close(FILELIST);
	    }
	}
	elsif ( -d $fullname ) {
	    print "Processing directory $fullname...\n" if $debug;
	    &ProcessDir( $fullname );
	}
    }
    closedir(DIR);
}

#
# The program starts here
while ($ARGV[0] ne "") {
    
    $filename = $ARGV[0];
    shift;
    if ($filename eq "-debug") {
	$debug = 1; 
	next;
    }
    elsif ($filename eq "-byfile") {
	$file_by_concept = 1;
	next;
    }
    elsif ($filename eq "-nohelp") {
	$add_help = 0;
	next;
    }
    elsif ($filename eq "-destdir") {
	$destdir = $ARGV[0];
	shift;
	next;
    }
    elsif ($filename eq "-locdir") {
	$locdir = $ARGV[0];
	shift;
	next;
    }
    elsif ($filename eq "-noskipcmdline") {
	$skip_cmdline = 0 ;
	next;
    }
    elsif ($filename eq "-help" ) {
	print "getexlist [ -debug ] [ -byfile ] [ -nohelp ] [ -destdir dir ]\n";
	print "          [ -noskipcmdline ] path\n";
	exit;
    }
    if (-d $filename) {
	# Instead, process a directory
	&ProcessDir( $filename );
    }
    else {
	&ProcessFile( $filename );
    }
}

if ($table_output) {
    $list_header = "<table>\n";
    $list_tail   = "</table>\n";
    $list_item   = "<TR><TD>";
    $list_help_start = "<TD>";
    $list_help_end   = "</TR>\n";
}
else {			
    $list_header = "<menu>\n";
    $list_tail   = "</menu>\n";
    $list_item   = "<LI>";
    $list_help_start = "<menu>\n";
    $list_help_end = "</menu>\n";
}

%Output = ();
if ($file_by_concept == 0) {
    print "<html>\n<title>$name</title><body bgcolor=\"FFFFFF\">\n";
}
#
# Use a case-insensitive sort
foreach $name (sort {uc($a) cmp uc($b)} keys(%Concepts)) {
    $OUTFILE = "OUTFILE";
    if ($file_by_concept) {
	$concept_file = $name;
	$concept_file =~ s/ /_/g;
	$concept_file .= ".html";
	$concept_file = $destdir . $concept_file;
	$concept_file = lc($concept_file);
	open($OUTFILE, ">$concept_file") || 
	    die "Could not open $concept_file\n";
	print $OUTFILE "<html>\n<title>$name</title><body bgcolor=\"FFFFFF\">\n";
    }
    else {
	$OUTFILE = STDOUT;
    }
    $subheading = $Concepts{$name};
    print $OUTFILE "<h2>$name</h2>\n";
    $printed_header = 0; 
    # PERL requires two braces (!) when you use next within a do ... while.
    do {{
	$subheading =~ /\^([^^]*)(.*)/;
	$curheading = $1;
	$subheading = $2;
	# There may be many files for this list
	if (defined $Output{"$name$curheading"}) {
	    print $OUTFILE "skipping because this has been seen\n" if $debug;
	    next;
	}
	$Output{"$name$curheading"} = 1;
	# Under each topic, we want to list each file only once.
	# We simply sort the files, and skip any file that is the
	# same as the previous file.
	$lastfilename = "zzz";
	foreach $filename (sort split(/\^/, $Filename{"$name$curheading"})) {
	    if ($filename eq "") { next; }
	    if ($filename eq $lastfilename) { next; }
	    $lastfilename = $filename;
	    if ($printed_header == 0) {
		print $OUTFILE $list_header;
		$printed_header = 1;
	    }
	    if ($curheading eq "") {
		# Split out just the root name
		$label = $filename;
		$label =~ s%.*/([^/]*)%$1%g;
	    }
	    else {
		$label = $curheading;
	    }
	    $linkname = $filename;
#	    $linkname =~ s%$link_pattern%$link_replacement%o;
            $linkname = "../../../$locdir$filename.html";
	    print $OUTFILE $list_item . "<A HREF=\"$linkname\"><CONCEPT>$label</CONCEPT></A>\n";
	    if ($add_help == 1 && $Help{$filename} ne "") {
		print $OUTFILE $list_help_start . $Help{$filename} . $list_help_end;
	    }		       
	}
    }} while ($subheading ne "");
    print $OUTFILE "printed header = $printed_header\n" if $debug;
    if ($printed_header == 1) {
	print $OUTFILE $list_tail;
    }
    if ($file_by_concept) {
	print $OUTFILE "</body>\n</html>\n";
	close( $OUTFILE );
    }
}
if ($file_by_concept == 0) {
    print "</body></html>\n";
}

#  foreach $item (keys %Help) {
#      print $item;
#      print "\n";
#      print $Help{$item};

#  }







