#!/usr/bin/perl
#=======================================================================
# Copyright (c) 2000-2001 Daniele Giacomini daniele@swlibero.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 of the License, 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.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#=======================================================================
# alml-pageref ROOT_FILE_NAME STAGE VERBOSE
#
# Replace page reference inside a TeX file genereated from Alml.
#=======================================================================

use POSIX;
use Locale::gettext;
setlocale (LC_MESSAGES, "");
textdomain ("alml");

#sub gettext
#{
#    return $_[0];
#}

# Program executable without path.
$program_executable = $0;
$program_executable =~ m{([^/]*)$};
$program_executable = $1;

# Page references taken from the .pageref file
# $tex_page_ref_list[x][0]        label
# $tex_page_ref_list[x][1]        page
#
@tex_page_ref_list = ();

#-----------------------------------------------------------------------
# Diagnostic output; it depends on the following global variables:
#   $verbose
#   $root_file_name
#
sub diag_output
{
    local ($string)    = $_[0];

    # Append to the diagnostic file.
    open (DIAG, ">> $root_file_name.diag");
    
    if ($verbose)
      {
        print STDOUT ($string);
      }
    # In any case, print it on the DIAG file
    print DIAG ($string);

    # Close the file.
    close (DIAG);

}

#-----------------------------------------------------------------------
# Scan an .pageref file and fill the tex page reference list.
#
# &tex_page_ref_list_fill (<file>)
#
sub tex_page_ref_list_fill
{
    local ($file_name) = $_[0];
    local ($label) = "";
    local ($page) = "";

    # Reset the array.
    @tex_page_ref_list = ();

    open (PAGEREF, "< $file_name");

    while ($line = <PAGEREF>)
      {
	if ($line =~ m/^\\AlmlNewLabel\{([^{}]+)\}\{([^{}]+)\}/)
	  {
	    $label = $1;
	    $page = $2;

	    # Page references taken from the .pageref file
	    # $tex_page_ref_list[x][0]        label
	    # $tex_page_ref_list[x][1]        page
	    #
	    $#tex_page_ref_list++;
	    $tex_page_ref_list[$#tex_page_ref_list] = ();
	    $tex_page_ref_list[$#tex_page_ref_list][0] = $label;
	    $tex_page_ref_list[$#tex_page_ref_list][1] = $page;

	    #print STDOUT $tex_page_ref_list[$#tex_page_ref_list][0];
	    #print STDOUT " ";
	    #print STDOUT $tex_page_ref_list[$#tex_page_ref_list][1];
	    #print STDOUT "\n";
	  }
      }

    close (PAGEREF);
}

#-----------------------------------------------------------------------
# Scan a .tex file and replace a dummy \pageref command.
#
# &tex_page_ref_list_replace (<file_in>, <file_out>, <n_scan>)
#
sub tex_page_ref_list_replace
{
    local ($file_in) = $_[0];
    local ($file_out) = $_[1];
    local ($scan_order) = $_[2];
    local ($next_scan_order) = $scan_order + 1;
    local ($line) = "";
    local ($n) = "";
    local ($pre) = "";
    local ($page) = "";
    local ($label) = "";
    local ($post) = "";

    open (FILE_IN, "< $file_in");
    open (FILE_OUT, "> $file_out");

    while ($line = <FILE_IN>)
      {
	while ($line =~ m/^(.*)\\AlmlPageRef\{$scan_order\}\{([^{}]*)\}\{([^{}]+)\}(.*)$/)
	  {
	    # \AlmlPageRef{0}{000}{pippo}
	    $pre = $1;		
	    $page = $2;		
	    $label = $3;		
	    $post = $4;		

	    #print STDOUT ("$label\n");

	    # Page references taken from the .pageref file
    	    # $tex_page_ref_list[x][0]        label
	    # $tex_page_ref_list[x][1]        page

	    #print STDOUT ($#tex_page_ref_list . "\n");

    	    for ($n = 0;
                 $n <= $#tex_page_ref_list;
                 $n++)
	      {
	        if ($tex_page_ref_list[$n][0] eq $label)
	          {
	            # Label found.
		    if ($verbose)
		      {
	    		# Show that the program is working.
			&diag_output (sprintf (gettext ("%s:%s: page label found: %s\n"),
                                               $program_executable,
		                               "$root_file_name.tex",
		                               $label));
		      }
		    last;
		  }
	      }
	    if ($tex_page_ref_list[$n][0] eq $label)
	      {
		 $line = $pre
	                . "\\AlmlPageRef\{"
		        . "$next_scan_order"
			. "\}\{"
			. $tex_page_ref_list[$n][1]
			. "\}\{"
			. "$label"
			. "\}"
		        . "$post\n";
	      }
	    else
	      {
		&diag_output (sprintf (gettext ("%s:%s: label \"%s\" not found !!!!\n"),
                                       $program_executable, "$root_file_name.tex", "$label"));
	      
		#-------------------------------------------------------
	        # Cannot keep the same wrong string, otherwise,
		# at the next loop, it will be found again!
		# So, the scan order is incremented anyway. Sorry.
		#-------------------------------------------------------
        	$line = $pre
	                . "\\AlmlPageRef\{"
		        . "$next_scan_order"
			. "\}\{"
			. "$page"
			. "\}\{"
			. "$label"
			. "\}"
		        . "$post\n";
	      }
	  }
	print FILE_OUT ($line);
      }

    if ($verbose)
      {
        # Close with a new line on the screen.
        print STDOUT ("\n");
      }

    close (FILE_IN);
    close (FILE_OUT);
}

#---------------------------------------------------------------
# Sort tex_page_ref_list.
#
# &sort_tex_page_ref_list (LOW_ELEMENT, UP_ELEMENT)
#
sub sort_tex_page_ref_list
{
    local ($a) = $_[0];        # lower index
    local ($z) = $_[1];        # upper index 

    local ($k) = 0;
    local ($exchange) = "";

    # Page references taken from the *.pageref file
    # $tex_page_ref_list[x][0]        label
    # $tex_page_ref_list[x][1]        page

    if ($a < $z)
      {
        # Scan the array to place the right element inside $a
        # index.
        for ($k = $a+1; $k <= $z; $k++)
          {
            if (uc ($tex_page_ref_list[$k][0]) lt uc ($tex_page_ref_list[$a][0]))
              {
                # Exchange sub-arrays.
                $exchange          = $tex_page_ref_list[$k];
                $tex_page_ref_list[$k] = $tex_page_ref_list[$a];
                $tex_page_ref_list[$a] = $exchange;
              }
          }
	
	# Show something.
	&diag_output (sprintf (gettext ("%s:%s:%s percent sorted (now at %s)\n"),
        	    	           $program_executable,
		                   "$root_file_name.tex",
		                   (int (($a/$z)*100)),
			           $tex_page_ref_list[$a][0]));
	
        &sort_tex_page_ref_list ($a+1, $z);
      }
}

#---------------------------------------------------------------
# Find an element inside tex_page_ref_list.
#
# &find_tex_page_ref_list (LABEL) --> array pointer
#
sub find_tex_page_ref_list
{
    local ($label) = $_[0];    # label to search
    local ($a) = $_[1];
    local ($z) = $_[2];
    local ($m);

    # Page references taken from the *.pageref file
    # $tex_page_ref_list[x][0]        label
    # $tex_page_ref_list[x][1]        page

    # Determina l'elemento centrale.
    $m = int (($a + $z) / 2);

    if ($m < $a)
      {
        # Non restano elementi da controllare: l'elemento cercato non c'.
        return -1;
      }
    elsif ($label lt $tex_page_ref_list[$m][0])
      {
        # Si ripete la ricerca nella parte inferiore.
        return &find_tex_page_ref_list ($label, $a, $m-1);
      }
    elsif ($label gt $tex_page_ref_list[$m][0])
      {
        # Si ripete la ricerca nella parte superiore.
        return &find_tex_page_ref_list ($label, $m+1, $z);
      }
    else
      {
        # $m rappresenta l'indice dell'elemento cercato.
        return $m;
      }
}


#======================================================================
# Start of program.
#----------------------------------------------------------------------

local ($root_file_name) = $ARGV[0];
local ($stage)          = $ARGV[1];
local ($verbose)        = $ARGV[2];

&diag_output (sprintf (gettext ("%s: reading %s\n"),
                       $program_executable, "$root_file_name.pageref"));
&tex_page_ref_list_fill ("$root_file_name.pageref");
system ("mv -f $root_file_name.tex $root_file_name.tex~");
&diag_output (sprintf (gettext ("%s: replacing %s with new page references\n"),
                       $program_executable, "$root_file_name.tex"));
&tex_page_ref_list_replace ("$root_file_name.tex~", "$root_file_name.tex", $stage);
system ("mv -f $root_file_name.pageref $root_file_name.pageref~");
system ("mv -f $root_file_name.log $root_file_name.log~");

#======================================================================

