#! /usr/local/bin/perl

#@(#) OA98 <Olivier.Aubert@enst-bretagne.fr>
#@(#) transp.pl Generation of transparencies based on a template

# This script is distributed under the GNU General Public License
# version 2.1 or later. See http://www.fsf.org/

# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2.1, or (at your option)
# any later version.

# 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 the
# GNU General Public License for more details.

# A copy of the GNU General Public License can be obtained from this
# program's author (send electronic mail to the above address) or from
# Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
# or from the Free Software Foundation website: http://www.fsf.org/

use HTML::Entities;
use strict;
use vars qw($template $toc $dir $version);

($version) = (q$Revision: 1.2 $ =~ /Revision:\s+([\d]+\.[\d]+)/);

# On va stocker tout le fichier original dans une structure: liste de hash-tables
# @data
# Les hash-tables auront comme cles:
#   title     [titre au format HTML]
#   content   [une reference sur une liste contenant les donnees]
#   filename  [genere a partir du titre]
#   current   [synonyme de filename]
#   previous  [le nom du fichier precedent]
#   next      [le nom du fichier suivant]
#   index     [le numero du transparent]
#   total     [le nombre total de transparents]
#   toc       [le nom du fichier de table des matieres]
# Dans le fichier template, les elements du type _cle_ seront remplaces par
# les valeurs calculees: _index_/_total_ => 2/10

$template = "source/template.html";
$toc = "index.html";
$dir = "";

# Parse le fichier de donnees (chaque transparent est commence par un titre,
# entre <h1>...</h1>). Il *doit* se terminer par un </body>.
sub parse_file
{
  my $file = shift;
  my $title = "";
  my @data;
  
  open (F, $file) or die "Cannot read $file: $!";
  # On cherche le premier transparent
  while (<F>)
  {
    if (m!^<h1>(.+?)</h1>!i)
    {
      $title = $1;
      last;
    }
  }
  
  if ($title eq "")
  {
    die "Unable to find a valid <h1> section.";
  }

  while ($title ne "")
  {
    my $filename;
    my %struct;
    my @content;

    # On applique un certain nombre de transformations a $title pour aboutir
    # au nom de fichier
    $filename = $title;
    $filename =~ s/\&(\w)\w+?;/$1/g;    
    decode_entities ($filename);
    $filename = lc ($filename);
    $filename =~ s/\s+/_/g;
    $filename =~ s/[^a-zA-Z0-9_-]/./g;
    $filename .= ".html";
    
    undef %struct;
    $struct{title} = $title;
    $struct{filename} = $filename;
    $struct{current} = $filename;

    @content = ();
    while (<F>)
    {
      if (m!^\<h1\>(.+?)\</h1>!i)
      {
        $title = $1;
        last;
      }
      if (m!^\</body\>!i)
      {
        $title = "";
        last;
      }
      # On pourrait ici extraire d'autres donnees du fichier que l'on
      # est en train de lire.
      push (@content, $_);
    }

    $struct{'content'} = [ @content ];

    push(@data, { %struct });
  }
  close (F);
  
  return \@data;
}

# Genere un fichier de donnees. On passe la structure contenant les donnees
# en parametre.
sub generate_file
{
  my $struct = shift;
  my %struct = %$struct;
  my $file = $struct{filename};

  # Note: on pourrait remplacer ca par un dup2 (DATA, T); qui irait lire
  # le template a la fin de ce script (apres le __DATA__)
  open (T, $template) or die "Cannot read $template: $!";
  open (F, ">$dir$file") or die "Cannot write $dir$file: $!";
  while (<T>)
  {
    my $i;

    # Inefficace, mais lisible et rapide a ecrire. Pourrait etre optimise
    # (en generant le code par exemple), mais ce n'est pas critique.
    # C'est laisse en exercice a l'hypothetique lecteur de commentaire.
    for $i (keys %struct)
    {
      if (ref($struct{$i}) eq "ARRAY")
      {
        s/_${i}_/@{$struct{$i}}/gi;
      }
      else
      {
        s/_${i}_/$struct{$i}/gi;
      }
    }
    print F;
  }
  close (F);
  close (T);
}

# Retraite la liste en generant les donnees supplementaires (en particulier
# les references entre transparents)
sub postprocess_data
{
  my $data = shift;
  my @data = @$data;
  my $total = scalar(@data);
  my $previous = $toc;
  my $i;

  # Considerations philosophiques: on est en presence d'elements d'une liste
  # dont on veut tirer des relations entre precedent, courant et suivant.
  # Le cas general se trouve au milieu, les cas particuliers sont le premier
  # et le dernier element.
  # Il faut egalement reflechir a ce qui se passe pour les cas tres
  # particuliers (liste a 0, 1 ou 2 elements).
  my $cur = $data[0];
  
  $cur->{'index'} = 1;
  $cur->{'total'} = $total;
  $cur->{'previous'} = $toc;
  $cur->{'next'} = $data[1]->{filename};
  $cur->{toc} = $toc;
  
  for ($i = 1; $i < $total - 1; $i++)
  {
    $cur = $data[$i];
    $cur->{'index'} = $i + 1;
    $cur->{'total'} = $total;
    $cur->{'previous'} = $data[$i - 1]->{filename};
    $cur->{'next'} = $data[$i + 1]->{filename};
    $cur->{toc} = $toc;
  }

  $cur = $data[$total - 1];
  $cur->{'index'} = $total;
  $cur->{'total'} = $total;
  $cur->{previous} = ${data[$total - 1]}->{filename};
  $cur->{'next'} = $toc;
  $cur->{toc} = $toc;

  #  Pas de valeur de retour: on manipule directement les references sur
  # les donnees stockees dans @data.
}

# Genere l'ensemble des fichiers resultats.
sub generate_data
{
  my $data = shift;
  my @data = @$data;
  my $d;
  
  print "Generating files...";
  for $d (@data)
  {
    print $d->{'index'}, "..."; 
    generate_file ($d);
  }
  print "ok.\n";
}

# Genere la table des matieres (sous forme d'une structure qui sera ajoutee
# egalement a la liste @data)
sub generate_toc
{
  my $data = shift;
  my @data = @$data;
  my $d;
  my(@content) = ();
  my(%struct) = ();
  
  push (@content, "<ul>\n");
  for $d (@data)
  {
    push (@content,
          '<li><a href="',
          $d->{filename},
          '">',
          $d->{title},
          "</a>\n");
  }
  push (@content, "</ul>");

  $struct{'index'} = 0;
  $struct{'total'} = scalar(@data);
  $struct{current} = $toc;
  $struct{previous} = $toc;
  $struct{'next'} = $data[0]->{filename};
  $struct{title} = "Liste des transparents";
  $struct{filename} = $toc;
  $struct{content} = [ @content ];
  $struct{toc} = $toc;

  # On met la liste en tete des transparents
  unshift (@$data, { %struct });
}

sub usage
{
  print <<"EOF";
Syntaxe: $0 fichier.html [repertoire]

Convertit fichier.html en un ensemble de transparents, base sur un template.
EOF
 exit (0);
}

# Routine principale. 
sub main
{
  my $orig = $ARGV[0] or usage();
  my $dest;

  # Tentative pour determiner automatiquement le nom du repertoire destination
  # Peut-etre devrait-on prendre plutot le <title>... du document original
  ($dest) = ($ARGV[1] || ($orig =~ /([^\/]+?)\.html/));

  # Pour les besoins de generate_file, on veut avoir une variable contenant le
  # nom du repertoire suivi de /
  $dir = "$dest/";

  if (! -d $dest)
  {
    mkdir ($dest, 0755) or die "Cannot mkdir $dest: $!";
  }

  $| = 1;
  print "Source file: $orig\nDestination directory: $dest\n";

  my $data;
  
  $data = parse_file ($orig);
  postprocess_data ($data);
  generate_toc ($data);
  generate_data ($data);

  exit(0);
}

main ();

__DATA__

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>(_index_/_total_) _title_</title>
<link rel="contents" href="_current_">
<link rel="STYLESHEET" href="../styles/default.css" type="text/css">

</head>
<body background="../images/recbg.jpg">
<!-- <center> -->

<!-- Entete de la page -->
<table border=0 width="100%"> 
  <tr>
    
    <td width=60 background="../images/recbg.jpg">
    <a href="_previous_">
    <img src="../icons/left.gif" align="left" border="0" ALT="<<<<<"></a>
    </td>
    
    <td bgcolor="#0000FF">
    <div class="intitule" align="center">
    _title_
    </div>
    </td>
    
    <td width=60 background="../images/recbg.jpg">
    <a href="_next_">
    <img width=50 height=40 src="../icons/right.gif" align="right"
    border="0" alt=">>>>>" > </a>
    
    </td>
  </tr>
</table>

<!-- Contenu du transparent -->
<table bgcolor="white"  border="1" width="100%" height="85%"
  cellspacing="10">
  
  <tr>
    <td>

        <div class="contenu">
_content_
        </div>
        
    </td>
  </tr>
</table>

<!-- Pied de page -->
<table bgcolor="#0000FF" border="0" width="100%">
  <tr>
    <td>
        <div class="author"><a href="mailto:Olivier.Aubert@enst-bretagne.fr">Olivier Aubert</a></div>
    </td>
        
        <th width="5"><a href="_previous_"><div
        class="navsign">&lt;&lt;</div></a></th>
        
        <th width="10"><a href="_current_"><div
        class="navtext">_index_/_total_</div></a></th>
        
        <th width="5"><a href="_next_"><div
        class="navsign">&gt;&gt;</div></a></th>
        
    <th><a href="_toc_"><div class="navtext">PLAN</div></a></th>
        
  </tr>
</table>

</body>
</html>
