#!/usr/bin/perl
#
# Copyright 2004 World Wide Web Consortium,
# (Massachusetts Institute of Technology, ERCIM, 
# Keio University). All Rights Reserved.
# This program is distributed under the W3C's
# Intellectual Property License. This program is
# distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE. See W3C License
# http://www.w3.org/Consortium/Legal/ for more details.
#
##############################################################################
#
# slidemaker tool
# split an all.htm into slides
#
# Stephan Montigaud - stephan@w3.org
# created 970601
# modified by Pierre Fillault
# check the documentation at http://www.w3.org/Talks/YYMMsub/
#
# modified 19990505 Bert Bos: ALT text of prev/next arrows is now
# "prev"/"next" rather than the title of the prev/next slide; looks better
# in lynx.
#
# modified 20011014 Philippe Le Hegaret: improved the link elements for a
# better use fo the mozilla link toolbar (added first, last and top). Fixed
# the style sheet links in all Overview-*.html (only cssUser was taken into
# account).
#
# modified 20020504 Masayasu Ishikawa: added XHTML support.
#
# modified 20040325 Dean Jackson: removed tables so we can use CSS
# for layout, remove all the code for HTML - UTF-8 XHTML strict only here!
# changed default styles (now better CSS - although results are ugly)
#
# Based on Id: w3cburst.pl,v 1.21 2001/10/17 01:15:16 plehegar Exp
# # $Id: sooperslide.pl,v 1.16 2004/05/20 19:27:39 hugo Exp $
#
# NOTE: all the anchors in this tool contain the extension
# indeed this package has to work outside the environment of a web server
# Users need to be able to display their presentation using file:\\
# which requires link to 'real' files

use Getopt::Std;

our($opt_h);
getopts('h');
$htmlsuffix = defined $opt_h ? '.htm' : '.html';

##############################################################################
## default values of variables
##

$doctype = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';

$xmlns = ' xmlns="http://www.w3.org/1999/xhtml" ';

my $metagenerator = '<meta name="generator" content="SooperSlide, http://dev.w3.org/cvsweb/2004/sooperslide/" />';

## table of content built from all.htm - also first page of the presentation
## this is only the basename as we need to generate one toc for each style sheets
## the main toc will not bear any more so the server can understand a request for '/'
## the next ones will bear a number corresponding to the slide index
$overview = 'Overview';

## name of the file containing the parameters of the presentation
$infos = 'infos.txt';

## header of the presentation
$logoAlt = 'W3C';
$logoLink = 'http://www.w3.org/';
$logoFile = '../sooperslide/common/w3c_home.png';

## default accesskeys for navigation icons used in the slides
$prevKey  = 'P';	# accesskey for previous slide
$nextKey  = 'N';	# accesskey for next slide
$tocKey   = 'C';	# accesskey for table of contents
$styleKey = 'S';	# accesskey for changing style sheets

## default author name
$author = 'W3C Staff';

## standard style sheets 
$cssStandardFiles = '../sooperslide/oldskool/stylesheet.css,../sooperslide/corepoorate/corepoorate.css';

# TODO - fix this up
#if (! -d '') {
#	## online location for W3C use
#	$cssStandardFiles = '/Talks/Tools/slide-640.css,/Talks/Tools/slide-800.css,/Talks/Tools/slide-1024.css';
#}

## default charset for use in meta http-equiv or XML declaration
$charset = 'utf-8';

## default language setting is US English 
$baselang = 'en-US';

## end of default values for the presentation
##############################################################################

##############################################################################
## reading user input from $infos
##
@PARAM = @ARGV; # we keep this for backward compatibility with an old version
                # of the slidemaker tool
                #when the parameters were in Makefile or make.bat

# read parameters from infos.txt and put them in @PARAM
if (open(INFOS, $infos)) {
    print STDOUT "--- Reading parameters file $infos ---\n";
    local(@file,$counter);
    $counter = 0;
    while (<INFOS>) {
	push(@file, $_);
    }
    @PARAM = ();
    do {
	if ($file[0] && $file[0] =~ m/^[^#\n\r]/) {
	    $file[0] =~ s/\n//;    # remove UNIX \n 
	    $file[0] =~ s/\r//;    # remove WINDOWS \r    
	    $file[0] =~ s/ *= */=/;
	    $PARAM[$counter++] = $file[0];
	    print "$file[0]\n";
	}
    } while (shift(@file));
}
## @PARAM is now a table with the user preferences for his presentation

## process arguments
## each preset variable is now re-attributed using the user preferences
foreach (@PARAM) {
    @_ = split(/ *= */);
    $cmd="\$$_[0] = \'$_[1]\';";
    if (length $_[1] != 0) { 
	eval($cmd);
    }
}

## save the style sheet file locations into tables 
@cssStandard = split(',',$cssStandardFiles);
$nbCssStandard = $#cssStandard+1;
@cssUser = split(',',$cssUserFiles);
$nbCssUser = $#cssUser +1;

## build an (X)HTML fragment for the author variable
## containing the presentation author name linked to
## a location of his choice
if ($authorUrl) {
    $author = "<a href=\"$authorUrl\">$author</a>";
}

## same string is built if there is a second author for the presentation 
if ($author2 && $author2Url) {
    $author2 = "<a href=\"$author2Url\">$author2</a>";
}

## put both authors together
if ($author2) {
    $author = $author." &amp; ".$author2;
}

## name of raw (X)HTML file containing the slides
$all = "all$htmlsuffix";

## set an XML declaration for XHTML
$xmldecl = "<?xml version=\"1.0\" encoding=\"$charset\"?>\n";

## adjust language information 
$langattr = " xml:lang=\"$baselang\" lang=\"$baselang\"";

# charset
$meta_charset = "<meta http-equiv=\"Content-type\" content=\"text/html; charset=$charset\"/>\n";

##############################################################################
## read the raw (X)HTML presentation
##

## copy file in memory
my $sep = $/;
$/ = undef;
if (!open(ALL, $all)) {
    if ($htmlsuffix eq '.html') {
	my $adderror = "$all nor ";
	$all = 'all.htm';
	if (!open(ALL, $all)) {
	    print "Error: Cannot open file: $adderror$all\n";
	    exit 0;
	} else {
	    print "Warning: $all not found, falling back to all.htm\n";
	}
    } else {
	print "Error: Cannot open file: $all\n";
	exit 0;
    }
}
my $buf = <ALL>;
close(ALL);
$/ = $sep;

## Remove comments from the raw presentation
## they do not need to show up on the slides
$buf =~ s/<!--.*?-->//sgo;

## the slidemaker tool assumes that each slide is self contained between
## 2 sets of h1 elements
## if not it will generate a rather weird output
## split using <h1...> and </h1> as separator (ignores attributes!)
@table = split(/<\/?h1[^>]*>/i, $buf);

# Get script elements in head to put them in each of the slides
my $scripts = '', $s = $table[0];;
for(;;) {
    my $orig = $s;
    $s =~ s|^.*(<script.*?>.*?</script>).*$|$1|si;
    if ($s eq $orig) {
	$s =~ s|^.*(<script.*?/>).*$|$1|si;
	if ($s eq $orig) {
	    $s = '';
	}
    }
    last if ($s eq '');
    $scripts .= "$s\n";
    $orig =~ s|$s||;
    $s = $orig;
}

if (! $talkTitle) {
    $table[0] =~ s|^.*<title.*?>(.*)</title>.*$|$1|si;
    $talkTitle = $table[0];
}

## compute the total number of slides
$total = $#table / 2;
if ($#table % 2 != 0) {
    $total = ($#table +1)/2;
}

##
## raw presentation has been read successfully
##############################################################################

##############################################################################
## processing the slides
 
print STDOUT "\n--- Processing $total slides ---\n"; 

## generate the header table of content of the presentation
## which is also the first page of the talk
&openOverview($overview, 0);

## start the slide count so we can number them
$slideCount = 1;


## @table is the array containing each slide with its title
## for each slide to be generated
## we delete each slide and its title when generated
## so that the current slide and its title are always at $table[0] (for the title)
## and $table[1] (for the slide content)
do {
    
    ## get rid of the first element contained by the raw presentation array
    shift(@table);
    ## then $table[0] is the title of the slide to be generated
    $table[0] =~ s/\n+/ /g;    ## replace return character by a white space 
    $table[0] =~ s/ +/ /g;     ## concatenate several white spaces to only one
    $table[0] =~ s/^ //;       ## remove all the starting white spaces in the title
    $table[0] =~ s/ $//;       ## remove all trailing white spaces in the title
    ## $slideTitle preserves link(s) in the title
    $slideTitle = $table[0];
    ## need to check if the title contains any anchor
    ## if so it needs to be removed
    ## because the title is being used in the table of content to link to the corresponding slide
    $table[0] =~ s/(.*)<a[^>]*>(.*)<\/a>(.*)/$1$2$3/;

    ## grab next slide title $table[2] (if there's a next slide)
    ## to be able to use in the 'next' navigation button
    ## keep in mind that $table[1] contains the slide corresponding to the title $table[0]
    $next_slide_title = $table[2] if $table[2];
    ## remove any anchor from the next slide title
    $next_slide_title =~ s/(.*)<a[^>]*>(.*)<\/a>(.*)/$1$2$3/;

    ## add the title of the current slide to the table of content
    &addTitle("$table[0]",$slideCount);

    ## the current slide content is stored $table[1]
    ## there is an attempt to make sure it's clean (X)HTML
    ## Pierre Fillault's note: use same piece of as used in http://www.w3.org/Web/Tools/CvsCommitScripting
    ## to make use of the validation service
    $slideContent = &clean_html($table[1]) ;

    ## generate the current slide
    ## parameters are:
    ## title of the slide, its content, the slide number, the title of the previous slide and the title of the next slide
    &createSlide("$slideTitle",$slideContent ,$slideCount++,$previous_slide_title,$next_slide_title);

    ## save the title of the previous slide to be displayed in the 'previous' navigation button
    $previous_slide_title="$table[0]";
    shift(@table);
}
## process the next slide 
while ($#table);

## close the table of content
&closeOverview;

## generate more toc with the all the style sheets
## as there's no way of loading a style sheet
## except dynamically, but that would be slow
## and would not work on all platforms (ie would fail on Joe's laptop)
&generateTOC;


print STDOUT "--- Finished ---\n";
exit 0;
##
## end of the slidemaker main program
##############################################################################


##############################################################################
## generate the header of the table of content

sub openOverview 
{
    ## open the file to write to
    open(FOO, ">$_[0]$htmlsuffix");
    
    ## the style sheet used in the table of content is
    $stylelink = "";
    ## here is the standard style sheet
    $stylelink .= "<link href=\"$cssStandard[$_[1]]\" rel=\"stylesheet\" media=\"screen\" type=\"text/css\" title=\"W3C Talk Style\"/>";    
    
    ## we overload with the user css if it exists
    if ($cssUser[$_[1]]) {
	$stylelink .= "\n<link href=\"$cssUser[$_[1]]\" rel=\"stylesheet\" type=\"text/css\" />";
    }

    print FOO <<END;
$xmldecl$doctype
<html$xmlns$langattr>
<head>
$meta_charset<title>$talkTitle - Slide list</title>
$metagenerator
<link rel="next" href="slide1-0$htmlsuffix" title="Next"/>
<link rel="first" href="slide1-0$htmlsuffix" title="First"/>
<link rel="last" href="slide$total-0$htmlsuffix" title="Last"/>
$stylelink
</head>
<body>
<div id="content">
END

print FOO <<END;
<h1 class="slidelist">$talkTitle
by $author</h1>

<h2>Table of contents</h2>

<ul>
END
}
##
## the beginning of the table of content has been generated and saved
##############################################################################

##############################################################################
## generate the footer of the table of content

sub closeOverview
{
	print FOO <<END;
</ul>

</div>
</body>
</html>
END
    close(FOO); 
}
##
## the toc has been completed and saved
##############################################################################

##############################################################################
## add an item in the toc

sub addTitle 
{
    $_[0] =~ s/\r//ig;      # remove the windows CR+LF 
    $_[0] =~ s/<[^>]+>//g;
    if (length $_[0] == 0) {
	return 1;
    }
    # add accesskey for first 9 slides (`1' - `9'), and tabindex for all slides
    if ($_[1] < 10) {
    print FOO <<END;
<li><a accesskey="$_[1]" tabindex="$_[1]" href="slide$_[1]-0$htmlsuffix">$_[0]</a></li>
END
    } else {
    print FOO <<END;
<li><a tabindex="$_[1]" href="slide$_[1]-0$htmlsuffix">$_[0]</a></li>
END
    }
}
##
##############################################################################

##############################################################################
## generate the current slide

sub createSlide 
{

    # parameters are respectively the slide title, its content,
    # its number, the next slide title and the previous slide title
    if (length $_[0] == 0) {
	return 1;
    }

    # work the slide title, the previous and next titles
    $_[0] =~ s/\r//ig;      # remove the windows CR+LF 
    $_[3] =~ s/\r//ig if ($_[3]); 
    $_[4] =~ s/\r//ig if ($_[4]);
    $title = $_[0];

    # Remove any tags from the prev & next titles
    $_[3] =~ s/<[^>]+>//g if ($_[3]);
    $_[4] =~ s/<[^>]+>//g if ($_[4]);
    $title =~ s/<[^>]+>//g;

    # Replace double quotes
    $_[3] =~ s/"/&#34;/g if ($_[3]);
    $_[4] =~ s/"/&#34;/g if ($_[4]);

    # work the slide content
    $_[1] =~ s/<\/body>//i; # remove if any
    $_[1] =~ s/<\/html>//i; # remove if any

    $status = sprintf "Slide %2d: %s\n", $_[2], $_[0];
    $status =~ s#<[^>]+>##g;
    print STDOUT $status;

    &verify_html($_[1]);    # check the (X)HTML

    ## we create as many slides as there are css files
    ## Pierre note: it'd be much nicer to have only one slide
    ## which could dynamically load the css file, but ...
    my $cNumber = 0;
    for ($i=0;$i<$nbCssStandard;$i++) {
    $cNumber = $i+1;
    $cNumber = 0  if ($i == $nbCssStandard-1);

    ## write to the slide
    open(SLIDE, ">slide$_[2]-$i$htmlsuffix");

    local($navBar);
    local($miniNavBar);
    local($toclink);
    local($firstlink);
    local($lastlink);
    local($prevlink);
    local($nextlink);

    ## navigation to previous slide, toc and next slide
    $navBar = "";
    $miniNavBar = "<address id=\"author\">$author</address>\n<span id='position'><span id='slide-number-intro'>Slide </span>$_[2] of $total</span>";
    
    ## the toc link needs to match the slide index
    ## so that the style sheets match between the slides and the toc
    $toclink = "<link rel=\"contents\" href=\"$overview$htmlsuffix\" title=\"Contents\"/>\n".
	"<link rel=\"top\" href=\"$overview$htmlsuffix\" title=\"Top\"/>";
    
    $firstlink = "<link rel=\"first\" href=\"slide1-$i$htmlsuffix\" title=\"First\"/>";
    $lastlink = "<link rel=\"last\" href=\"slide$total-$i$htmlsuffix\" title=\"Last\"/>";
    
    ## initialization of the navigation links
    $nextlink = "";
    $prevlink = "";

    if ($_[2]>1) {
	$prevlink = "<link rel=\"prev\" href=\"slide".eval($_[2]-1)."-$i$htmlsuffix\" title=\"Previous\"/>";
	$navBar .= "<a id=\"navigation-previous\" rel=\"prev\" href=\"slide".eval($_[2]-1)."-$i$htmlsuffix\" accesskey=\"$prevKey\"><span>Previous</span></a>\n";
    } else {
	## add a link back to the toc for the first slide --CMN 19991102
	if ($i == 0) {
	    $prevlink = "<link rel=\"prev\" href=\"$overview$htmlsuffix\" title=\"Previous\"/>";
	    $navBar .= "<a id=\"navigation-previous\" rel=\"prev\" href=\"$overview$htmlsuffix\" accesskey=\"$prevKey\"><span>Previous</span></a>\n";
	} else {
	    $prevlink = "<link rel=\"prev\" href=\"$overview-$i$htmlsuffix\" title=\"Previous\"/>";
	    $navBar .= "<a id=\"navigation-previous\" rel=\"prev\" href=\"$overview-$i$htmlsuffix\" accesskey=\"$prevKey\"><span>Previous</span></a>\n";
	}
    }
    
    
    if ($i == 0) {
   	## we're using the first css file, so no need to number the toc
	# @@ huh?
	$navBar .= "<a id=\"navigation-toc\" rel=\"contents\" href=\"$overview$htmlsuffix\" accesskey=\"$tocKey\"><span>Table of Contents</span></a>\n";
        #$navBar = $navBar."<a rel=\"contents\" href=\"$overview$htmlsuffix\" accesskey=\"$tocKey\"><img src=\"$toc\" width=\"32\" height=\"32\" alt=\" contents\" title=\"Table of Contents\"$border/></a>";
    } else {
        ## change $toclink
        $toclink = "<link rel=\"contents\" href=\"$overview-$i$htmlsuffix\" title=\"Contents\"/>\n".
	    "<link rel=\"top\" href=\"$overview-$i$htmlsuffix\" title=\"Top\"/>";
        ## we're using another css, the toc needs to match
	# @@ huh?
	$navBar .= "<a id=\"navigation-toc\" rel=\"contents\" href=\"$overview-$i$htmlsuffix\" accesskey=\"$tocKey\"><span>Table of Contents</span></a>\n";
	#$navBar = $navBar."<a rel=\"contents\" href=\"$overview-$i$htmlsuffix\" accesskey=\"$tocKey\"><img src=\"$toc\" width=\"32\" height=\"32\" alt=\" contents\" title=\"Table of Contents\"$border/></a>";
    }
    ## add style change before the "next" button --CMN 19991102
    # @@ todo - style change
    if ($cNumber != $i) {
	$navBar .= "<a id=\"navigation-switch\" href=\"slide".eval($_[2])."-$cNumber$htmlsuffix\" accesskey=\"$styleKey\"><span>Change Style</span></a>\n";
    }

    if ($_[2] != $total) {
	$nextlink = "<link rel=\"next\" href=\"slide".eval($_[2]+1)."-$i$htmlsuffix\" title=\"Next\"/>";
	$navBar .= "<a id=\"navigation-next\" rel=\"next\" href=\"slide".eval($_[2]+1)."-$i$htmlsuffix\" accesskey=\"$nextKey\"><span>Next</span></a>\n";
    } 

    $stylelink = "";
    # here is the standard style sheet
    $stylelink .= "<link href=\"$cssStandard[$i]\" rel=\"stylesheet\" media=\"screen\" type=\"text/css\" title=\"W3C Talk Style\"/>";

    # we overload with the user css if it exists
    if ($cssUser[$i]) {
	$stylelink .= "\n<link href=\"$cssUser[$i]\" rel=\"stylesheet\" type=\"text/css\" />";
    }

    if ($logoLink2 && $logoAlt2 && $logoFile2) {
	$header2="<a id='other-header' href='$logoLink2'><img alt='$logoAlt2' src='$logoFile2' /></a>";
    }

    print SLIDE <<END;
$xmldecl$doctype
<html$xmlns$langattr>
<head>
$meta_charset<title>$talkTitle - slide "$title"</title>
$metagenerator
$firstlink
$lastlink
$nextlink
$prevlink
$toclink
$stylelink
$scripts</head>
<body>

<div id="navigation">
$navBar
</div>

<div id="header">
  <a id='main-header' href='$logoLink'><img src='$logoFile' alt='$logoAlt' /></a>
  $header2
</div>


<div id="content">
<h1>$_[0]</h1>
<hr id='top-separator' />
$_[1]
</div>

<div id="footer">
<hr id='bottom-separator' />
$miniNavBar
</div>

</body>
</html>
END

     close(SLIDE);
  }
  return 0;
}

##############################################################################
## generate all the toc of contents needed for each css choosen by the user
## the default toc is not numbered so it can be served by a request to '/'
## (ie it remains Overview$htmlsuffix whereas the other toc are called Overview_#$htmlsuffix)

sub generateTOC {

    ## read the general toc
    open(FOO, "<$overview$htmlsuffix"); 
    @TOC = <FOO>;
    close(FOO);
    $toc = "@TOC";
    
    ## for each user CSS file
    ## starting after the default css
    for ($css=1;$css<$nbCssStandard;$css++) {
	
	## create new TOC
	$newTOC = $toc;
	## replace the navigation link elements
	$newTOC =~ s#<link rel=\"next\" href=\"[^\"]*\" title=\"Next\"/>#<link rel=\"next\" href=\"slide1-$css.html\" title=\"Next\"/>#ig;
	$newTOC =~ s#<link rel=\"first\" href=\"[^\"]*\" title=\"First\"/>#<link rel=\"first\" href=\"slide1-$css.html\" title=\"First\"/>#ig;
	$newTOC =~ s#<link rel=\"last\" href=\"[^\"]*\" title=\"Last\"/>#<link rel=\"last\" href=\"slide$total-$css.html\" title=\"Last\"/>#ig;
	
	## replace the style link with a new one	
	## <link href="/Talks/Tools/w3ctalk-640.css" rel="stylesheet" type="text/css" title="W3C Talk">
	## we eventually choose the user css file if any
	$newTOC =~ s#<link href=\"[^\"]*\" rel=\"stylesheet\" media="screen" type=\"text\/css\" title=\"W3C Talk Style\"/>#<link href=\"$cssStandard[$css]\" rel=\"stylesheet\" type=\"text\/css\" title=\"W3C Talk\"/>#ig;
	if ($cssUser[$css]) {
	    $newTOC =~ s#<link href=\"[^\"]*\" rel=\"stylesheet\" type=\"text\/css\" title=\"User Talk\"/>#<link href=\"$cssUser[$css]\" rel=\"stylesheet\" type=\"text\/css\" title=\"User Talk\"/>#ig;
	}
    
	## the links on the toc need also to be modified
	## to link to the correct slides
	$newTOC =~ s/<a accesskey=\"(\d)\" tabindex=\"(\d+)\" href=\"slide(\d+)-\d+$htmlsuffix\">/<a accesskey=\"$1\" tabindex=\"$2\" href=\"slide$3-$css$htmlsuffix">/ig;
	$newTOC =~ s/<a tabindex=\"(\d+)\" href=\"slide(\d+)-\d+$htmlsuffix\">/<a tabindex=\"$1\" href=\"slide$2-$css$htmlsuffix">/ig;
	
	## write to new TOC
	$outfile = $overview."-".$css."$htmlsuffix";
	open(OUT, ">$outfile");
	print OUT $newTOC;
	close(OUT)
	}
}

##############################################################################
# check that the (X)HTML of the slide 
# is correct (alt attributes, ...)
# This procedure produces only warning
sub verify_html {

    if ($_[0] =~ /<img([^>]*)>/im) {
	if (!($1 =~ /alt=/im)) {
	    print STDOUT "WARNING: <img/> without alt\n";
	    print STDOUT "         <img$1/>\n" ;
	}
    }
}

##############################################################################
# clean the html of the slide
# remove all <div class="comment">blabla</div>
sub clean_html {
    $_[0] =~ s/<div\s+class\s*=\s*(?:comment[\s>]|\"comment\").*?<\/div>//igs;
    return $_[0];
}
